├── examples ├── tests ├── isInViewport.js ├── isInViewport.js.map ├── common.css ├── es6-example │ ├── common.css │ ├── rollup.config.js │ ├── main.js │ ├── readme.md │ ├── package.json │ └── index.html ├── advanced.js ├── basic.js ├── advanced-viewport.js ├── index.html ├── advanced.html ├── basic.html └── advanced-viewport.html ├── tests ├── lib │ ├── mocha.css │ ├── mocha.js │ ├── isInViewport.min.js │ ├── should.js │ ├── isInViewport.min.js.map │ ├── grunt-reporter.js │ └── jquery.min.js ├── horizontallyScrollingViewportTests.js ├── tests.html ├── customViewportTests.js └── defaultViewportTests.js ├── src ├── .eslintrc └── index.js ├── .eslintrc ├── .travis.yml ├── .gitignore ├── bower.json ├── isInViewport.jquery.json ├── now.json ├── license.md ├── package.json ├── lib ├── isInViewport.min.js ├── isInViewport.es6.js ├── isInViewport.min.js.map ├── isInViewport.js ├── isInViewport.js.map └── isInViewport.es6.js.map ├── gulpfile.js └── readme.md /examples/tests: -------------------------------------------------------------------------------- 1 | ../tests -------------------------------------------------------------------------------- /examples/isInViewport.js: -------------------------------------------------------------------------------- 1 | ../lib/isInViewport.js -------------------------------------------------------------------------------- /tests/lib/mocha.css: -------------------------------------------------------------------------------- 1 | ../../node_modules/mocha/mocha.css -------------------------------------------------------------------------------- /tests/lib/mocha.js: -------------------------------------------------------------------------------- 1 | ../../node_modules/mocha/mocha.js -------------------------------------------------------------------------------- /examples/isInViewport.js.map: -------------------------------------------------------------------------------- 1 | ../lib/isInViewport.js.map -------------------------------------------------------------------------------- /tests/lib/isInViewport.min.js: -------------------------------------------------------------------------------- 1 | ../../lib/isInViewport.min.js -------------------------------------------------------------------------------- /tests/lib/should.js: -------------------------------------------------------------------------------- 1 | ../../node_modules/should/should.js -------------------------------------------------------------------------------- /tests/lib/isInViewport.min.js.map: -------------------------------------------------------------------------------- 1 | ../../lib/isInViewport.min.js.map -------------------------------------------------------------------------------- /tests/lib/grunt-reporter.js: -------------------------------------------------------------------------------- 1 | ../../node_modules/grunt-blanket-mocha/support/grunt-reporter.js -------------------------------------------------------------------------------- /src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 6, 4 | "sourceType": "module" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": "standard", 4 | "env": { 5 | "jquery": true, 6 | "mocha": true 7 | }, 8 | "rules": { 9 | "space-before-function-paren": 0, 10 | "no-multiple-empty-lines": [2, {"max": 2}] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "lts/*" 4 | script: 5 | npm run build 6 | before_deploy: 7 | - npm install --no-save now 8 | deploy: 9 | provider: script 10 | script: npm run deploy 11 | skip_cleanup: true 12 | on: 13 | branch: master 14 | -------------------------------------------------------------------------------- /examples/common.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | background-color: #FBFBFB; 5 | color: #151612; 6 | font-family:"Century Gothic", CenturyGothic, AppleGothic, sans-serif; 7 | } 8 | h1 { 9 | font-size: 3em; 10 | } 11 | a, a:visited, a:active, a:hover { 12 | text-decoration: none; 13 | } 14 | .left { 15 | float: left; 16 | } 17 | .right { 18 | float: right; 19 | } -------------------------------------------------------------------------------- /examples/es6-example/common.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | background-color: #FBFBFB; 5 | color: #151612; 6 | font-family:"Century Gothic", CenturyGothic, AppleGothic, sans-serif; 7 | } 8 | h1 { 9 | font-size: 3em; 10 | } 11 | a, a:visited, a:active, a:hover { 12 | text-decoration: none; 13 | } 14 | .left { 15 | float: left; 16 | } 17 | .right { 18 | float: right; 19 | } -------------------------------------------------------------------------------- /examples/es6-example/rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonjs from 'rollup-plugin-commonjs' 2 | import nodeResolve from 'rollup-plugin-node-resolve' 3 | 4 | export default { 5 | entry: './main.js', 6 | dest: './main.compiled.js', 7 | format: 'iife', 8 | globals: { 9 | window: 'window' 10 | }, 11 | sourceMap: true, 12 | external: ['window'], 13 | plugins: [nodeResolve({ skip: ['window'] }), commonjs({ exclude: ['window'] })] 14 | } 15 | -------------------------------------------------------------------------------- /examples/advanced.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $(document).ready(function() { 3 | $('#container > div.box').css('background-color', '#21221E'); 4 | $('#container > div.box:in-viewport(100)').css('background-color', '#C5C7BC'); 5 | 6 | $(window).scroll(function() { 7 | $('#container > div.box').css('background-color', '#21221E'); 8 | $('#container > div.box:in-viewport(100)').css('background-color', '#C5C7BC'); 9 | }); 10 | }); 11 | }(jQuery)); 12 | -------------------------------------------------------------------------------- /examples/es6-example/main.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | import 'is-in-viewport' 3 | 4 | 5 | $(document).ready(function() { 6 | $('#container > div.box').css('background-color', '#21221E') 7 | $('#container > div.box:in-viewport(100)').css('background-color', '#C5C7BC') 8 | 9 | $(window).scroll(function() { 10 | $('#container > div.box').css('background-color', '#21221E') 11 | $('#container > div.box:in-viewport(100)').css('background-color', '#C5C7BC') 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ############# 2 | ## Windows detritus 3 | ############# 4 | 5 | # Windows image file caches 6 | Thumbs.db 7 | ehthumbs.db 8 | 9 | # Folder config file 10 | Desktop.ini 11 | 12 | # Recycle Bin used on file shares 13 | $RECYCLE.BIN/ 14 | 15 | # Mac crap 16 | .DS_Store 17 | 18 | 19 | ############# 20 | ## Mine 21 | ############# 22 | *.sublime-* 23 | node*/ 24 | isInViewport_*.js 25 | .gitattributes 26 | *.log 27 | /**/*.dmp 28 | TAGS 29 | /**/*.tern-port 30 | node_modules 31 | *compiled* 32 | -------------------------------------------------------------------------------- /examples/es6-example/readme.md: -------------------------------------------------------------------------------- 1 | # Using `is-in-viewport` in an ES6/ES2015 module 2 | ----- 3 | 4 | Run `npm install && npm start` and point your browser to `http://localhost:8000` to see the running example. 5 | 6 | The code is bundled using [rollup](https://github.com/rollup/rollup). 7 | You can see how it used in [main.js](./main.js) and see the [bundling config](./rollup.config.js) on how the bundling is done. 8 | 9 | Since `is-in-viewport` declares `jquery` as a peer dependency, make sure you have it installed as that is the copy it attaches itself onto. 10 | -------------------------------------------------------------------------------- /examples/basic.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $(document).ready(function() { 3 | $('#container > div.box').css('background-color', '#21221E'); 4 | $('#container > div.box:in-viewport').css('background-color', '#C5C7BC'); 5 | 6 | var t = $('.js-hook').text(); 7 | 8 | $(window).scroll(function() { 9 | $('.js-hook').css({ 10 | 'background-color': '#21221E', 11 | 'color': '#fff' 12 | }).find('p').text(t); 13 | $('.js-hook:in-viewport(100)').css({ 14 | 'background-color': '#C5C7BC', 15 | 'color': '#151612' 16 | }).find('p').text('Now in viewport.'); 17 | }); 18 | }); 19 | }(jQuery)); 20 | -------------------------------------------------------------------------------- /examples/es6-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "is-in-viewport-es6-example", 3 | "version": "1.0.0", 4 | "description": "An example of using is-in-viewport in an es6 module", 5 | "main": "main.compiled.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "rollup -c && serve . -p 8000", 9 | "prepublish": "rollup -c" 10 | }, 11 | "author": "Mudit Ameta", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "rollup": "^0.41.5", 15 | "rollup-plugin-commonjs": "^8.0.2", 16 | "rollup-plugin-node-resolve": "^2.0.0", 17 | "serve": "^10.1.1" 18 | }, 19 | "dependencies": { 20 | "is-in-viewport": "^3.0.0", 21 | "jquery": "^3.1.1" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isInViewport", 3 | "version": "3.0.4", 4 | "homepage": "https://github.com/zeusdeux/isInViewport", 5 | "authors": [ 6 | "Mudit Ameta " 7 | ], 8 | "description": "An ultra-light jQuery plugin that tells you if an element is in the viewport but with a twist.", 9 | "main": "lib/isInViewport.min.js", 10 | "keywords": [ 11 | "viewport", 12 | "jquery", 13 | "selector" 14 | ], 15 | "license": "MIT", 16 | "ignore": [ 17 | "examples/**", 18 | "**/.*", 19 | "node_modules", 20 | "bower_components", 21 | "tests", 22 | "*.sublime-*", 23 | "Grunt*.js", 24 | "package.json", 25 | "isInViewport_*.js", 26 | "*.jquery.json", 27 | ".travis*", 28 | ".git*", 29 | "/**/*.dmp", 30 | "/**/*compiled*" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /isInViewport.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isInViewport", 3 | "title": "isInViewport.js", 4 | "description": "An ultra-light jQuery plugin that tells you if the element is in the viewport, but with a twist.", 5 | "keywords": [ 6 | "viewport", 7 | "isInViewport", 8 | "scroll" 9 | ], 10 | "demo": "http://isinviewport.mudit.xyz/", 11 | "version": "3.0.4", 12 | "author": { 13 | "name": "Mudit Ameta", 14 | "url": "https://mudit.xyz" 15 | }, 16 | "licenses": [ 17 | { 18 | "type": "MIT", 19 | "url": "https://github.com/zeusdeux/isInViewport/blob/master/license.md" 20 | } 21 | ], 22 | "bugs": "https://github.com/zeusdeux/isInViewport/issues", 23 | "homepage": "https://github.com/zeusdeux/isInViewport", 24 | "docs": "https://github.com/zeusdeux/isInViewport", 25 | "dependencies": { 26 | "jquery": ">1.7.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isInViewport", 3 | "version": 2, 4 | "public": false, 5 | "alias": ["isinviewport.mudit.xyz", "www.isinviewport.mudit.xyz"], 6 | "builds": [ 7 | { "src": "examples/advanced-viewport.html", "use": "@now/static" }, 8 | { "src": "examples/advanced-viewport.js", "use": "@now/static" }, 9 | { "src": "examples/advanced.html", "use": "@now/static" }, 10 | { "src": "examples/advanced.js", "use": "@now/static" }, 11 | { "src": "examples/basic.html", "use": "@now/static" }, 12 | { "src": "examples/basic.js", "use": "@now/static" }, 13 | { "src": "examples/common.css", "use": "@now/static" }, 14 | { "src": "examples/index.html", "use": "@now/static" }, 15 | { "src": "examples/isInViewport.js", "use": "@now/static" }, 16 | { "src": "examples/isInViewport.js.map", "use": "@now/static" }, 17 | { "src": "tests/**/*", "use": "@now/static" } 18 | ], 19 | "routes": [ 20 | { "src": "/", "dest": "/examples/index.html"}, 21 | { "src": "/tests/(?.*)", "dest": "/tests/$path"}, 22 | { "src": "/(?.*)", "dest": "/examples/$path"} 23 | ], 24 | "github": { 25 | "enabled": false 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright (c) 2012-2017 Mudit Ameta 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /examples/advanced-viewport.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $(document).ready(function() { 3 | //this adjusts the width when there isn't any scrollbar (like on a mobile) 4 | var divWidth = $('div.box:first').outerWidth(); 5 | 6 | // custom viewport 7 | var $viewport = $('#viewport'); 8 | 9 | //outerWidth to include the massive padding it has 10 | //width doesn't work as box-sizing: border-box; 11 | //so padding cuts into width 12 | //sigh! 13 | $('.tolerance').width(divWidth); 14 | $('.outOfViewport').css('left',divWidth+'px'); 15 | 16 | $viewport.find('div.box').css('background-color', '#21221E').text('out of viewport'); 17 | 18 | // using custom viewport with a the "in-viewport" pseudo-selector 19 | $viewport.find('div.box:in-viewport(100, #viewport)').css('background-color', '#C5C7BC').text('in viewport'); 20 | 21 | $('#viewport').scroll(function() { 22 | $viewport.find('div.box').css('background-color', '#21221E').text('out of viewport'); 23 | 24 | // using custom viewport with the isInViewport function 25 | $viewport.find('div.box').isInViewport({ tolerance: 100, viewport: $viewport }).css('background-color', '#C5C7BC').text('in viewport'); 26 | }); 27 | }); 28 | }(jQuery)); 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "is-in-viewport", 3 | "version": "3.0.4", 4 | "private": false, 5 | "description": "An ultra-light jQuery plugin that tells you if an element is in the viewport but with a twist.", 6 | "main": "lib/isInViewport.js", 7 | "module": "lib/isInViewport.es6.js", 8 | "scripts": { 9 | "test": "gulp test", 10 | "build": "gulp", 11 | "clean": "gulp clean", 12 | "deploy": "now -t $NOW_TOKEN && now alias -t $NOW_TOKEN" 13 | }, 14 | "directories": { 15 | "example": "examples" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/zeusdeux/isInViewport.git" 20 | }, 21 | "keywords": [ 22 | "viewport", 23 | "jquery", 24 | "jquery-plugin" 25 | ], 26 | "author": "Mudit Ameta", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/zeusdeux/isInViewport/issues" 30 | }, 31 | "peerDependencies": { 32 | "jquery": ">1.7.0" 33 | }, 34 | "devDependencies": { 35 | "del": "^2.2.2", 36 | "eslint": "^3.17.1", 37 | "eslint-config-standard": "^7.0.1", 38 | "eslint-plugin-promise": "^3.5.0", 39 | "eslint-plugin-standard": "^2.1.1", 40 | "gulp": "^3.9.1", 41 | "gulp-buble": "^0.8.0", 42 | "gulp-cli": "^1.2.2", 43 | "gulp-concat": "^2.6.1", 44 | "gulp-eslint": "^3.0.1", 45 | "gulp-mocha-phantomjs": "^0.12.1", 46 | "gulp-rename": "^1.2.2", 47 | "gulp-sourcemaps": "^2.4.1", 48 | "gulp-uglify": "^2.1.0", 49 | "mocha": "^3.2.0", 50 | "pump": "^1.0.2", 51 | "rollup-plugin-buble": "^0.15.0", 52 | "rollup-stream": "^1.19.0", 53 | "should": "^11.2.1", 54 | "vinyl-buffer": "^1.0.0", 55 | "vinyl-source-stream": "^1.1.0" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/isInViewport.min.js: -------------------------------------------------------------------------------- 1 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],n):n(e.jQuery)}(this,function(e){"use strict";function n(n){var t=this;if(1===arguments.length&&"function"==typeof n&&(n=[n]),!(n instanceof Array))throw new SyntaxError("isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions");return n.forEach(function(n){"function"!=typeof n?(console.warn("isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions"),console.warn("isInViewport: Ignoring non-function values in array and moving on")):[].slice.call(t).forEach(function(t){return n.call(e(t))})}),this}function t(n){var t=e("
").css({width:"100%"});n.append(t);var o=n.width()-t.width();return t.remove(),o}function o(n,r){var i=n.getBoundingClientRect(),a=i.top,u=i.bottom,c=i.left,f=i.right,s=e.extend({tolerance:0,viewport:window},r),d=!1,l=s.viewport.jquery?s.viewport:e(s.viewport);l.length||(console.warn("isInViewport: The viewport selector you have provided matches no element on page."),console.warn("isInViewport: Defaulting to viewport as window"),l=e(window));var p=l.height(),w=l.width(),h=l[0].toString();if(l[0]!==window&&"[object Window]"!==h&&"[object DOMWindow]"!==h){var v=l[0].getBoundingClientRect();a-=v.top,u-=v.top,c-=v.left,f-=v.left,o.scrollBarWidth=o.scrollBarWidth||t(l),w-=o.scrollBarWidth}return s.tolerance=~~Math.round(parseFloat(s.tolerance)),s.tolerance<0&&(s.tolerance=p+s.tolerance),f<=0||c>=w?d:d=s.tolerance?a<=s.tolerance&&u>=s.tolerance:u>0&&a<=p}function r(n){if(n){var t=n.split(",");return 1===t.length&&isNaN(t[0])&&(t[1]=t[0],t[0]=void 0),{tolerance:t[0]?t[0].trim():void 0,viewport:t[1]?e(t[1].trim()):void 0}}return{}}e=e&&e.hasOwnProperty("default")?e.default:e,/** 2 | * @author Mudit Ameta 3 | * @license https://github.com/zeusdeux/isInViewport/blob/master/license.md MIT 4 | */ 5 | e.extend(e.expr.pseudos||e.expr[":"],{"in-viewport":e.expr.createPseudo?e.expr.createPseudo(function(e){return function(n){return o(n,r(e))}}):function(e,n,t){return o(e,r(t[3]))}}),e.fn.isInViewport=function(e){return this.filter(function(n,t){return o(t,e)})},e.fn.run=n}); 6 | //# sourceMappingURL=isInViewport.min.js.map 7 | -------------------------------------------------------------------------------- /tests/horizontallyScrollingViewportTests.js: -------------------------------------------------------------------------------- 1 | function runHorizontallyScrollingViewport() { 2 | var visible = '' 3 | $('li:in-viewport(0, #blocks)').each(function() { 4 | visible += $(this).text() + ' ' 5 | }) 6 | return visible.trim() 7 | } 8 | 9 | function runHorizontallyScrollingViewportVariant() { 10 | var visible = '' 11 | $('li').isInViewport({ tolerance: 0, viewport: $('#blocks') }).each(function() { 12 | visible += $(this).text() + ' ' 13 | }) 14 | return visible.trim() 15 | } 16 | 17 | 18 | var runner = function(runViewportFn, type) { 19 | describe('isInViewport using ' + type, function() { 20 | describe('viewport is a horizonatlly scrollable list (ul#blocks)', function() { 21 | var buidList = function() { 22 | $('body').append('
    ') 23 | 24 | // Add 10 list items to the list 25 | for (var i = 1; i <= 10; i++) { 26 | $('#blocks').append('
  • ' + i + '
  • ') 27 | } 28 | } 29 | var removeList = function() { 30 | $('#blocks').remove() 31 | } 32 | var scrollLeft = function(px) { 33 | px = px || $('#blocks')[0].scrollWidth 34 | $('#blocks').scrollLeft(px) 35 | } 36 | 37 | before(buidList) 38 | after(removeList) 39 | 40 | describe('when the first four items are visible', function() { 41 | it('should return the string "1 2 3 4" as a list of currently visible items', function() { 42 | runViewportFn().should.be.exactly('1 2 3 4') 43 | }) 44 | }) 45 | describe('when we scroll the list left by 525px', function() { 46 | it('should return the string "4 5 6 7 8" as a list of currently visible items', function() { 47 | scrollLeft(525) 48 | runViewportFn().should.be.exactly('4 5 6 7 8') 49 | }) 50 | }) 51 | describe('when we scroll the list to the end', function() { 52 | it('should return the string "7 8 9 10" as a list of currently visible items', function() { 53 | scrollLeft() 54 | runViewportFn().should.be.exactly('7 8 9 10') 55 | }) 56 | }) 57 | }) 58 | }) 59 | } 60 | 61 | runner(runHorizontallyScrollingViewport, 'pseudo-selector') 62 | runner(runHorizontallyScrollingViewportVariant, 'exposed isInViewport function') 63 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp') 2 | const rollup = require('rollup-stream') 3 | const sourcemaps = require('gulp-sourcemaps') 4 | const source = require('vinyl-source-stream') 5 | const buffer = require('vinyl-buffer') 6 | const rename = require('gulp-rename') 7 | const uglify = require('gulp-uglify') 8 | const mochaPhantomjs = require('gulp-mocha-phantomjs') 9 | const buble = require('gulp-buble') 10 | const del = require('del') 11 | const pump = require('pump') 12 | const eslint = require('gulp-eslint') 13 | 14 | 15 | // clean build folder 16 | gulp.task('clean', () => { 17 | return del([ 18 | 'lib/*' 19 | ]) 20 | }) 21 | 22 | // lint 'em files 23 | gulp.task('lint', () => { 24 | return gulp.src(['src/*.js', 'tests/*.js']) 25 | .pipe(eslint()) 26 | .pipe(eslint.format()) 27 | .pipe(eslint.failAfterError()) 28 | }) 29 | 30 | // compile to es2015 but leave the import/exports intact 31 | gulp.task('compile', ['lint'], () => { 32 | return gulp.src('./src/index.js') 33 | .pipe(sourcemaps.init()) 34 | .pipe(buble({ 35 | transforms: { 36 | modules: false 37 | } 38 | })) 39 | .pipe(rename('isInViewport.es6.js')) 40 | .pipe(sourcemaps.write('.')) 41 | .pipe(gulp.dest('lib')) 42 | }) 43 | 44 | // bundle it 45 | gulp.task('rollup', ['compile'], () => { 46 | return rollup({ 47 | input: './lib/isInViewport.es6.js', 48 | format: 'umd', 49 | name: 'isInViewport', 50 | globals: { 51 | jquery: 'jQuery', 52 | window: 'window' 53 | }, 54 | external: ['jquery', 'window'] 55 | }) 56 | .pipe(source('isInViewport.es6.js', './lib')) 57 | .pipe(buffer()) 58 | .pipe(sourcemaps.init({loadMaps: true})) 59 | .pipe(rename('isInViewport.js')) 60 | .pipe(sourcemaps.write('.')) 61 | .pipe(gulp.dest('lib')) 62 | }) 63 | 64 | // minify it 65 | gulp.task('minify', ['rollup'], (cb) => { 66 | pump([ 67 | gulp.src('./lib/isInViewport.js'), 68 | sourcemaps.init({loadMaps: true}), 69 | uglify({ 70 | preserveComments: (_, {type, value: text}) => type === 'comment2' && /@(author|license)/g.test(text) 71 | }), 72 | rename('isInViewport.min.js'), 73 | sourcemaps.write('.'), 74 | gulp.dest('lib') 75 | ], cb) 76 | }) 77 | 78 | // test the transpiled, minified bundle 79 | gulp.task('test', ['minify'], () => { 80 | return gulp.src('./tests/tests.html') 81 | .pipe(mochaPhantomjs()) 82 | .on('error', () => gulp.start('clean')) // remove built files if tests fail 83 | }) 84 | 85 | gulp.task('default', ['clean', 'test']) 86 | -------------------------------------------------------------------------------- /examples/es6-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ES6/ES2015 module isInViewport Example 8 | 9 | 10 | 59 | 61 | 62 | 63 | 64 | 67 |
    68 |
    69 |

    70 | 1 71 |

    72 |
    73 |
    74 |

    75 | 2 76 |

    77 |
    78 |
    79 |

    80 | 3 81 |

    82 |
    83 |
    84 |

    85 | 4 86 |

    87 |
    88 |
    89 |

    90 | 5 91 |

    92 |
    93 |
    94 |

    95 | 6 96 |

    97 |
    98 |
    99 |

    100 | This div, if not in the tolerance area, will never turn light grey. 101 |

    102 |
    103 |
    104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | isInViewport demo 8 | 9 | 10 | 58 | 73 | 74 | 75 | 76 | 77 | Fork me on GitHub 78 | 79 | 82 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /tests/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | isInViewport: Default viewport tests 7 | 8 | 77 | 78 | 79 | 80 | 84 |
    85 | 86 | 87 | 88 | 89 | 90 | 91 | 95 | 96 | 97 | 98 | 99 | 100 | 110 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /examples/advanced.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Advanced isInViewport Example 8 | 9 | 10 | 59 | 61 | 63 | 65 | 80 | 81 | 82 | 83 | 87 |
    88 |
    89 |

    90 | 1 91 |

    92 |
    93 |
    94 |

    95 | 2 96 |

    97 |
    98 |
    99 |

    100 | 3 101 |

    102 |
    103 |
    104 |

    105 | 4 106 |

    107 |
    108 |
    109 |

    110 | 5 111 |

    112 |
    113 |
    114 |

    115 | 6 116 |

    117 |
    118 |
    119 |

    120 | This div, if not in the tolerance area, will never turn light grey. 121 |

    122 |
    123 |
    124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /examples/basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Basic isInViewport Example 8 | 9 | 10 | 62 | 64 | 66 | 68 | 83 | 84 | 85 | 86 | 90 |
    91 |
    92 |
    93 |

    Initially no options are passed to the :in-viewport selector.

    94 |

    Hence all visible div(s) are light grey coloured as default tolerance is height of window.

    95 |

    onscroll, in-viewport is called with tolerance as 100

    96 |

    and debug as true for the div with class `js-hook` ie the 2nd div.

    97 |

    Therefore 2nd div turns light grey only when it is inside tolerance area.

    98 |
    99 |
    100 |
    101 |

    2

    102 |
    103 |
    104 |

    3

    105 |
    106 |
    107 |

    4

    108 |
    109 |
    110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /examples/advanced-viewport.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Advanced-viewport usage example 7 | 8 | 70 | 72 | 74 | 76 | 91 | 92 | 93 | 94 |
    95 |
    96 |
    97 | 101 |
    1
    102 |
    2
    103 |
    3
    104 |
    4
    105 |
    5
    106 |
    6
    107 |
    7
    108 |
    109 |
    110 |

    Where's the 4th div? Inspect it using the developer's console or firebug. :)

    111 |
    112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | 3 | /** 4 | * @author Mudit Ameta 5 | * @license https://github.com/zeusdeux/isInViewport/blob/master/license.md MIT 6 | */ 7 | 8 | // expose isInViewport as a custom pseudo-selector 9 | $.extend($.expr.pseudos || $.expr[':'], { 10 | // if $.expr.createPseudo is available, use it 11 | 'in-viewport': $.expr.createPseudo 12 | ? $.expr.createPseudo(argsString => currElement => isInViewport(currElement, getSelectorArgs(argsString))) 13 | : (currObj, index, meta) => isInViewport(currObj, getSelectorArgs(meta[3])) 14 | }) 15 | 16 | 17 | // expose isInViewport as a function too 18 | // this lets folks pass around actual objects as options (like custom viewport) 19 | // and doesn't tie 'em down to strings. It also prevents isInViewport from 20 | // having to look up and wrap the dom element corresponding to the viewport selector 21 | $.fn.isInViewport = function(options) { 22 | return this.filter((i, el) => isInViewport(el, options)) 23 | } 24 | 25 | $.fn.run = run 26 | 27 | // lets you chain any arbitrary function or an array of functions and returns a jquery object 28 | function run(args) { 29 | if (arguments.length === 1 && typeof args === 'function') { 30 | args = [args] 31 | } 32 | 33 | if (!(args instanceof Array)) { 34 | throw new SyntaxError('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions') 35 | } 36 | 37 | args.forEach(arg => { 38 | if (typeof arg !== 'function') { 39 | console.warn('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions') 40 | console.warn('isInViewport: Ignoring non-function values in array and moving on') 41 | } else { 42 | [].slice.call(this).forEach(t => arg.call($(t))) 43 | } 44 | }) 45 | 46 | return this 47 | } 48 | 49 | 50 | // gets the width of the scrollbar 51 | function getScrollbarWidth(viewport) { 52 | // append a div that has 100% width to get true width of viewport 53 | const el = $('
    ').css({ 54 | width: '100%' 55 | }) 56 | viewport.append(el) 57 | 58 | // subtract true width from the viewport width which is inclusive 59 | // of scrollbar by default 60 | const scrollBarWidth = viewport.width() - el.width() 61 | 62 | // remove our element from DOM 63 | el.remove() 64 | return scrollBarWidth 65 | } 66 | 67 | 68 | // Returns true if DOM element `element` is in viewport 69 | function isInViewport(element, options) { 70 | let {top, bottom, left, right} = element.getBoundingClientRect() 71 | 72 | let settings = $.extend({ 73 | tolerance: 0, 74 | viewport: window 75 | }, options) 76 | let isVisibleFlag = false 77 | let $viewport = settings.viewport.jquery ? settings.viewport : $(settings.viewport) 78 | 79 | if (!$viewport.length) { 80 | console.warn('isInViewport: The viewport selector you have provided matches no element on page.') 81 | console.warn('isInViewport: Defaulting to viewport as window') 82 | $viewport = $(window) 83 | } 84 | 85 | const $viewportHeight = $viewport.height() 86 | let $viewportWidth = $viewport.width() 87 | const typeofViewport = $viewport[0].toString() 88 | 89 | // if the viewport is other than window recalculate the top, 90 | // bottom,left and right wrt the new viewport 91 | // the [object DOMWindow] check is for window object type in PhantomJS 92 | if ($viewport[0] !== window && typeofViewport !== '[object Window]' && typeofViewport !== '[object DOMWindow]') { 93 | // use getBoundingClientRect() instead of $.Offset() 94 | // since the original top/bottom positions are calculated relative to browser viewport and not document 95 | const viewportRect = $viewport[0].getBoundingClientRect() 96 | 97 | // recalculate these relative to viewport 98 | top = top - viewportRect.top 99 | bottom = bottom - viewportRect.top 100 | left = left - viewportRect.left 101 | right = right - viewportRect.left 102 | 103 | // get the scrollbar width from cache or calculate it 104 | isInViewport.scrollBarWidth = isInViewport.scrollBarWidth || getScrollbarWidth($viewport) 105 | 106 | // remove the width of the scrollbar from the viewport width 107 | $viewportWidth -= isInViewport.scrollBarWidth 108 | } 109 | 110 | // handle falsy, non-number and non-integer tolerance value 111 | // same as checking using isNaN and then setting to 0 112 | // bitwise operators deserve some love too you know 113 | settings.tolerance = ~~Math.round(parseFloat(settings.tolerance)) 114 | 115 | if (settings.tolerance < 0) { 116 | settings.tolerance = $viewportHeight + settings.tolerance // viewport height - tol 117 | } 118 | 119 | // the element is NOT in viewport iff it is completely out of 120 | // viewport laterally or if it is completely out of the tolerance 121 | // region. Therefore, if it is partially in view then it is considered 122 | // to be in the viewport and hence true is returned. Because we have adjusted 123 | // the left/right positions relative to the viewport, we should check the 124 | // element's right against the viewport's 0 (left side), and the element's 125 | // left against the viewport's width to see if it is outside of the viewport. 126 | 127 | if (right <= 0 || left >= $viewportWidth) { 128 | return isVisibleFlag 129 | } 130 | 131 | // if the element is bound to some tolerance 132 | isVisibleFlag = settings.tolerance ? top <= settings.tolerance && bottom >= settings.tolerance : bottom > 0 && top <= $viewportHeight 133 | 134 | return isVisibleFlag 135 | } 136 | 137 | 138 | // get the selector args from the args string proved by Sizzle 139 | function getSelectorArgs(argsString) { 140 | if (argsString) { 141 | const args = argsString.split(',') 142 | 143 | // when user only gives viewport and no tolerance 144 | if (args.length === 1 && isNaN(args[0])) { 145 | args[1] = args[0] 146 | args[0] = void 0 147 | } 148 | 149 | return { 150 | tolerance: args[0] ? args[0].trim() : void 0, 151 | viewport: args[1] ? $(args[1].trim()) : void 0 152 | } 153 | } 154 | return {} 155 | } 156 | -------------------------------------------------------------------------------- /lib/isInViewport.es6.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | 3 | /** 4 | * @author Mudit Ameta 5 | * @license https://github.com/zeusdeux/isInViewport/blob/master/license.md MIT 6 | */ 7 | 8 | // expose isInViewport as a custom pseudo-selector 9 | $.extend($.expr.pseudos || $.expr[':'], { 10 | // if $.expr.createPseudo is available, use it 11 | 'in-viewport': $.expr.createPseudo 12 | ? $.expr.createPseudo(function (argsString) { return function (currElement) { return isInViewport(currElement, getSelectorArgs(argsString)); }; }) 13 | : function (currObj, index, meta) { return isInViewport(currObj, getSelectorArgs(meta[3])); } 14 | }) 15 | 16 | 17 | // expose isInViewport as a function too 18 | // this lets folks pass around actual objects as options (like custom viewport) 19 | // and doesn't tie 'em down to strings. It also prevents isInViewport from 20 | // having to look up and wrap the dom element corresponding to the viewport selector 21 | $.fn.isInViewport = function(options) { 22 | return this.filter(function (i, el) { return isInViewport(el, options); }) 23 | } 24 | 25 | $.fn.run = run 26 | 27 | // lets you chain any arbitrary function or an array of functions and returns a jquery object 28 | function run(args) { 29 | var this$1 = this; 30 | 31 | if (arguments.length === 1 && typeof args === 'function') { 32 | args = [args] 33 | } 34 | 35 | if (!(args instanceof Array)) { 36 | throw new SyntaxError('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions') 37 | } 38 | 39 | args.forEach(function (arg) { 40 | if (typeof arg !== 'function') { 41 | console.warn('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions') 42 | console.warn('isInViewport: Ignoring non-function values in array and moving on') 43 | } else { 44 | [].slice.call(this$1).forEach(function (t) { return arg.call($(t)); }) 45 | } 46 | }) 47 | 48 | return this 49 | } 50 | 51 | 52 | // gets the width of the scrollbar 53 | function getScrollbarWidth(viewport) { 54 | // append a div that has 100% width to get true width of viewport 55 | var el = $('
    ').css({ 56 | width: '100%' 57 | }) 58 | viewport.append(el) 59 | 60 | // subtract true width from the viewport width which is inclusive 61 | // of scrollbar by default 62 | var scrollBarWidth = viewport.width() - el.width() 63 | 64 | // remove our element from DOM 65 | el.remove() 66 | return scrollBarWidth 67 | } 68 | 69 | 70 | // Returns true if DOM element `element` is in viewport 71 | function isInViewport(element, options) { 72 | var ref = element.getBoundingClientRect(); 73 | var top = ref.top; 74 | var bottom = ref.bottom; 75 | var left = ref.left; 76 | var right = ref.right; 77 | 78 | var settings = $.extend({ 79 | tolerance: 0, 80 | viewport: window 81 | }, options) 82 | var isVisibleFlag = false 83 | var $viewport = settings.viewport.jquery ? settings.viewport : $(settings.viewport) 84 | 85 | if (!$viewport.length) { 86 | console.warn('isInViewport: The viewport selector you have provided matches no element on page.') 87 | console.warn('isInViewport: Defaulting to viewport as window') 88 | $viewport = $(window) 89 | } 90 | 91 | var $viewportHeight = $viewport.height() 92 | var $viewportWidth = $viewport.width() 93 | var typeofViewport = $viewport[0].toString() 94 | 95 | // if the viewport is other than window recalculate the top, 96 | // bottom,left and right wrt the new viewport 97 | // the [object DOMWindow] check is for window object type in PhantomJS 98 | if ($viewport[0] !== window && typeofViewport !== '[object Window]' && typeofViewport !== '[object DOMWindow]') { 99 | // use getBoundingClientRect() instead of $.Offset() 100 | // since the original top/bottom positions are calculated relative to browser viewport and not document 101 | var viewportRect = $viewport[0].getBoundingClientRect() 102 | 103 | // recalculate these relative to viewport 104 | top = top - viewportRect.top 105 | bottom = bottom - viewportRect.top 106 | left = left - viewportRect.left 107 | right = right - viewportRect.left 108 | 109 | // get the scrollbar width from cache or calculate it 110 | isInViewport.scrollBarWidth = isInViewport.scrollBarWidth || getScrollbarWidth($viewport) 111 | 112 | // remove the width of the scrollbar from the viewport width 113 | $viewportWidth -= isInViewport.scrollBarWidth 114 | } 115 | 116 | // handle falsy, non-number and non-integer tolerance value 117 | // same as checking using isNaN and then setting to 0 118 | // bitwise operators deserve some love too you know 119 | settings.tolerance = ~~Math.round(parseFloat(settings.tolerance)) 120 | 121 | if (settings.tolerance < 0) { 122 | settings.tolerance = $viewportHeight + settings.tolerance // viewport height - tol 123 | } 124 | 125 | // the element is NOT in viewport iff it is completely out of 126 | // viewport laterally or if it is completely out of the tolerance 127 | // region. Therefore, if it is partially in view then it is considered 128 | // to be in the viewport and hence true is returned. Because we have adjusted 129 | // the left/right positions relative to the viewport, we should check the 130 | // element's right against the viewport's 0 (left side), and the element's 131 | // left against the viewport's width to see if it is outside of the viewport. 132 | 133 | if (right <= 0 || left >= $viewportWidth) { 134 | return isVisibleFlag 135 | } 136 | 137 | // if the element is bound to some tolerance 138 | isVisibleFlag = settings.tolerance ? top <= settings.tolerance && bottom >= settings.tolerance : bottom > 0 && top <= $viewportHeight 139 | 140 | return isVisibleFlag 141 | } 142 | 143 | 144 | // get the selector args from the args string proved by Sizzle 145 | function getSelectorArgs(argsString) { 146 | if (argsString) { 147 | var args = argsString.split(',') 148 | 149 | // when user only gives viewport and no tolerance 150 | if (args.length === 1 && isNaN(args[0])) { 151 | args[1] = args[0] 152 | args[0] = void 0 153 | } 154 | 155 | return { 156 | tolerance: args[0] ? args[0].trim() : void 0, 157 | viewport: args[1] ? $(args[1].trim()) : void 0 158 | } 159 | } 160 | return {} 161 | } 162 | 163 | //# sourceMappingURL=isInViewport.es6.js.map 164 | -------------------------------------------------------------------------------- /lib/isInViewport.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["index.js"],"names":["global","factory","this$1","this","arguments","length","args","Array","SyntaxError","forEach","arg","console","warn","const","el","remove","scrollBarWidth","let","ref","element","getBoundingClientRect","top","bottom","left","right","tolerance","viewport","window","options","isVisibleFlag","$viewport","settings","jquery","$","$viewportWidth","width","typeofViewport","viewportRect","isInViewport","getSelectorArgs","argsString","split","isNaN","filter","i","fn","run"],"mappings":"CAAA,SAAQA,EAAMC,iMAgCZ,GAAIC,GAAMC,QAET,IAAAC,UAAAC,QAAA,kBAAAC,cAIGA,YAAaC,aACb,IAAQC,aAAK,uGAGdC,QAAA,SAAAC,GACD,kBAAAA,+GAEFC,QAAWC,KAAA,kLAcXC,MAAM,8CAUN,OADFC,GAAAC,SACgCC,kBAE9BC,GAAIC,GAAAC,EAAaC,wBACfC,EAAAH,EAAYG,IACZC,EAAUJ,EAAAI,OACTC,EAAQL,EAAAK,KACPC,EAAAN,EAAAM,kBAGJC,UAAK,EACHC,SAAQC,QACRC,GACAC,GAAc,EACfC,EAAAC,EAAAL,SAAAM,OAAAD,EAAAL,SAAAO,EAAAF,EAAAL,SAEKI,GAAAzB,SACNY,QAAIL,KAAA,qFACJC,QAAMD,KAAA,gFAKFsB,EAAiBJ,EAAUK,6BAM7BL,EAAY,KAAAH,QAAgB,oBAAAS,GAAA,uBAAAA,EAAA,CAG5B,GAAAC,GAAgBP,EAAa,GAAAV,uBAG7BC,IAAYgB,EAAChB,uBAGbG,GAAca,EAAId,6CAMpBW,GAAkBI,EAAetB,8HAqB1Ba,iEAWHU,GAAiBC,MACjBA,EAAU,IACXlC,GAAAkC,EAAAC,MAAA,IAQJ,OALuB,KAAlBnC,EAAAD,QAAqBqC,MAAQpC,EAAI,MACjCA,EAAA,GAAUA,EAAK,GAChBA,EAAA,OAAA;;;;oNA5HL,MAASH,MAAIwC,OAAO,SAAAC,EAAA9B,GAAA,MAAAwB,GAAAxB,EAAAc,QAClBiB,GAAAC,IAAIA","file":"isInViewport.min.js","sourcesContent":["import $ from 'jquery'\n\n/**\n * @author Mudit Ameta\n * @license https://github.com/zeusdeux/isInViewport/blob/master/license.md MIT\n */\n\n// expose isInViewport as a custom pseudo-selector\n$.extend($.expr.pseudos || $.expr[':'], {\n // if $.expr.createPseudo is available, use it\n 'in-viewport': $.expr.createPseudo\n ? $.expr.createPseudo(argsString => currElement => isInViewport(currElement, getSelectorArgs(argsString)))\n : (currObj, index, meta) => isInViewport(currObj, getSelectorArgs(meta[3]))\n})\n\n\n// expose isInViewport as a function too\n// this lets folks pass around actual objects as options (like custom viewport)\n// and doesn't tie 'em down to strings. It also prevents isInViewport from\n// having to look up and wrap the dom element corresponding to the viewport selector\n$.fn.isInViewport = function(options) {\n return this.filter((i, el) => isInViewport(el, options))\n}\n\n$.fn.run = run\n\n// lets you chain any arbitrary function or an array of functions and returns a jquery object\nfunction run(args) {\n if (arguments.length === 1 && typeof args === 'function') {\n args = [args]\n }\n\n if (!(args instanceof Array)) {\n throw new SyntaxError('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions')\n }\n\n args.forEach(arg => {\n if (typeof arg !== 'function') {\n console.warn('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions')\n console.warn('isInViewport: Ignoring non-function values in array and moving on')\n } else {\n [].slice.call(this).forEach(t => arg.call($(t)))\n }\n })\n\n return this\n}\n\n\n// gets the width of the scrollbar\nfunction getScrollbarWidth(viewport) {\n // append a div that has 100% width to get true width of viewport\n const el = $('
    ').css({\n width: '100%'\n })\n viewport.append(el)\n\n // subtract true width from the viewport width which is inclusive\n // of scrollbar by default\n const scrollBarWidth = viewport.width() - el.width()\n\n // remove our element from DOM\n el.remove()\n return scrollBarWidth\n}\n\n\n// Returns true if DOM element `element` is in viewport\nfunction isInViewport(element, options) {\n let {top, bottom, left, right} = element.getBoundingClientRect()\n\n let settings = $.extend({\n tolerance: 0,\n viewport: window\n }, options)\n let isVisibleFlag = false\n let $viewport = settings.viewport.jquery ? settings.viewport : $(settings.viewport)\n\n if (!$viewport.length) {\n console.warn('isInViewport: The viewport selector you have provided matches no element on page.')\n console.warn('isInViewport: Defaulting to viewport as window')\n $viewport = $(window)\n }\n\n const $viewportHeight = $viewport.height()\n let $viewportWidth = $viewport.width()\n const typeofViewport = $viewport[0].toString()\n\n // if the viewport is other than window recalculate the top,\n // bottom,left and right wrt the new viewport\n // the [object DOMWindow] check is for window object type in PhantomJS\n if ($viewport[0] !== window && typeofViewport !== '[object Window]' && typeofViewport !== '[object DOMWindow]') {\n // use getBoundingClientRect() instead of $.Offset()\n // since the original top/bottom positions are calculated relative to browser viewport and not document\n const viewportRect = $viewport[0].getBoundingClientRect()\n\n // recalculate these relative to viewport\n top = top - viewportRect.top\n bottom = bottom - viewportRect.top\n left = left - viewportRect.left\n right = right - viewportRect.left\n\n // get the scrollbar width from cache or calculate it\n isInViewport.scrollBarWidth = isInViewport.scrollBarWidth || getScrollbarWidth($viewport)\n\n // remove the width of the scrollbar from the viewport width\n $viewportWidth -= isInViewport.scrollBarWidth\n }\n\n // handle falsy, non-number and non-integer tolerance value\n // same as checking using isNaN and then setting to 0\n // bitwise operators deserve some love too you know\n settings.tolerance = ~~Math.round(parseFloat(settings.tolerance))\n\n if (settings.tolerance < 0) {\n settings.tolerance = $viewportHeight + settings.tolerance // viewport height - tol\n }\n\n // the element is NOT in viewport iff it is completely out of\n // viewport laterally or if it is completely out of the tolerance\n // region. Therefore, if it is partially in view then it is considered\n // to be in the viewport and hence true is returned. Because we have adjusted\n // the left/right positions relative to the viewport, we should check the\n // element's right against the viewport's 0 (left side), and the element's\n // left against the viewport's width to see if it is outside of the viewport.\n\n if (right <= 0 || left >= $viewportWidth) {\n return isVisibleFlag\n }\n\n // if the element is bound to some tolerance\n isVisibleFlag = settings.tolerance ? top <= settings.tolerance && bottom >= settings.tolerance : bottom > 0 && top <= $viewportHeight\n\n return isVisibleFlag\n}\n\n\n// get the selector args from the args string proved by Sizzle\nfunction getSelectorArgs(argsString) {\n if (argsString) {\n const args = argsString.split(',')\n\n // when user only gives viewport and no tolerance\n if (args.length === 1 && isNaN(args[0])) {\n args[1] = args[0]\n args[0] = void 0\n }\n\n return {\n tolerance: args[0] ? args[0].trim() : void 0,\n viewport: args[1] ? $(args[1].trim()) : void 0\n }\n }\n return {}\n}\n"]} -------------------------------------------------------------------------------- /lib/isInViewport.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) : 3 | typeof define === 'function' && define.amd ? define(['jquery'], factory) : 4 | (factory(global.jQuery)); 5 | }(this, (function ($) { 'use strict'; 6 | 7 | $ = $ && $.hasOwnProperty('default') ? $['default'] : $; 8 | 9 | /** 10 | * @author Mudit Ameta 11 | * @license https://github.com/zeusdeux/isInViewport/blob/master/license.md MIT 12 | */ 13 | 14 | // expose isInViewport as a custom pseudo-selector 15 | $.extend($.expr.pseudos || $.expr[':'], { 16 | // if $.expr.createPseudo is available, use it 17 | 'in-viewport': $.expr.createPseudo 18 | ? $.expr.createPseudo(function (argsString) { return function (currElement) { return isInViewport(currElement, getSelectorArgs(argsString)); }; }) 19 | : function (currObj, index, meta) { return isInViewport(currObj, getSelectorArgs(meta[3])); } 20 | }); 21 | 22 | 23 | // expose isInViewport as a function too 24 | // this lets folks pass around actual objects as options (like custom viewport) 25 | // and doesn't tie 'em down to strings. It also prevents isInViewport from 26 | // having to look up and wrap the dom element corresponding to the viewport selector 27 | $.fn.isInViewport = function(options) { 28 | return this.filter(function (i, el) { return isInViewport(el, options); }) 29 | }; 30 | 31 | $.fn.run = run; 32 | 33 | // lets you chain any arbitrary function or an array of functions and returns a jquery object 34 | function run(args) { 35 | var this$1 = this; 36 | 37 | if (arguments.length === 1 && typeof args === 'function') { 38 | args = [args]; 39 | } 40 | 41 | if (!(args instanceof Array)) { 42 | throw new SyntaxError('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions') 43 | } 44 | 45 | args.forEach(function (arg) { 46 | if (typeof arg !== 'function') { 47 | console.warn('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions'); 48 | console.warn('isInViewport: Ignoring non-function values in array and moving on'); 49 | } else { 50 | [].slice.call(this$1).forEach(function (t) { return arg.call($(t)); }); 51 | } 52 | }); 53 | 54 | return this 55 | } 56 | 57 | 58 | // gets the width of the scrollbar 59 | function getScrollbarWidth(viewport) { 60 | // append a div that has 100% width to get true width of viewport 61 | var el = $('
    ').css({ 62 | width: '100%' 63 | }); 64 | viewport.append(el); 65 | 66 | // subtract true width from the viewport width which is inclusive 67 | // of scrollbar by default 68 | var scrollBarWidth = viewport.width() - el.width(); 69 | 70 | // remove our element from DOM 71 | el.remove(); 72 | return scrollBarWidth 73 | } 74 | 75 | 76 | // Returns true if DOM element `element` is in viewport 77 | function isInViewport(element, options) { 78 | var ref = element.getBoundingClientRect(); 79 | var top = ref.top; 80 | var bottom = ref.bottom; 81 | var left = ref.left; 82 | var right = ref.right; 83 | 84 | var settings = $.extend({ 85 | tolerance: 0, 86 | viewport: window 87 | }, options); 88 | var isVisibleFlag = false; 89 | var $viewport = settings.viewport.jquery ? settings.viewport : $(settings.viewport); 90 | 91 | if (!$viewport.length) { 92 | console.warn('isInViewport: The viewport selector you have provided matches no element on page.'); 93 | console.warn('isInViewport: Defaulting to viewport as window'); 94 | $viewport = $(window); 95 | } 96 | 97 | var $viewportHeight = $viewport.height(); 98 | var $viewportWidth = $viewport.width(); 99 | var typeofViewport = $viewport[0].toString(); 100 | 101 | // if the viewport is other than window recalculate the top, 102 | // bottom,left and right wrt the new viewport 103 | // the [object DOMWindow] check is for window object type in PhantomJS 104 | if ($viewport[0] !== window && typeofViewport !== '[object Window]' && typeofViewport !== '[object DOMWindow]') { 105 | // use getBoundingClientRect() instead of $.Offset() 106 | // since the original top/bottom positions are calculated relative to browser viewport and not document 107 | var viewportRect = $viewport[0].getBoundingClientRect(); 108 | 109 | // recalculate these relative to viewport 110 | top = top - viewportRect.top; 111 | bottom = bottom - viewportRect.top; 112 | left = left - viewportRect.left; 113 | right = right - viewportRect.left; 114 | 115 | // get the scrollbar width from cache or calculate it 116 | isInViewport.scrollBarWidth = isInViewport.scrollBarWidth || getScrollbarWidth($viewport); 117 | 118 | // remove the width of the scrollbar from the viewport width 119 | $viewportWidth -= isInViewport.scrollBarWidth; 120 | } 121 | 122 | // handle falsy, non-number and non-integer tolerance value 123 | // same as checking using isNaN and then setting to 0 124 | // bitwise operators deserve some love too you know 125 | settings.tolerance = ~~Math.round(parseFloat(settings.tolerance)); 126 | 127 | if (settings.tolerance < 0) { 128 | settings.tolerance = $viewportHeight + settings.tolerance; // viewport height - tol 129 | } 130 | 131 | // the element is NOT in viewport iff it is completely out of 132 | // viewport laterally or if it is completely out of the tolerance 133 | // region. Therefore, if it is partially in view then it is considered 134 | // to be in the viewport and hence true is returned. Because we have adjusted 135 | // the left/right positions relative to the viewport, we should check the 136 | // element's right against the viewport's 0 (left side), and the element's 137 | // left against the viewport's width to see if it is outside of the viewport. 138 | 139 | if (right <= 0 || left >= $viewportWidth) { 140 | return isVisibleFlag 141 | } 142 | 143 | // if the element is bound to some tolerance 144 | isVisibleFlag = settings.tolerance ? top <= settings.tolerance && bottom >= settings.tolerance : bottom > 0 && top <= $viewportHeight; 145 | 146 | return isVisibleFlag 147 | } 148 | 149 | 150 | // get the selector args from the args string proved by Sizzle 151 | function getSelectorArgs(argsString) { 152 | if (argsString) { 153 | var args = argsString.split(','); 154 | 155 | // when user only gives viewport and no tolerance 156 | if (args.length === 1 && isNaN(args[0])) { 157 | args[1] = args[0]; 158 | args[0] = void 0; 159 | } 160 | 161 | return { 162 | tolerance: args[0] ? args[0].trim() : void 0, 163 | viewport: args[1] ? $(args[1].trim()) : void 0 164 | } 165 | } 166 | return {} 167 | } 168 | 169 | }))); 170 | 171 | //# sourceMappingURL=isInViewport.js.map 172 | -------------------------------------------------------------------------------- /tests/customViewportTests.js: -------------------------------------------------------------------------------- 1 | function runCustomIsInViewport(tol) { 2 | $('#viewport > div.box').css('background-color', '#21221E').text('out of viewport') 3 | if (typeof tol !== 'undefined') { 4 | $('#viewport > div.box:in-viewport(' + tol + ', #viewport)').css('background-color', '#C5C7BC').text('in viewport') 5 | } else { 6 | $('#viewport > div.box:in-viewport(#viewport)').css('background-color', '#C5C7BC').text('in viewport') 7 | } 8 | } 9 | 10 | function runCustomIsInViewportVariant(tol) { 11 | var $viewport = $('#viewport') 12 | 13 | $viewport.find('div.box').css('background-color', '#21221E').text('out of viewport') 14 | if (typeof tol !== 'undefined') { 15 | $viewport.find('div.box').isInViewport({ tolerance: tol, viewport: $viewport }).css('background-color', '#C5C7BC').text('in viewport') 16 | } else { 17 | $viewport.find('div.box').isInViewport({ viewport: $viewport }).css('background-color', '#C5C7BC').text('in viewport') 18 | } 19 | } 20 | 21 | 22 | var runner = function(runViewportFn, type) { 23 | describe('isInViewport using ' + type, function() { 24 | describe('viewport is div#viewport', function() { 25 | var div 26 | var viewport = '#viewport' 27 | 28 | before(function() { 29 | var html = '
    1
    ' 30 | $('body').prepend(html) 31 | runViewportFn(100) 32 | div = $('.box') 33 | }) 34 | 35 | after(function() { 36 | $('#container').remove() 37 | }) 38 | 39 | function top(x, tol) { 40 | div.css('top', '0') 41 | div.css('top', x + 'px') 42 | runViewportFn(tol) 43 | } 44 | 45 | function left(x, tol) { 46 | div.css('left', '0') 47 | div.css('left', x + 'px') 48 | runViewportFn(tol) 49 | } 50 | 51 | describe('tolerance is 100', function() { 52 | describe('div location vertically in viewport', function() { 53 | describe('when bottom of div is outside tolerance region while top is inside', function() { 54 | it('should return the text from div as "in viewport"', function() { 55 | div.text().should.be.exactly('in viewport') 56 | }) 57 | }) 58 | describe('when bottom of div is equal to tolerance ie it\'s on the edge of tolerance region', function() { 59 | it('should return the text from div as "in viewport"', function() { 60 | top(-100, 100) 61 | div.text().should.be.exactly('in viewport') 62 | }) 63 | }) 64 | describe('when bottom of div is inside tolerance region', function() { 65 | it('should return the text from div as "out of viewport"', function() { 66 | top(-150, 100) 67 | div.text().should.be.exactly('out of viewport') 68 | }) 69 | }) 70 | describe('when top of div is equal to tolerance ie it\'s on the edge of tolerance region', function() { 71 | it('should return the text from div as "in viewport"', function() { 72 | top(100, 100) 73 | div.text().should.be.exactly('in viewport') 74 | }) 75 | }) 76 | describe('when top of div is outside tolerance region', function() { 77 | it('should return the text from div as "out of viewport"', function() { 78 | top(101, 100) 79 | div.text().should.be.exactly('out of viewport') 80 | }) 81 | }) 82 | }) 83 | 84 | describe('div location horizontally in viewport', function() { 85 | describe('when left is greater than viewport width', function() { 86 | it('should return the text from div as "out of viewport"', function() { 87 | top(0, 100) 88 | left(99999, 100) 89 | div.text().should.be.exactly('out of viewport') 90 | }) 91 | }) 92 | describe('when left is greater than viewport left edge', function() { 93 | it('should return the text from div as "out of viewport"', function() { 94 | left(-99999, 100) 95 | div.text().should.be.exactly('out of viewport') 96 | }) 97 | }) 98 | describe('when left is lesser than viewport width', function() { 99 | it('should return the text from div as "in viewport"', function() { 100 | left(90, 100) 101 | div.text().should.be.exactly('in viewport') 102 | left(0, 100) 103 | }) 104 | }) 105 | }) 106 | }) 107 | 108 | describe('tolerance is 0', function() { 109 | describe('div location vertically in viewport', function() { 110 | describe('when div top is 0', function() { 111 | it('should return the text from div as "in viewport"', function() { 112 | top(0, 0) 113 | left(0, 0) 114 | div.text().should.be.exactly('in viewport') 115 | }) 116 | }) 117 | describe('when div top < 0 but bottom > 0', function() { 118 | it('should return the text from div as "in viewport"', function() { 119 | top(-1, 0) 120 | div.text().should.be.exactly('in viewport') 121 | }) 122 | }) 123 | describe('when div bottom < 0', function() { 124 | it('should return the text from div as "out of viewport"', function() { 125 | top(-201, 0) 126 | div.text().should.be.exactly('out of viewport') 127 | }) 128 | }) 129 | describe('when div top > viewport height', function() { 130 | it('should return the text from div as "out of viewport"', function() { 131 | top(99999, 0) 132 | div.text().should.be.exactly('out of viewport') 133 | }) 134 | }) 135 | }) 136 | 137 | describe('div location horizontally in viewport', function() { 138 | describe('when left is greater than viewport width', function() { 139 | it('should return the text from div as "out of viewport"', function() { 140 | top(0, 0) 141 | left(99999, 0) 142 | div.text().should.be.exactly('out of viewport') 143 | }) 144 | }) 145 | describe('when left is greater than viewport left edge', function() { 146 | it('should return the text from div as "out of viewport"', function() { 147 | left(-99999, 0) 148 | div.text().should.be.exactly('out of viewport') 149 | }) 150 | }) 151 | describe('when left is lesser than viewport width', function() { 152 | it('should return the text from div as "in viewport"', function() { 153 | left(90, 0) 154 | div.text().should.be.exactly('in viewport') 155 | left(0, 0) 156 | }) 157 | }) 158 | }) 159 | }) 160 | 161 | describe('when tolerance is -100', function() { 162 | it('should be window.height - abs(tolerance)', function() { 163 | var viewportHt = $(viewport).height() 164 | top(viewportHt - 100, -100) 165 | div.text().should.be.exactly('in viewport') 166 | }) 167 | }) 168 | 169 | describe('when tolerance is undefined', function() { 170 | describe('when viewport is specified', function() { 171 | describe('when div is inside viewport', function() { 172 | it('should return the text from div as "in viewport"', function() { 173 | left(0) 174 | top(0) 175 | div.text().should.be.exactly('in viewport') 176 | }) 177 | }) 178 | }) 179 | }) 180 | }) 181 | }) 182 | } 183 | 184 | // test both pseudo-selector as well as exposed isInViewport fn 185 | runner(runCustomIsInViewport, 'pseudo-selector') 186 | runner(runCustomIsInViewportVariant, 'isInViewport exposed function') 187 | -------------------------------------------------------------------------------- /lib/isInViewport.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"isInViewport.js","sources":["index.js"],"sourcesContent":["import $ from 'jquery'\n\n/**\n * @author Mudit Ameta\n * @license https://github.com/zeusdeux/isInViewport/blob/master/license.md MIT\n */\n\n// expose isInViewport as a custom pseudo-selector\n$.extend($.expr.pseudos || $.expr[':'], {\n // if $.expr.createPseudo is available, use it\n 'in-viewport': $.expr.createPseudo\n ? $.expr.createPseudo(argsString => currElement => isInViewport(currElement, getSelectorArgs(argsString)))\n : (currObj, index, meta) => isInViewport(currObj, getSelectorArgs(meta[3]))\n})\n\n\n// expose isInViewport as a function too\n// this lets folks pass around actual objects as options (like custom viewport)\n// and doesn't tie 'em down to strings. It also prevents isInViewport from\n// having to look up and wrap the dom element corresponding to the viewport selector\n$.fn.isInViewport = function(options) {\n return this.filter((i, el) => isInViewport(el, options))\n}\n\n$.fn.run = run\n\n// lets you chain any arbitrary function or an array of functions and returns a jquery object\nfunction run(args) {\n if (arguments.length === 1 && typeof args === 'function') {\n args = [args]\n }\n\n if (!(args instanceof Array)) {\n throw new SyntaxError('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions')\n }\n\n args.forEach(arg => {\n if (typeof arg !== 'function') {\n console.warn('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions')\n console.warn('isInViewport: Ignoring non-function values in array and moving on')\n } else {\n [].slice.call(this).forEach(t => arg.call($(t)))\n }\n })\n\n return this\n}\n\n\n// gets the width of the scrollbar\nfunction getScrollbarWidth(viewport) {\n // append a div that has 100% width to get true width of viewport\n const el = $('
    ').css({\n width: '100%'\n })\n viewport.append(el)\n\n // subtract true width from the viewport width which is inclusive\n // of scrollbar by default\n const scrollBarWidth = viewport.width() - el.width()\n\n // remove our element from DOM\n el.remove()\n return scrollBarWidth\n}\n\n\n// Returns true if DOM element `element` is in viewport\nfunction isInViewport(element, options) {\n let {top, bottom, left, right} = element.getBoundingClientRect()\n\n let settings = $.extend({\n tolerance: 0,\n viewport: window\n }, options)\n let isVisibleFlag = false\n let $viewport = settings.viewport.jquery ? settings.viewport : $(settings.viewport)\n\n if (!$viewport.length) {\n console.warn('isInViewport: The viewport selector you have provided matches no element on page.')\n console.warn('isInViewport: Defaulting to viewport as window')\n $viewport = $(window)\n }\n\n const $viewportHeight = $viewport.height()\n let $viewportWidth = $viewport.width()\n const typeofViewport = $viewport[0].toString()\n\n // if the viewport is other than window recalculate the top,\n // bottom,left and right wrt the new viewport\n // the [object DOMWindow] check is for window object type in PhantomJS\n if ($viewport[0] !== window && typeofViewport !== '[object Window]' && typeofViewport !== '[object DOMWindow]') {\n // use getBoundingClientRect() instead of $.Offset()\n // since the original top/bottom positions are calculated relative to browser viewport and not document\n const viewportRect = $viewport[0].getBoundingClientRect()\n\n // recalculate these relative to viewport\n top = top - viewportRect.top\n bottom = bottom - viewportRect.top\n left = left - viewportRect.left\n right = right - viewportRect.left\n\n // get the scrollbar width from cache or calculate it\n isInViewport.scrollBarWidth = isInViewport.scrollBarWidth || getScrollbarWidth($viewport)\n\n // remove the width of the scrollbar from the viewport width\n $viewportWidth -= isInViewport.scrollBarWidth\n }\n\n // handle falsy, non-number and non-integer tolerance value\n // same as checking using isNaN and then setting to 0\n // bitwise operators deserve some love too you know\n settings.tolerance = ~~Math.round(parseFloat(settings.tolerance))\n\n if (settings.tolerance < 0) {\n settings.tolerance = $viewportHeight + settings.tolerance // viewport height - tol\n }\n\n // the element is NOT in viewport iff it is completely out of\n // viewport laterally or if it is completely out of the tolerance\n // region. Therefore, if it is partially in view then it is considered\n // to be in the viewport and hence true is returned. Because we have adjusted\n // the left/right positions relative to the viewport, we should check the\n // element's right against the viewport's 0 (left side), and the element's\n // left against the viewport's width to see if it is outside of the viewport.\n\n if (right <= 0 || left >= $viewportWidth) {\n return isVisibleFlag\n }\n\n // if the element is bound to some tolerance\n isVisibleFlag = settings.tolerance ? top <= settings.tolerance && bottom >= settings.tolerance : bottom > 0 && top <= $viewportHeight\n\n return isVisibleFlag\n}\n\n\n// get the selector args from the args string proved by Sizzle\nfunction getSelectorArgs(argsString) {\n if (argsString) {\n const args = argsString.split(',')\n\n // when user only gives viewport and no tolerance\n if (args.length === 1 && isNaN(args[0])) {\n args[1] = args[0]\n args[0] = void 0\n }\n\n return {\n tolerance: args[0] ? args[0].trim() : void 0,\n viewport: args[1] ? $(args[1].trim()) : void 0\n }\n }\n return {}\n}\n"],"names":["this","const","let"],"mappings":"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"} -------------------------------------------------------------------------------- /lib/isInViewport.es6.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"isInViewport.es6.js","sources":["index.js"],"sourcesContent":["import $ from 'jquery'\n\n/**\n * @author Mudit Ameta\n * @license https://github.com/zeusdeux/isInViewport/blob/master/license.md MIT\n */\n\n// expose isInViewport as a custom pseudo-selector\n$.extend($.expr.pseudos || $.expr[':'], {\n // if $.expr.createPseudo is available, use it\n 'in-viewport': $.expr.createPseudo\n ? $.expr.createPseudo(argsString => currElement => isInViewport(currElement, getSelectorArgs(argsString)))\n : (currObj, index, meta) => isInViewport(currObj, getSelectorArgs(meta[3]))\n})\n\n\n// expose isInViewport as a function too\n// this lets folks pass around actual objects as options (like custom viewport)\n// and doesn't tie 'em down to strings. It also prevents isInViewport from\n// having to look up and wrap the dom element corresponding to the viewport selector\n$.fn.isInViewport = function(options) {\n return this.filter((i, el) => isInViewport(el, options))\n}\n\n$.fn.run = run\n\n// lets you chain any arbitrary function or an array of functions and returns a jquery object\nfunction run(args) {\n if (arguments.length === 1 && typeof args === 'function') {\n args = [args]\n }\n\n if (!(args instanceof Array)) {\n throw new SyntaxError('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions')\n }\n\n args.forEach(arg => {\n if (typeof arg !== 'function') {\n console.warn('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions')\n console.warn('isInViewport: Ignoring non-function values in array and moving on')\n } else {\n [].slice.call(this).forEach(t => arg.call($(t)))\n }\n })\n\n return this\n}\n\n\n// gets the width of the scrollbar\nfunction getScrollbarWidth(viewport) {\n // append a div that has 100% width to get true width of viewport\n const el = $('
    ').css({\n width: '100%'\n })\n viewport.append(el)\n\n // subtract true width from the viewport width which is inclusive\n // of scrollbar by default\n const scrollBarWidth = viewport.width() - el.width()\n\n // remove our element from DOM\n el.remove()\n return scrollBarWidth\n}\n\n\n// Returns true if DOM element `element` is in viewport\nfunction isInViewport(element, options) {\n let {top, bottom, left, right} = element.getBoundingClientRect()\n\n let settings = $.extend({\n tolerance: 0,\n viewport: window\n }, options)\n let isVisibleFlag = false\n let $viewport = settings.viewport.jquery ? settings.viewport : $(settings.viewport)\n\n if (!$viewport.length) {\n console.warn('isInViewport: The viewport selector you have provided matches no element on page.')\n console.warn('isInViewport: Defaulting to viewport as window')\n $viewport = $(window)\n }\n\n const $viewportHeight = $viewport.height()\n let $viewportWidth = $viewport.width()\n const typeofViewport = $viewport[0].toString()\n\n // if the viewport is other than window recalculate the top,\n // bottom,left and right wrt the new viewport\n // the [object DOMWindow] check is for window object type in PhantomJS\n if ($viewport[0] !== window && typeofViewport !== '[object Window]' && typeofViewport !== '[object DOMWindow]') {\n // use getBoundingClientRect() instead of $.Offset()\n // since the original top/bottom positions are calculated relative to browser viewport and not document\n const viewportRect = $viewport[0].getBoundingClientRect()\n\n // recalculate these relative to viewport\n top = top - viewportRect.top\n bottom = bottom - viewportRect.top\n left = left - viewportRect.left\n right = right - viewportRect.left\n\n // get the scrollbar width from cache or calculate it\n isInViewport.scrollBarWidth = isInViewport.scrollBarWidth || getScrollbarWidth($viewport)\n\n // remove the width of the scrollbar from the viewport width\n $viewportWidth -= isInViewport.scrollBarWidth\n }\n\n // handle falsy, non-number and non-integer tolerance value\n // same as checking using isNaN and then setting to 0\n // bitwise operators deserve some love too you know\n settings.tolerance = ~~Math.round(parseFloat(settings.tolerance))\n\n if (settings.tolerance < 0) {\n settings.tolerance = $viewportHeight + settings.tolerance // viewport height - tol\n }\n\n // the element is NOT in viewport iff it is completely out of\n // viewport laterally or if it is completely out of the tolerance\n // region. Therefore, if it is partially in view then it is considered\n // to be in the viewport and hence true is returned. Because we have adjusted\n // the left/right positions relative to the viewport, we should check the\n // element's right against the viewport's 0 (left side), and the element's\n // left against the viewport's width to see if it is outside of the viewport.\n\n if (right <= 0 || left >= $viewportWidth) {\n return isVisibleFlag\n }\n\n // if the element is bound to some tolerance\n isVisibleFlag = settings.tolerance ? top <= settings.tolerance && bottom >= settings.tolerance : bottom > 0 && top <= $viewportHeight\n\n return isVisibleFlag\n}\n\n\n// get the selector args from the args string proved by Sizzle\nfunction getSelectorArgs(argsString) {\n if (argsString) {\n const args = argsString.split(',')\n\n // when user only gives viewport and no tolerance\n if (args.length === 1 && isNaN(args[0])) {\n args[1] = args[0]\n args[0] = void 0\n }\n\n return {\n tolerance: args[0] ? args[0].trim() : void 0,\n viewport: args[1] ? $(args[1].trim()) : void 0\n }\n }\n return {}\n}\n"],"names":["this","const","let"],"mappings":"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"} -------------------------------------------------------------------------------- /tests/defaultViewportTests.js: -------------------------------------------------------------------------------- 1 | function runIsInViewport(tol) { 2 | $('#container > div.box').css('background-color', '#21221E').text('out of viewport') 3 | $('#container > div.box:in-viewport(' + tol + ')').css('background-color', '#C5C7BC').text('in viewport') 4 | } 5 | 6 | function runIsInViewportWithJqueryNot(tol) { 7 | $('#container > div.box').not(':in-viewport(' + tol + ')').css('background-color', '#21221E').text('out of viewport') 8 | $('#container > div.box:in-viewport(' + tol + ')').css('background-color', '#C5C7BC').text('in viewport') 9 | } 10 | 11 | function runIsInViewportVariant(tol) { 12 | $('#container > div.box').css('background-color', '#21221E').text('out of viewport') 13 | $('#container > div.box').isInViewport({ tolerance: tol }).css('background-color', '#C5C7BC').text('in viewport') 14 | } 15 | 16 | var runner = function(runIsInViewportFn, type) { 17 | describe('isInViewport using ' + type, function() { 18 | describe('viewport is window', function() { 19 | var div 20 | var addContainer = function() { 21 | var html = '
    1
    ' 22 | $('body').prepend(html) 23 | runIsInViewportFn(100) 24 | div = $('.box') 25 | } 26 | var removeContainer = function() { 27 | $('#container').remove() 28 | } 29 | 30 | before(addContainer) 31 | 32 | after(removeContainer) 33 | 34 | function top(y, tol) { 35 | div.css('top', '0') 36 | div.css('top', y + 'px') 37 | runIsInViewportFn(tol) 38 | } 39 | 40 | function left(x, tol) { 41 | div.css('left', '0') 42 | div.css('left', x + 'px') 43 | runIsInViewportFn(tol) 44 | } 45 | 46 | describe('when tolerance is 100', function() { 47 | describe('div location vertically in viewport', function() { 48 | describe('when bottom of div is outside tolerance region while top is inside', function() { 49 | it('should return the text from div as "in viewport"', function() { 50 | div.text().should.be.exactly('in viewport') 51 | }) 52 | }) 53 | describe('when bottom of div is equal to tolerance ie it\'s on the edge of tolerance region', function() { 54 | it('should return the text from div as "in viewport"', function() { 55 | top(-100, 100) 56 | div.text().should.be.exactly('in viewport') 57 | }) 58 | }) 59 | describe('when bottom of div is inside tolerance region', function() { 60 | it('should return the text from div as "out of viewport"', function() { 61 | top(-150, 100) 62 | div.text().should.be.exactly('out of viewport') 63 | }) 64 | }) 65 | describe('when top of div is equal to tolerance ie it\'s on the edge of tolerance region', function() { 66 | it('should return the text from div as "in viewport"', function() { 67 | top(100, 100) 68 | div.text().should.be.exactly('in viewport') 69 | }) 70 | }) 71 | describe('when top of div is outside tolerance region', function() { 72 | it('should return the text from div as "out of viewport"', function() { 73 | top(101, 100) 74 | div.text().should.be.exactly('out of viewport') 75 | }) 76 | }) 77 | }) 78 | 79 | describe('div location horizontally in viewport', function() { 80 | describe('when left is greater than viewport width', function() { 81 | it('should return the text from div as "out of viewport"', function() { 82 | top(0, 100) 83 | left(99999, 100) 84 | div.text().should.be.exactly('out of viewport') 85 | }) 86 | }) 87 | describe('when left is greater than viewport left edge', function() { 88 | it('should return the text from div as "out of viewport"', function() { 89 | left(-99999, 100) 90 | div.text().should.be.exactly('out of viewport') 91 | }) 92 | }) 93 | describe('when left is lesser than viewport width', function() { 94 | it('should return the text from div as "in viewport"', function() { 95 | left(90, 100) 96 | div.text().should.be.exactly('in viewport') 97 | left(0, 100) 98 | }) 99 | }) 100 | }) 101 | }) 102 | 103 | describe('when tolerance is 0', function() { 104 | describe('div location vertically in viewport', function() { 105 | describe('when div top is 0', function() { 106 | it('should return the text from div as "in viewport"', function() { 107 | top(0, 0) 108 | left(0, 0) 109 | div.text().should.be.exactly('in viewport') 110 | }) 111 | }) 112 | describe('when div top < 0 but bottom > 0', function() { 113 | it('should return the text from div as "in viewport"', function() { 114 | top(-1, 0) 115 | div.text().should.be.exactly('in viewport') 116 | }) 117 | }) 118 | describe('when div bottom < 0', function() { 119 | it('should return the text from div as "out of viewport"', function() { 120 | top(-201, 0) 121 | div.text().should.be.exactly('out of viewport') 122 | }) 123 | }) 124 | describe('when div top > viewport height', function() { 125 | it('should return the text from div as "out of viewport"', function() { 126 | top(99999, 0) 127 | div.text().should.be.exactly('out of viewport') 128 | }) 129 | }) 130 | describe('when both divs are in viewport', function() { 131 | describe('when two arbitrary functions are chained using .do/.run', function() { 132 | describe('when the first fn changes inner text to done and second adds a class name given by inner text', function() { 133 | it('should have added a class named "done" to both divs', function() { 134 | removeContainer() 135 | var html = '
    1
    2
    ' 136 | $('body').prepend(html) 137 | var divs = $('div.box:in-viewport') 138 | var count = 0 139 | divs.should.have.length(2, 'length isn\'t 2') 140 | divs.run(function() { 141 | this.text('done') 142 | }).run(function() { 143 | // value of this is a normal html node and not a jQuery object 144 | // hence it is being converted to a jQuery object here 145 | this.addClass(this.text()) 146 | }) 147 | $.each(divs, function(i, v) { 148 | if ($(v).hasClass('done')) { 149 | count++ 150 | } 151 | }) 152 | count.should.be.exactly(2, 'both divs don\'t have "done" class') 153 | }) 154 | }) 155 | }) 156 | describe('when values other than functions are passed to .do/.run', function() { 157 | it('should throw an error', function() { 158 | var divs = $('div.box:in-viewport') 159 | divs.should.have.length(2, 'length isn\'t 2') 160 | try { 161 | divs.run('boooop') 162 | } catch (e) { 163 | e.message.should.be.exactly('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions') 164 | } 165 | }) 166 | }) 167 | describe('when array containing mixed values is passed to .do/.run', function() { 168 | it('should ignore all non-function values and execute the functions that are in the array', function() { 169 | var divs = $('div.box:in-viewport') 170 | var temp = 0 171 | var faultyArray = [1, 'test', function() { 172 | return ++temp 173 | }] 174 | divs.should.have.length(2, 'length isn\'t 2') 175 | divs.run(faultyArray) 176 | temp.should.be.exactly(2, 'The only function in faultyArray didn\'t run') // 2 since there are 2 divs 177 | }) 178 | }) 179 | describe('when an array of functions is passed to .do/.run', function() { 180 | it('should execute all of the functions', function() { 181 | var divs = $('div.box:in-viewport') 182 | var temp = 0 183 | var fnArray = [] 184 | var tempFn = function() { 185 | return ++temp 186 | } 187 | for (var i = 0; i < 4; i++) { 188 | fnArray.push(tempFn) 189 | } 190 | divs.should.have.length(2, 'length isn\'t 2') 191 | divs.run(fnArray) 192 | temp.should.be.exactly(8, 'all four functions did not execute') 193 | }) 194 | }) 195 | }) 196 | }) 197 | 198 | describe('div location horizontally in viewport', function() { 199 | describe('when left is greater than viewport width', function() { 200 | it('should return the text from div as "out of viewport"', function() { 201 | removeContainer() 202 | addContainer() 203 | top(0, 0) 204 | left(99999, 0) 205 | div.text().should.be.exactly('out of viewport') 206 | }) 207 | }) 208 | describe('when left is greater than viewport left edge', function() { 209 | it('should return the text from div as "out of viewport"', function() { 210 | left(-99999, 0) 211 | div.text().should.be.exactly('out of viewport') 212 | }) 213 | }) 214 | describe('when left is lesser than viewport width', function() { 215 | it('should return the text from div as "in viewport"', function() { 216 | left(90, 0) 217 | div.text().should.be.exactly('in viewport') 218 | left(0, 0) 219 | }) 220 | }) 221 | }) 222 | }) 223 | 224 | describe('when tolerance is -100', function() { 225 | it('should be window.height - abs(tolerance)', function() { 226 | var winHt = $(window).height() 227 | top(winHt - 100, -100) 228 | div.text().should.be.exactly('in viewport') 229 | }) 230 | }) 231 | 232 | describe('when tolerance is not a number', function() { 233 | it('should return default tolerance to 0', function() { 234 | top(0, 'ads') 235 | left(0, 'ad') 236 | div.text().should.be.exactly('in viewport') 237 | }) 238 | }) 239 | }) 240 | }) 241 | } 242 | 243 | runner(runIsInViewport, 'pseudo-selector') 244 | runner(runIsInViewportVariant, 'exposed isInViewport function') 245 | runner(runIsInViewportWithJqueryNot, 'jquery\'s .not selector') 246 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | isInViewport.js 2 | ================ 3 | [![Build Status](https://travis-ci.org/zeusdeux/isInViewport.svg?branch=master)](https://travis-ci.org/zeusdeux/isInViewport) 4 | [![CDNJS](https://img.shields.io/cdnjs/v/is-in-viewport.svg)](https://cdnjs.com/libraries/is-in-viewport) 5 | 6 | An ultra-light jQuery plugin that tells you if the element is in the viewport, but with a twist. 7 | 8 | Did you say [demo](http://www.isinviewport.mudit.xyz) (inclusive of tests)? 9 | 10 | For a more performant alternative, please take a look at [observe-element-in-viewport](https://github.com/zeusdeux/observe-element-in-viewport) which uses the new `IntersectionObserver` API. Please keep in mind that you might have to ship a [polyfill](https://github.com/w3c/IntersectionObserver/tree/master/polyfill) for `IntersectionObserver` depending on the browsers you support. 11 | 12 | **Note**: If you need this in a React application, please use the [use-is-in-viewport hook](https://github.com/zeusdeux/use-is-in-viewport). 13 | 14 | Installation 15 | ---------------- 16 | #### Using in a module 17 | 18 | ```js 19 | npm install --save is-in-viewport 20 | ``` 21 | You can then `require('is-in-viewport')` or `import 'is-in-viewport'` in your code. 22 | It will automagically work with the bundler of your choice. If it breaks, please feel free to open an issue. 23 | 24 | Example usage in an ES6/ES2015 module is shown [in the `examples/es6-example`](./examples/es6-example/) folder. 25 | 26 | __Note__: `isInViewport` is a side-effecting module. It imports `jquery` that you have installed and attaches itself on it. 27 | As a consequence, `isInViewport` requires `jquery` to be installed as a peer dependency. 28 | Your bundling will fail if `jquery` isn't installed as [`is-in-viewport` `import`s `jquery`](./src/index.js#L1). 29 | 30 | #### Using directly in a script tag 31 | 32 | - Get the release that you want from [releases/tags](https://github.com/zeusdeux/isInViewport/releases) (or `bower install isInViewport` or `npm install --save is-in-viewport`) 33 | - Copy/link either `isInViewport.js` or `isInViewport.min.js` and the respective sourcemap from the `lib` folder to your folder containing your scripts 34 | - Add it after you include `jQuery` 35 | - You're ready to go! 36 | 37 | Usage 38 | ---------------- 39 | 40 | 41 | #### Basic usage 42 | 43 | ```javascript 44 | $( 'selector:in-viewport' ) 45 | ``` 46 | When used as a selector it returns all the elements that match. Since it returns the element(s) it can *thus be chained* with other jQuery methods. It can also be used with jquery's `.is`. 47 | 48 | ###### Example: 49 | ```javascript 50 | $( 'div:in-viewport' ).css( 'background-color', 'red' ); 51 | // same as 52 | var $div = $( 'div' ); 53 | if ( $div.is( ':in-viewport' ) ) { 54 | $div.css( 'background-color', 'red' ); 55 | } 56 | ``` 57 | Both of the above will set the `background-color` as `red` for all `div`s that are in the viewport. 58 | 59 | #### Advanced usage 60 | 61 | ##### Using `in-viewport` pseudo-selector 62 | 63 | ```javascript 64 | $( 'selector:in-viewport( tolerance[, viewport selector] )' ) 65 | ``` 66 | This returns all the elements that are in the viewport while taking into account the `tolerance` criterion. 67 | 68 | Since it returns the element(s) it can *thus be chained* with other jQuery methods. 69 | 70 | When a viewport selector is specified, it uses that to calculate if the element is in *that* viewport or not. 71 | 72 | When a viewport selector is *not* specified, it defaults to *window* as the viewport. 73 | 74 | The viewport selector is any valid jQuery selector. 75 | 76 | ###### Defaults: 77 | - `tolerance` defaults to `0` 78 | - `viewport` defaults to `window` 79 | 80 | ###### Example: 81 | ```javascript 82 | //example 1 83 | //the height of tolerance region is 100px from top of viewport 84 | $( 'div:in-viewport( 100 )' ).css( 'background-color', 'red' ); 85 | 86 | //example 2 87 | //the height of tolerance region is (viewport.height - 100px) from top of viewport 88 | $( 'div:in-viewport( -100 )' ).css( 'background-color', 'green' ); 89 | 90 | //example 3 91 | $('#viewport > div.box:in-viewport( 100, #viewport )').css( 'background-color', 'blue' ) 92 | .text( 'in viewport' ); 93 | ``` 94 | 95 | __Example 1__ will set the `background-color` as `red` for all `divs` that are in the viewport with a `tolerance` of `100px`. 96 | 97 | __Example 2__ will set the `background-color` as `green` for all `divs` that are in the viewport with a `tolerance` of `viewport height - 100px`. This lets the user conveniently provide a `tolerance` value closer to the viewport height without having to call `$(viewport).height()` all the time. 98 | 99 | __Example 3__ will set the `background-color` as `blue` and `text` as `in viewport` for all `divs` that are in the custom viewport given by `#viewport` and with a `tolerance` of `100px`. 100 | 101 | With the advanced usage it becomes very easy to build things like menus with items that get auto-highlighted based on which section you are on, transition effects when an element comes into the viewport, etc. 102 | 103 | See the examples in the `examples` directory for more clarity. 104 | 105 | ###### Note: 106 | - When `tolerance` is `0` or `undefined` it is actually *equal to* `tolerance: $(viewport).height()` and *not* `0`. 107 | 108 | This makes it easier for developers to have the whole `viewport` available to them as a valid `viewport`. 109 | 110 | 111 | ##### Using exposed `isInViewport` function 112 | 113 | ```javascript 114 | $( 'selector' ).isInViewport({ tolerance: tolerance, viewport: viewport }) 115 | ``` 116 | This returns all the elements that are in the viewport while taking into account the `tolerance` criterion. 117 | 118 | Since it returns the element(s) it can *thus be chained* with other jQuery methods. 119 | 120 | When a viewport is specified, it uses that to calculate if the element is in *that* viewport or not. 121 | 122 | When a viewport is *not* specified, it defaults to *window* as the viewport. 123 | 124 | **The viewport is a valid DOM element or jQuery wrapped DOM element, NOT a selector string.** 125 | 126 | ###### Defaults: 127 | - `tolerance` defaults to `0` 128 | - `viewport` defaults to `window` 129 | 130 | ###### Example: 131 | ```javascript 132 | //example 1 133 | //the height of tolerance region is 100px from top of viewport 134 | $( 'div' ).isInViewport({ tolerance: 100 }).css( 'background-color', 'red' ); 135 | 136 | //example 2 137 | //the height of tolerance region is (viewport.height - 100px) from top of viewport 138 | $( 'div' ).isInViewport({ tolerance: -100 }).css( 'background-color', 'green' ); 139 | 140 | //example 3 141 | var $viewport = $('#viewport'); 142 | 143 | $viewport 144 | .find('div.box') 145 | .isInViewport({ tolerance: 100, viewport: $viewport }) 146 | .css( 'background-color', 'blue' ) 147 | .text( 'in viewport' ); 148 | ``` 149 | 150 | 151 | ## Support 152 | __Chrome, Firefox 3.5+, IE9+, Safari 5+, Opera 10.5+__ 153 | 154 | ## Note 155 | - `:in-viewport` selector *does* support chaining. 156 | 157 | Changelog 158 | ---------------- 159 | `3.0.3` 160 | 161 | - Use `jQuery.expr.pseudos` when found since `jQuery.expr[':']` is deprecated 162 | 163 | `3.0.2` 164 | 165 | - Support new rollup properties and get rid of removed rollups properties (`moduleId`, `moduleName`, etc) 166 | 167 | `3.0.1` 168 | 169 | - Fix jQuery no conflict mode issue (#39) 170 | 171 | `3.0.0` 172 | 173 | - Remove the deprecated `$(el).do` method 174 | - Remove support for browsers < { IE9, Safari 5, Opera 10.5, Firefox 3.5 } 175 | - Add support for modules and bundlers. You can now `import 'is-in-viewport'`/`require('is-in-viewport')` in your project (yay!) 176 | - Add properly functioning sourcemaps for easier debugging 177 | 178 | `2.4.2` 179 | 180 | - Remove `postInstall` script which was breaking builds 181 | 182 | `2.4.1` 183 | 184 | - Undo `2.4.0` as `is-in-viewport` already exists on bower and isn't owned by me 185 | 186 | `2.4.0` 187 | 188 | - Update `bower.json` to comply with new validations 189 | - Rename package on bower to match with that on npm i.e., `is-in-viewport` 190 | 191 | `2.3.1` 192 | 193 | - Remove unnecessary boolean coercion 194 | 195 | `2.3.0` 196 | 197 | - Re-exposed `isInViewport` with saner semantics. You can now pass options as JS objects to `isInViewport` and hence can now do things like: 198 | ```javascript 199 | var $viewport = $(); 200 | 201 | $viewport 202 | .find() 203 | .isInViewport({ tolerance: 100, viewport: $viewport }) // <- passing the viewport jQuery object in directly 204 | .css(color: 'red'); 205 | ``` 206 | - Deprecated `do` in favour of `run` 207 | - When available, `isInViewport` now uses `Sizzle.selectors.createPseudo` 208 | 209 | `2.2.5` 210 | 211 | - Updated readme to point to new demo. Mostly a bump for npm to pickup the new readme. 212 | 213 | `2.2.4` 214 | 215 | - Pulled [#15](https://github.com/zeusdeux/isInViewport/pull/15)(fixes horizontal viewport check) 216 | 217 | `2.2.3` 218 | 219 | - Allow use as CommonJS -> [#19](https://github.com/zeusdeux/isInViewport/pull/19) 220 | - Fixed gruntfile. It now generates proper filenames during build. 221 | 222 | `2.2.2` 223 | 224 | - Published to `npm` 225 | - Updated install instructions to include `npm` 226 | 227 | `2.2.1` 228 | 229 | - Pulled in a few bugfixes 230 | - Fixed ie8 bugs 231 | 232 | `2.2.0` 233 | 234 | - Aliased the `.do` method with `.run` since `do` is a reserved word and errors out when used as a property in IE. To be on the safer side, use `.run` to chain any arbitrary function or an array of functions. 235 | 236 | `2.1.0` 237 | 238 | - Added a `.do` method that lets the user chain any arbitrary function or an array of functions. Example: 239 | 240 | ```javascript 241 | //usage 1: pass a function 242 | $( 'div:in-viewport' ) 243 | .do(function(){ 244 | console.log( this ); //will log the current jQuery element object it's being called on 245 | }) 246 | .css( 'background-color', 'red' ); 247 | 248 | //usage 2: pass an array of functions 249 | var fnArray = [ 250 | function(){ console.log("Fn 1: %o", this); }, 251 | function(){ console.log("Fn 2: %o", this); } 252 | //or say another function that maybe adds 253 | //elements to be tracked when in viewport 254 | ]; 255 | $( 'div:in-viewport' ).do(fnArray); 256 | ``` 257 | 258 | `2.0.0` 259 | 260 | - Added support for negative `tolerance` values that are now relative to the `viewport` height 261 | - Added support for custom viewport selector (see [Advanced usage](#advanced-usage)) 262 | - Added support for checking if an element is in viewport both horizontally and vertically. (checks both now) 263 | - Removed support for the old usage syntax in favour of the `:in-viewport` selector i.e., 264 | ```javascript 265 | //removed 266 | $( selector ).isInViewport( {"tolerance" :100, "debug": true} ) 267 | 268 | //current usage 269 | $( 'selector:in-viewport( 100 )' ) 270 | ``` 271 | - Removed the `debug` option because, lets be honest, no one really used it. 272 | - Removed the weird code that handled *end of page* condition in the core. It's the user's 273 | prerogative to do what he/she wants when their page is scrolled to *end of page*. 274 | 275 | `1.1.1` 276 | 277 | - Added `bower` support. 278 | 279 | `1.1.0` 280 | 281 | - Added support for `:in-viewport` selector as per [joeframbach's](http://www.reddit.com/user/joeframbach) suggestion. 282 | -------------------------------------------------------------------------------- /tests/lib/jquery.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v3.1.1 | (c) jQuery Foundation | jquery.org/license */ 2 | !function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.1.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext,B=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,C=/^.[^:#\[\.,]*$/;function D(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):C.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(D(this,a||[],!1))},not:function(a){return this.pushStack(D(this,a||[],!0))},is:function(a){return!!D(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var E,F=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,G=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||E,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:F.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),B.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};G.prototype=r.fn,E=r(d);var H=/^(?:parents|prev(?:Until|All))/,I={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function J(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return J(a,"nextSibling")},prev:function(a){return J(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return a.contentDocument||r.merge([],a.childNodes)}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(I[a]||r.uniqueSort(e),H.test(a)&&e.reverse()),this.pushStack(e)}});var K=/[^\x20\t\r\n\f]+/g;function L(a){var b={};return r.each(a.match(K)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?L(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function M(a){return a}function N(a){throw a}function O(a,b,c){var d;try{a&&r.isFunction(d=a.promise)?d.call(a).done(b).fail(c):a&&r.isFunction(d=a.then)?d.call(a,b,c):b.call(void 0,a)}catch(a){c.call(void 0,a)}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==N&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:M,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:M)),c[2][3].add(g(0,a,r.isFunction(d)?d:N))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(O(a,g.done(h(c)).resolve,g.reject),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)O(e[c],h(c),g.reject);return g.promise()}});var P=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&P.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var Q=r.Deferred();r.fn.ready=function(a){return Q.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,holdReady:function(a){a?r.readyWait++:r.ready(!0)},ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||Q.resolveWith(d,[r]))}}),r.ready.then=Q.then;function R(){d.removeEventListener("DOMContentLoaded",R), 3 | a.removeEventListener("load",R),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",R),a.addEventListener("load",R));var S=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)S(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){W.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=V.get(a,b),c&&(!d||r.isArray(c)?d=V.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return V.get(a,c)||V.access(a,c,{empty:r.Callbacks("once memory").add(function(){V.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,ka=/^$|\/(?:java|ecma)script/i,la={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};la.optgroup=la.option,la.tbody=la.tfoot=la.colgroup=la.caption=la.thead,la.th=la.td;function ma(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&r.nodeName(a,b)?r.merge([a],c):c}function na(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=ma(l.appendChild(f),"script"),j&&na(g),c){k=0;while(f=g[k++])ka.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var qa=d.documentElement,ra=/^key/,sa=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ta=/^([^.]*)(?:\.(.+)|)/;function ua(){return!0}function va(){return!1}function wa(){try{return d.activeElement}catch(a){}}function xa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)xa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=va;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(qa,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(K)||[""],j=b.length;while(j--)h=ta.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.hasData(a)&&V.get(a);if(q&&(i=q.events)){b=(b||"").match(K)||[""],j=b.length;while(j--)if(h=ta.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&V.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(V.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i\x20\t\r\n\f]*)[^>]*)\/>/gi,za=/\s*$/g;function Da(a,b){return r.nodeName(a,"table")&&r.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a:a}function Ea(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Fa(a){var b=Ba.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ga(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(V.hasData(a)&&(f=V.access(a),g=V.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c1&&"string"==typeof q&&!o.checkClone&&Aa.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ia(f,b,c,d)});if(m&&(e=pa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(ma(e,"script"),Ea),i=h.length;l")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=ma(h),f=ma(a),d=0,e=f.length;d0&&na(g,!i&&ma(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(T(c)){if(b=c[V.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[V.expando]=void 0}c[W.expando]&&(c[W.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ja(this,a,!0)},remove:function(a){return Ja(this,a)},text:function(a){return S(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ia(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Da(this,a);b.appendChild(a)}})},prepend:function(){return Ia(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Da(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ia(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ia(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(ma(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return S(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!za.test(a)&&!la[(ja.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c1)}});function Ya(a,b,c,d,e){return new Ya.prototype.init(a,b,c,d,e)}r.Tween=Ya,Ya.prototype={constructor:Ya,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=Ya.propHooks[this.prop];return a&&a.get?a.get(this):Ya.propHooks._default.get(this)},run:function(a){var b,c=Ya.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Ya.propHooks._default.set(this),this}},Ya.prototype.init.prototype=Ya.prototype,Ya.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},Ya.propHooks.scrollTop=Ya.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=Ya.prototype.init,r.fx.step={};var Za,$a,_a=/^(?:toggle|show|hide)$/,ab=/queueHooks$/;function bb(){$a&&(a.requestAnimationFrame(bb),r.fx.tick())}function cb(){return a.setTimeout(function(){Za=void 0}),Za=r.now()}function db(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ba[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function eb(a,b,c){for(var d,e=(hb.tweeners[b]||[]).concat(hb.tweeners["*"]),f=0,g=e.length;f1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?ib:void 0)), 4 | void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&r.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(K);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),ib={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=jb[b]||r.find.attr;jb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=jb[g],jb[g]=e,e=null!=c(a,b,d)?g:null,jb[g]=f),e}});var kb=/^(?:input|select|textarea|button)$/i,lb=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return S(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):kb.test(a.nodeName)||lb.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function mb(a){var b=a.match(K)||[];return b.join(" ")}function nb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,nb(this)))});if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=nb(c),d=1===c.nodeType&&" "+mb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=mb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,nb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=nb(c),d=1===c.nodeType&&" "+mb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=mb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,nb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(K)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=nb(this),b&&V.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":V.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+mb(nb(c))+" ").indexOf(b)>-1)return!0;return!1}});var ob=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":r.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(ob,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:mb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(r.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var pb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!pb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,pb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(V.get(h,"events")||{})[b.type]&&V.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&T(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!T(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=V.access(d,b);e||d.addEventListener(a,c,!0),V.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=V.access(d,b)-1;e?V.access(d,b,e):(d.removeEventListener(a,c,!0),V.remove(d,b))}}});var qb=a.location,rb=r.now(),sb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var tb=/\[\]$/,ub=/\r?\n/g,vb=/^(?:submit|button|image|reset|file)$/i,wb=/^(?:input|select|textarea|keygen)/i;function xb(a,b,c,d){var e;if(r.isArray(b))r.each(b,function(b,e){c||tb.test(a)?d(a,e):xb(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)xb(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(r.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)xb(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&wb.test(this.nodeName)&&!vb.test(a)&&(this.checked||!ia.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:r.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(ub,"\r\n")}}):{name:b.name,value:c.replace(ub,"\r\n")}}).get()}});var yb=/%20/g,zb=/#.*$/,Ab=/([?&])_=[^&]*/,Bb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Cb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Db=/^(?:GET|HEAD)$/,Eb=/^\/\//,Fb={},Gb={},Hb="*/".concat("*"),Ib=d.createElement("a");Ib.href=qb.href;function Jb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(K)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Kb(a,b,c,d){var e={},f=a===Gb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Lb(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Mb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Nb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:qb.href,type:"GET",isLocal:Cb.test(qb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Hb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Lb(Lb(a,r.ajaxSettings),b):Lb(r.ajaxSettings,a)},ajaxPrefilter:Jb(Fb),ajaxTransport:Jb(Gb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Bb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||qb.href)+"").replace(Eb,qb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(K)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Ib.protocol+"//"+Ib.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Kb(Fb,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Db.test(o.type),f=o.url.replace(zb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(yb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(sb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Ab,"$1"),n=(sb.test(f)?"&":"?")+"_="+rb++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Hb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Kb(Gb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Mb(o,y,d)),v=Nb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Ob={0:200,1223:204},Pb=r.ajaxSettings.xhr();o.cors=!!Pb&&"withCredentials"in Pb,o.ajax=Pb=!!Pb,r.ajaxTransport(function(b){var c,d;if(o.cors||Pb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Ob[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("