├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .jscsrc ├── .npmignore ├── .nvmrc ├── Gruntfile.js ├── LICENSE-MIT ├── bower.json ├── demo ├── bbq-fixed.html ├── bbq.html ├── demo.css ├── fixed-fix.html ├── fixed-nojs-fix.html ├── fixed-nojs.html ├── fixed.html ├── hashchange.html ├── index.html ├── jq3.html └── scroll-behavior-smooth.html ├── index.html ├── jquery.smooth-scroll.js ├── jquery.smooth-scroll.min.js ├── lib ├── jquery.ba-bbq.js ├── jquery │ ├── jquery.js │ └── ui-easing.js ├── qunit │ ├── qunit.css │ └── qunit.js └── tmpl │ ├── footer.tpl │ ├── header.tpl │ ├── umdfoot.tpl │ └── umdhead.tpl ├── package.json ├── readme.md ├── src └── jquery.smooth-scroll.js ├── test ├── index.html └── tests.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [lib/jquery/**.js] 11 | indent_style = tab 12 | indent_size = 4 13 | 14 | [lib/qunit/**.js] 15 | indent_style = tab 16 | indent_size = 4 17 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'kswedberg/es5', 3 | rules: { 4 | 'comma-dangle': ['warn', 'never'] 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "requireCurlyBraces": [ 3 | "if", 4 | "else", 5 | "for", 6 | "while", 7 | "do", 8 | "try", 9 | "catch" 10 | ], 11 | "requireSpaceAfterKeywords": [ 12 | "if", 13 | "else", 14 | "for", 15 | "while", 16 | "do", 17 | "switch", 18 | "case", 19 | "return", 20 | "try", 21 | "catch", 22 | "typeof" 23 | ], 24 | "requireSpaceBeforeBlockStatements": true, 25 | "requireParenthesesAroundIIFE": true, 26 | "requireSpacesInConditionalExpression": true, 27 | "disallowSpacesInNamedFunctionExpression": { 28 | "beforeOpeningRoundBrace": true 29 | }, 30 | "disallowSpacesInFunctionDeclaration": { 31 | "beforeOpeningRoundBrace": true 32 | }, 33 | "requireSpaceBetweenArguments": true, 34 | "requireBlocksOnNewline": true, 35 | "disallowEmptyBlocks": true, 36 | "disallowSpacesInsideArrayBrackets": true, 37 | "disallowSpacesInsideParentheses": true, 38 | "disallowDanglingUnderscores": true, 39 | "requireCommaBeforeLineBreak": true, 40 | "disallowSpacesInCallExpression": true, 41 | "disallowSpaceAfterPrefixUnaryOperators": true, 42 | "disallowSpaceBeforePostfixUnaryOperators": true, 43 | "disallowSpaceBeforeBinaryOperators": [ 44 | "," 45 | ], 46 | "requireSpacesInForStatement": true, 47 | "requireSpaceBeforeBinaryOperators": true, 48 | "requireSpaceAfterBinaryOperators": true, 49 | "disallowKeywords": [ 50 | "with" 51 | ], 52 | "disallowMixedSpacesAndTabs": true, 53 | "disallowTrailingWhitespace": true, 54 | "disallowKeywordsOnNewLine": [ 55 | "else" 56 | ], 57 | "requireLineFeedAtFileEnd": true, 58 | "requireCapitalizedConstructors": true, 59 | "requireDotNotation": true, 60 | "disallowNewlineBeforeBlockStatements": true, 61 | "disallowMultipleLineStrings": true, 62 | "requireSpaceBeforeObjectValues": true, 63 | "validateQuoteMarks": "'", 64 | "requireSpaceAfterLineComment": true, 65 | "validateIndentation": 2, 66 | "validateLineBreaks": "LF", 67 | "disallowSpacesInFunction": { 68 | "beforeOpeningRoundBrace": true 69 | }, 70 | "requireSpacesInFunction": { 71 | "beforeOpeningCurlyBrace": true 72 | }, 73 | "disallowMultipleLineBreaks": true, 74 | "disallowYodaConditions": true, 75 | "disallowFunctionDeclarations": true, 76 | "disallowMultipleVarDecl": "exceptUndefined", 77 | "requirePaddingNewlinesBeforeKeywords": [ 78 | "do", 79 | "for", 80 | "if", 81 | "switch", 82 | "try", 83 | "void", 84 | "while", 85 | "return" 86 | ], 87 | "excludeFiles": ["**/node_modules/**", "**/min/**", "**/*.min.js"] 88 | } 89 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | demo 2 | node_modules 3 | lib 4 | bower.json 5 | smooth-scroll.jquery.json 6 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | var pkg = grunt.file.readJSON('package.json'); 3 | var marked = require('marked'); 4 | var hl = require('node-syntaxhighlighter'); 5 | 6 | marked.setOptions({ 7 | highlight: function(code, lang) { 8 | var language = hl.getLanguage(lang || 'javascript'); 9 | 10 | return hl.highlight(code, language); 11 | }, 12 | gfm: true 13 | }); 14 | 15 | // Project configuration. 16 | grunt.initConfig({ 17 | pluginName: 'smooth-scroll', 18 | pkg: pkg, 19 | meta: { 20 | banner: '/*!<%= "\\n" %>' + 21 | ' * <%= pkg.title %> - v<%= pkg.version %> - ' + 22 | '<%= grunt.template.today("yyyy-mm-dd") + "\\n" %>' + 23 | '<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' + 24 | ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>' + 25 | '<%= "\\n" %>' + 26 | ' * Licensed <%= pkg.license %>' + 27 | '<%= "\\n" %>' + ' */' + 28 | '<%= "\\n\\n" %>' 29 | }, 30 | concat: { 31 | all: { 32 | src: ['src/jquery.<%= pluginName %>.js'], 33 | dest: 'jquery.<%= pluginName %>.js' 34 | }, 35 | options: { 36 | stripBanners: true, 37 | banner: '<%= meta.banner %>', 38 | process: function(src) { 39 | var umdHead = grunt.file.read('lib/tmpl/umdhead.tpl'); 40 | var umdFoot = grunt.file.read('lib/tmpl/umdfoot.tpl'); 41 | 42 | var ret = src 43 | .replace('(function($) {', umdHead) 44 | .replace('})(jQuery);', umdFoot); 45 | 46 | return ret; 47 | } 48 | } 49 | }, 50 | uglify: { 51 | all: { 52 | files: { 53 | 'jquery.<%= pluginName %>.min.js': ['<%= concat.all.dest %>'] 54 | }, 55 | options: { 56 | banner: '<%= meta.banner %>' 57 | // preserveComments: /\/\*[\s\S]*/ 58 | } 59 | } 60 | }, 61 | watch: { 62 | scripts: { 63 | files: '<%= jshint.all %>', 64 | tasks: ['jshint:all'] 65 | }, 66 | docs: { 67 | files: ['readme.md', 'lib/tmpl/**/*.html'], 68 | tasks: ['docs'] 69 | } 70 | 71 | }, 72 | jshint: { 73 | all: ['Gruntfile.js', 'src/**/*.js'], 74 | options: { 75 | curly: true, 76 | devel: true, 77 | eqeqeq: true, 78 | unused: true, 79 | immed: true, 80 | latedef: true, 81 | newcap: true, 82 | noarg: true, 83 | sub: true, 84 | undef: true, 85 | boss: true, 86 | eqnull: true, 87 | browser: true, 88 | globals: { 89 | jQuery: true, 90 | require: false 91 | } 92 | } 93 | }, 94 | eslint: { 95 | target: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'], 96 | options: { 97 | fix: true 98 | // configFile: '.eslintrc.js', 99 | } 100 | }, 101 | version: { 102 | src: { 103 | src: ['src/jquery.<%= pluginName %>.js'] 104 | }, 105 | banners: { 106 | pkg: pkg, 107 | src: [ 108 | 'jquery.<%= pluginName %>.js', 109 | 'jquery.<%= pluginName %>.min.js' 110 | ], 111 | options: { 112 | prefix: '- v' 113 | } 114 | }, 115 | package: { 116 | src: ['package.json'] 117 | } 118 | } 119 | }); 120 | 121 | grunt.registerTask('docs', 'Convert readme.md to html and concat with header and footer for index.html', function() { 122 | var readme = grunt.file.read('readme.md'); 123 | var head = grunt.template.process(grunt.file.read('lib/tmpl/header.tpl')); 124 | var foot = grunt.file.read('lib/tmpl/footer.tpl'); 125 | var doc = marked(readme); 126 | 127 | grunt.file.write('index.html', head + doc + foot); 128 | }); 129 | 130 | grunt.registerTask('updateBower', 'Update bower.json to match package.json', function() { 131 | var pkg = require('./package.json'); 132 | var props = ['name', 'main', 'homepage', 'version', 'repository', 'dependencies', 'keywords', 'license']; 133 | var json = { 134 | description: 'Easy implementation of smooth scrolling for same-page links' 135 | }; 136 | 137 | props.forEach(function(item) { 138 | if (pkg[item]) { 139 | json[item] = pkg[item]; 140 | } 141 | }); 142 | 143 | json.authors = [pkg.author]; 144 | json.moduleType = ['amd', 'node']; 145 | json.ignore = ['demo/', 'lib/', 'src/', 'test/', '**/.*', 'Gruntfile.js', 'package.json']; 146 | 147 | grunt.file.write('bower.json', JSON.stringify(json, null, 2)); 148 | }); 149 | 150 | grunt.registerTask('lint', ['eslint']); 151 | grunt.registerTask('build', ['lint', 'concat', 'version', 'updateBower', 'uglify', 'docs']); 152 | grunt.registerTask('default', ['build']); 153 | 154 | ['patch', 'minor', 'major'].forEach(function(release) { 155 | grunt.registerTask(release, ['lint', 'version:src:' + release, 'concat', 'uglify', 'version:banners:' + release, 'version:package:' + release, 'updateBower']); 156 | }); 157 | 158 | grunt.loadNpmTasks('grunt-eslint'); 159 | grunt.loadNpmTasks('grunt-contrib-jshint'); 160 | grunt.loadNpmTasks('grunt-contrib-uglify'); 161 | grunt.loadNpmTasks('grunt-contrib-concat'); 162 | grunt.loadNpmTasks('grunt-contrib-watch'); 163 | grunt.loadNpmTasks('grunt-version'); 164 | }; 165 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person 2 | obtaining a copy of this software and associated documentation 3 | files (the "Software"), to deal in the Software without 4 | restriction, including without limitation the rights to use, 5 | copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the 7 | Software is furnished to do so, subject to the following 8 | conditions: 9 | 10 | The above copyright notice and this permission notice shall be 11 | included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 16 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 | OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Easy implementation of smooth scrolling for same-page links", 3 | "name": "jquery-smooth-scroll", 4 | "main": "jquery.smooth-scroll.js", 5 | "homepage": "https://github.com/kswedberg/jquery-smooth-scroll", 6 | "version": "2.2.0", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/kswedberg/jquery-smooth-scroll" 10 | }, 11 | "dependencies": { 12 | "jquery": ">=1.7.0" 13 | }, 14 | "keywords": [ 15 | "jQuery", 16 | "jquery-plugin", 17 | "scroll", 18 | "animation" 19 | ], 20 | "license": "MIT", 21 | "authors": [ 22 | { 23 | "name": "Karl Swedberg", 24 | "email": "kswedberg@gmail.com", 25 | "url": "https://karlswedberg.com/" 26 | } 27 | ], 28 | "moduleType": [ 29 | "amd", 30 | "node" 31 | ], 32 | "ignore": [ 33 | "demo/", 34 | "lib/", 35 | "src/", 36 | "test/", 37 | "**/.*", 38 | "Gruntfile.js", 39 | "package.json" 40 | ] 41 | } -------------------------------------------------------------------------------- /demo/bbq-fixed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Smooth Scroll jQuery Plugin Demo 6 | 23 | 24 | 25 |

Smooth Scroll jQuery Plugin with Back Button Support

26 |
27 | 36 |

p1 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

37 |

p2 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

38 | 39 |

p3 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

40 | 41 |

p4 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

42 | 43 |

p5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

44 | 45 |

p6 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

46 | 47 | 48 |
49 | 50 | 51 | 52 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /demo/bbq.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Smooth Scroll jQuery Plugin Demo - BBQ 7 | 8 | 9 | 10 | 11 |
12 | 13 |

Smooth Scroll jQuery Plugin with Back Button Support

14 |
15 | 26 |

p1 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

27 |

p2 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

28 | back to nav 29 |

p3 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

30 | back to nav 31 |

p4 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

32 | back to nav 33 |

p5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

34 | back to nav 35 |

p6 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

36 | back to nav 37 | 38 |
39 |
40 | 41 | 42 | 46 | 47 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /demo/demo.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Helvetica, Arial, sans-serif; 3 | color: #353536; 4 | line-height: 1.4; 5 | } 6 | h1 { 7 | margin-top: 0; 8 | text-align: center; 9 | font-size: 1.6em; 10 | } 11 | ul { 12 | padding-left: 1em; 13 | } 14 | .relative-scrollers { 15 | position: fixed; 16 | padding: 10px; 17 | top: 0; 18 | left: 0; 19 | box-shadow: 3px 3px 3px rgba(0, 0, 0, .2); 20 | background-color: #fff; 21 | background-color: rgba(255, 255, 255, 0.8); 22 | } 23 | .relative-scrollers > div { 24 | margin-bottom: 1em; 25 | } 26 | a { 27 | color: #0069d2; 28 | } 29 | button { 30 | background-color: #3399ff; 31 | color: #fff; 32 | border-width: 0; 33 | padding: 12px; 34 | width: 100%; 35 | } 36 | .container { 37 | margin: 0 auto 60px; 38 | max-width: 1100px; 39 | } 40 | .intro { 41 | margin: 0 140px; 42 | } 43 | .demo-column { 44 | margin: 0 auto 40px; 45 | width: 280px; 46 | padding: 0 140px; 47 | } 48 | .scrollme-wrapper { 49 | padding: 10px; 50 | background-color: #e3e3e3; 51 | } 52 | .scrollme { 53 | height: 100px; 54 | width: 180px; 55 | overflow: auto; 56 | padding-left: 8px; 57 | border: 1px solid #999; 58 | background-color: #fff; 59 | } 60 | .scrollme-x { 61 | width: 400px; 62 | } 63 | .scrollme-x div, 64 | .scrollme-x p { 65 | float: left; 66 | width: 180px; 67 | } 68 | @media (max-width: 560px) { 69 | .relative-scrollers { 70 | box-sizing: border-box; 71 | width: 100%; 72 | } 73 | .relative-scrollers > div { 74 | width: 49%; 75 | display: inline-block; 76 | } 77 | 78 | .container { 79 | margin-top: 150px; 80 | } 81 | 82 | .intro, 83 | .demo-column { 84 | margin-left: 0; 85 | margin-right: 0; 86 | padding-left: 10px; 87 | padding-right: 10px; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /demo/fixed-fix.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Smooth Scroll jQuery Plugin Demo 6 | 24 | 25 | 26 | 27 |
28 | 29 | 36 | 37 |

Stupid hack to fix mobile webkit bug

38 | 39 |
40 |   $(document).ready(function() {
41 | 
42 |     var $stupid = $('<div></div>')
43 |       .height(1)
44 |       .hide()
45 |       .appendTo('body');
46 | 
47 |     var mobileHack = function() {
48 |       $stupid.show();
49 |       setTimeout(function() {
50 |         $stupid.hide();
51 |       }, 10);
52 |     };
53 | 
54 |     $('ul.mainnav a').smoothScroll({
55 |       afterScroll: mobileHack
56 |     });
57 | 
58 |   });
59 | 
60 | 
61 | 62 |

p1 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

63 |

p2 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

64 |

p3 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

65 |

p4 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

66 |

p5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

67 |

p6 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

68 | 69 |
70 | 71 | 72 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /demo/fixed-nojs-fix.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mobile Webkit position:fixed Demo 6 | 29 | 30 | 31 | 32 |
33 | 34 | 42 | 43 |

In Mobile Safari (iPad/iPhone):

44 |
    45 |
  1. Click one of the navigation links to the left. *Works*
  2. 46 |
  3. Click another. *Does NOT Work*
  4. 47 |
  5. Scroll the page a little manually by touching and dragging.
  6. 48 |
  7. Click one of the navigation links to the left. *Works*
  8. 49 |
  9. Click another. *Does NOT Work*
  10. 50 |
51 | 52 | 53 |

Stupid Hack Demo:

54 |
    55 |
  1. 56 |
  2. Repeat steps 1 and 2. They should both work.
  3. 57 |
  4. Groan when you see the hack.
  5. 58 |
59 | 60 |
 61 | $(document).ready(function() {
 62 |   $('button').one('click', function() {
 63 | 
 64 |     // Start stupid hack
 65 |     var $stupid = $('<div></div>')
 66 |       .height(1)
 67 |       .hide()
 68 |       .appendTo('body');
 69 | 
 70 |     $('ul.mainnav').on('click', 'a', function() {
 71 |       $stupid.show();
 72 |       setTimeout(function() {
 73 |         $stupid.hide();
 74 |       }, 10);
 75 |     });
 76 |     // end stupid hack
 77 | 
 78 |   });
 79 | });
 80 | 
 81 |     
82 | 83 |
84 | 85 |

p1 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

86 |

p2 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

87 |

p3 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

88 |

p4 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

89 |

p5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

90 |

p6 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

91 | 92 | 93 |
94 | 95 | 96 | 97 | 98 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /demo/fixed-nojs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Smooth Scroll jQuery Plugin Demo 6 | 27 | 28 | 29 | 30 |
31 | 32 | 40 | 41 |

In Mobile Safari (iPad/iPhone):

42 |
    43 |
  1. Click one of the navigation links to the left. *Works*
  2. 44 |
  3. Click another. *Does NOT Work*
  4. 45 |
  5. Scroll the page a little manually by touching and dragging.
  6. 46 |
  7. Click one of the navigation links to the left. *Works*
  8. 47 |
  9. Click another. *Does NOT Work*
  10. 48 |
49 | 50 |

Questions:

51 | 57 | 58 |
59 | 60 |

p1 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

61 |

p2 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

62 |

p3 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

63 |

p4 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

64 |

p5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

65 |

p6 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

66 | 67 | 68 |
69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /demo/fixed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Smooth Scroll jQuery Plugin Demo 6 | 38 | 39 | 40 | 41 |
42 | 43 | 51 |

Or, try it with hashchange support

52 | 53 | 54 | 55 |
56 |
57 |

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

59 |
60 | You found me by scrolling horizontally. nice job! 61 |
62 |
63 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 64 |

65 |

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

67 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 68 |

69 |
70 |

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

72 |
73 | You scrolled horizontally and vertically. Awesome! 74 |
75 |
76 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 77 |

78 |

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

80 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 81 |

82 |
83 | 84 |

p1 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

85 |

p2 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

86 |

p3 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

87 |

p4 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

88 |

p5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

89 |

p6 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

90 | 91 | 92 |
93 | 94 | 95 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /demo/hashchange.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Smooth Scroll jQuery Plugin Demo - hashchange 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |

Smooth Scroll jQuery Plugin with Back Button Support

15 |
16 |

Uses native hashchange DOM event

17 | 28 |

p1 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

29 |

p2 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

30 | back to nav 31 |

p3 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

32 | back to nav 33 |

p4 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

34 | back to nav 35 |

p5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

36 | back to nav 37 |

p6 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

38 | back to nav 39 | 40 |
41 |
42 | 43 | 44 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Smooth Scroll jQuery Plugin Demo 6 | 7 | 8 | 9 | 10 | 73 | 74 | 75 | 76 |
77 |
78 | 79 |
80 |
81 | 82 |
83 |
84 | 85 |
86 |
87 | 88 |
89 |
90 |
91 |
92 |

jQuery smoothScroll Demo

93 |

View GitHub Repo

94 |

Try it with jQuery BBQ hashchange support or native hashchange support (IE9+)

95 |

Scroll the Document to one of the following paragraphs:

96 |
97 | 98 |
99 | 108 |

Toggle scrolling speed for the p1 link

109 | 110 |
111 |

Scrollable div

112 |
113 |
114 |

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

116 |
117 | You found me by scrolling horizontally. nice job! 118 |
119 |
120 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 121 |

122 |

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

124 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 125 |

126 |
127 |

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

129 |
130 | You scrolled horizontally and vertically. Awesome! 131 |
132 |
133 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 134 |

135 |

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

137 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 138 |

139 |
140 | 141 |

142 |

143 |
144 |

p1 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

145 |

p2 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

146 |

p3 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

147 |

p4 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

148 |

p5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

149 |

p6 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

150 | 151 |
152 |
153 | 154 | 155 | -------------------------------------------------------------------------------- /demo/jq3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Smooth Scroll jQuery Plugin Demo 6 | 30 | 31 | 32 | 33 | 34 | 35 | 83 | 84 | 85 |
86 |

Scroll the Document to one of the following paragraphs:

87 | 96 |

Try it with jQuery BBQ hashchange support

97 |

Or, native hashchange support (IE9+)

98 |

Toggle scrolling speed for the p1 link

99 | 100 | 101 | 102 |
103 |
104 |

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

106 |
107 | You found me by scrolling horizontally. nice job! 108 |
109 |
110 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 111 |

112 |

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

114 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 115 |

116 |
117 |

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

119 |
120 | You scrolled horizontally and vertically. Awesome! 121 |
122 |
123 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 124 |

125 |

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

127 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 128 |

129 |
130 | 131 |

p1 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

132 |

p2 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

133 |

p3 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

134 |

p4 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

135 |

p5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

136 |

p6 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

137 | 138 | 139 |
140 | 141 | 142 | -------------------------------------------------------------------------------- /demo/scroll-behavior-smooth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Smooth Scroll jQuery Plugin Demo 6 | 33 | 34 | 35 | 36 | 78 | 79 | 80 |
81 |

Scroll the Document to one of the following paragraphs:

82 | 90 |

Or, try it with hashchange support

91 |

Toggle scrolling speed for the p1 link

92 | 93 | 94 | 95 |
96 |
97 |

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

99 |
100 | You found me by scrolling horizontally. nice job! 101 |
102 |
103 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 104 |

105 |

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

107 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 108 |

109 |
110 |

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

112 |
113 | You scrolled horizontally and vertically. Awesome! 114 |
115 |
116 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 117 |

118 |

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

120 |

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 121 |

122 |
123 | 124 |

p1 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

125 |

p2 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

126 |

p3 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

127 |

p4 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

128 |

p5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

129 |

p6 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

130 | 131 | 132 |
133 | 134 | 135 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | jQuery Smooth Scroll Plugin 7 | 71 | 72 | 73 | 74 |
Demo
75 |

Smooth Scroll Plugin

76 |

Allows for easy implementation of smooth scrolling for same-page links.

77 |

NPM

78 |

Note: Version 2.0+ of this plugin requires jQuery version 1.7 or greater.

79 |

Download

80 |

Using npm:

81 |
1
npm install jquery-smooth-scroll
82 |
83 |

The old-fashioned way:

84 |

Go to the following URL in your browser and copy/paste the code into your own file: 85 | https://raw.githubusercontent.com/kswedberg/jquery-smooth-scroll/master/jquery.smooth-scroll.js

86 |

Demo

87 |

You can try a bare-bones demo at kswedberg.github.io/jquery-smooth-scroll/demo/

88 |

Features

89 |

$.fn.smoothScroll

90 | 100 |

Options

101 |

The following options, shown with their default values, are available for both $.fn.smoothScroll and $.smoothScroll:

102 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
  offset: 0,
 
  // one of 'top' or 'left'
  direction: 'top',
 
  // only use if you want to override default behavior or if using $.smoothScroll
  scrollTarget: null,
 
  // automatically focus the target element after scrolling to it
  autoFocus: false,
 
  // string to use as selector for event delegation
  delegateSelector: null,
 
  // fn(opts) function to be called before scrolling occurs.
  // `this` is the element(s) being scrolled
  beforeScroll: function() {},
 
  // fn(opts) function to be called after scrolling occurs.
  // `this` is the triggering element
  afterScroll: function() {},
 
  // easing name. jQuery comes with "swing" and "linear." For others, you'll need an easing plugin
  // from jQuery UI or elsewhere
  easing: 'swing',
 
  // speed can be a number or 'auto'
  // if 'auto', the speed will be calculated based on the formula:
  // (current scroll position - target scroll position) / autoCoefficient
  speed: 400,
 
  // autoCoefficent: Only used when speed set to "auto".
  // The higher this number, the faster the scroll speed
  autoCoefficient: 2,
 
  // $.fn.smoothScroll only: whether to prevent the default click action
  preventDefault: true
 
}
103 |
104 |

The options object for $.fn.smoothScroll can take two additional properties: 105 | exclude and excludeWithin. The value for both of these is an array of 106 | selectors, DOM elements or jQuery objects. Default value for both is an 107 | empty array.

108 |

Setting options after initial call

109 |

If you need to change any of the options after you've already called .smoothScroll(), 110 | you can do so by passing the "options" string as the first argument and an 111 | options object as the second.

112 |

$.smoothScroll

113 | 131 |

Additional Option

132 |

The following option, in addition to those listed for $.fn.smoothScroll above, is available 133 | for $.smoothScroll:

134 |
1
2
3
4
5
{
  // The jQuery set of elements you wish to scroll.
  //  if null (default), $('html, body').firstScrollable() is used.
  scrollElement: null
}
135 |
136 |

Note:

137 |

If you use $.smoothScroll, do NOT use the body element (document.body or $('body')) alone for the scrollElement option. Probably not a good idea to use document.documentElement ($('html')) by itself either.

138 |

$.fn.scrollable

139 | 146 |

$.fn.firstScrollable

147 | 157 |

Examples

158 |

Scroll down one "page" at a time (v2.1+)

159 |

With smoothScroll version 2.1 and later, you can use the "relative string" syntax to scroll an element or the document a certain number of pixels relative to its current position. The following code will scroll the document down one page at a time when the user clicks the ".pagedown" button:

160 |
1
2
3
$('button.pagedown').on('click', function() {
  $.smoothScroll('+=' + $(window).height());
});
161 |
162 |

Smooth scrolling on page load

163 |

If you want to scroll to an element when the page loads, use $.smoothScroll() in a script at the end of the body or use $(document).ready(). To prevent the browser from automatically scrolling to the element on its own, your link on page 1 will need to include a fragment identifier that does not match an element id on page 2. To ensure that users without JavaScript get to the same element, you should modify the link's hash on page 1 with JavaScript. Your script on page 2 will then modify it back to the correct one when you call $.smoothScroll().

164 |

For example, let's say you want to smooth scroll to <div id="scrolltome"></div> on page-2.html. For page-1.html, your script might do the following:

165 |
1
2
3
4
5
$('a[href="page-2.html#scrolltome"]').attr('href', function() {
  var hrefParts = this.href.split(/#/);
  hrefParts[1] = 'smoothScroll' + hrefParts[1];
  return hrefParts.join('#');
});
166 |
167 |

Then for page-2.html, your script would do this:

168 |
1
2
3
4
5
6
7
8
// Call $.smoothScroll if location.hash starts with "#smoothScroll"
var reSmooth = /^#smoothScroll/;
var id;
if (reSmooth.test(location.hash)) {
  // Strip the "#smoothScroll" part off (and put "#" back on the beginning)
  id = '#' + location.hash.replace(reSmooth, '');
  $.smoothScroll({scrollTarget: id});
}
169 |
170 |

Focus element after scrolling to it.

171 |

Imagine you have a link to a form somewhere on the same page. When the user clicks the link, you want the user to be able to begin interacting with that form.

172 | 182 |
1
2
3
4
5
$('a.example').smoothScroll({
  afterScroll: function(options) {
    $(options.scrollTarget).find('input')[0].focus();
  }
});
183 |
184 |

For accessibility reasons, it might make sense to focus any element you scroll to, even if it's not a natively focusable element. To do so, you could add a tabIndex attribute to the target element (this, again, is for versions prior to 2.2):

185 |
1
2
3
4
5
6
7
8
9
10
11
$('div.example').smoothScroll({
  afterScroll: function(options) {
    var $tgt = $(options.scrollTarget);
    $tgt[0].focus();
 
    if (!$tgt.is(document.activeElement)) {
      $tgt.attr('tabIndex', '-1');
      $tgt[0].focus();
    }
  }
});
186 |
187 |

Notes

188 | 202 |

Contributing

203 |

Thank you! Please consider the following when working on this repo before you submit a pull request:

204 | 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /jquery.smooth-scroll.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Smooth Scroll - v2.2.0 - 2017-05-05 3 | * https://github.com/kswedberg/jquery-smooth-scroll 4 | * Copyright (c) 2017 Karl Swedberg 5 | * Licensed MIT 6 | */ 7 | 8 | (function(factory) { 9 | if (typeof define === 'function' && define.amd) { 10 | // AMD. Register as an anonymous module. 11 | define(['jquery'], factory); 12 | } else if (typeof module === 'object' && module.exports) { 13 | // CommonJS 14 | factory(require('jquery')); 15 | } else { 16 | // Browser globals 17 | factory(jQuery); 18 | } 19 | }(function($) { 20 | 21 | var version = '2.2.0'; 22 | var optionOverrides = {}; 23 | var defaults = { 24 | exclude: [], 25 | excludeWithin: [], 26 | offset: 0, 27 | 28 | // one of 'top' or 'left' 29 | direction: 'top', 30 | 31 | // if set, bind click events through delegation 32 | // supported since jQuery 1.4.2 33 | delegateSelector: null, 34 | 35 | // jQuery set of elements you wish to scroll (for $.smoothScroll). 36 | // if null (default), $('html, body').firstScrollable() is used. 37 | scrollElement: null, 38 | 39 | // only use if you want to override default behavior 40 | scrollTarget: null, 41 | 42 | // automatically focus the target element after scrolling to it 43 | autoFocus: false, 44 | 45 | // fn(opts) function to be called before scrolling occurs. 46 | // `this` is the element(s) being scrolled 47 | beforeScroll: function() {}, 48 | 49 | // fn(opts) function to be called after scrolling occurs. 50 | // `this` is the triggering element 51 | afterScroll: function() {}, 52 | 53 | // easing name. jQuery comes with "swing" and "linear." For others, you'll need an easing plugin 54 | // from jQuery UI or elsewhere 55 | easing: 'swing', 56 | 57 | // speed can be a number or 'auto' 58 | // if 'auto', the speed will be calculated based on the formula: 59 | // (current scroll position - target scroll position) / autoCoeffic 60 | speed: 400, 61 | 62 | // coefficient for "auto" speed 63 | autoCoefficient: 2, 64 | 65 | // $.fn.smoothScroll only: whether to prevent the default click action 66 | preventDefault: true 67 | }; 68 | 69 | var getScrollable = function(opts) { 70 | var scrollable = []; 71 | var scrolled = false; 72 | var dir = opts.dir && opts.dir === 'left' ? 'scrollLeft' : 'scrollTop'; 73 | 74 | this.each(function() { 75 | var el = $(this); 76 | 77 | if (this === document || this === window) { 78 | return; 79 | } 80 | 81 | if (document.scrollingElement && (this === document.documentElement || this === document.body)) { 82 | scrollable.push(document.scrollingElement); 83 | 84 | return false; 85 | } 86 | 87 | if (el[dir]() > 0) { 88 | scrollable.push(this); 89 | } else { 90 | // if scroll(Top|Left) === 0, nudge the element 1px and see if it moves 91 | el[dir](1); 92 | scrolled = el[dir]() > 0; 93 | 94 | if (scrolled) { 95 | scrollable.push(this); 96 | } 97 | // then put it back, of course 98 | el[dir](0); 99 | } 100 | }); 101 | 102 | if (!scrollable.length) { 103 | this.each(function() { 104 | // If no scrollable elements and has scroll-behavior:smooth because 105 | // "When this property is specified on the root element, it applies to the viewport instead." 106 | // and "The scroll-behavior property of the … body element is *not* propagated to the viewport." 107 | // → https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior 108 | if (this === document.documentElement && $(this).css('scrollBehavior') === 'smooth') { 109 | scrollable = [this]; 110 | } 111 | 112 | // If still no scrollable elements, fall back to , 113 | // if it's in the jQuery collection 114 | // (doing this because Safari sets scrollTop async, 115 | // so can't set it to 1 and immediately get the value.) 116 | if (!scrollable.length && this.nodeName === 'BODY') { 117 | scrollable = [this]; 118 | } 119 | }); 120 | } 121 | 122 | // Use the first scrollable element if we're calling firstScrollable() 123 | if (opts.el === 'first' && scrollable.length > 1) { 124 | scrollable = [scrollable[0]]; 125 | } 126 | 127 | return scrollable; 128 | }; 129 | 130 | var rRelative = /^([\-\+]=)(\d+)/; 131 | 132 | $.fn.extend({ 133 | scrollable: function(dir) { 134 | var scrl = getScrollable.call(this, {dir: dir}); 135 | 136 | return this.pushStack(scrl); 137 | }, 138 | firstScrollable: function(dir) { 139 | var scrl = getScrollable.call(this, {el: 'first', dir: dir}); 140 | 141 | return this.pushStack(scrl); 142 | }, 143 | 144 | smoothScroll: function(options, extra) { 145 | options = options || {}; 146 | 147 | if (options === 'options') { 148 | if (!extra) { 149 | return this.first().data('ssOpts'); 150 | } 151 | 152 | return this.each(function() { 153 | var $this = $(this); 154 | var opts = $.extend($this.data('ssOpts') || {}, extra); 155 | 156 | $(this).data('ssOpts', opts); 157 | }); 158 | } 159 | 160 | var opts = $.extend({}, $.fn.smoothScroll.defaults, options); 161 | 162 | var clickHandler = function(event) { 163 | var escapeSelector = function(str) { 164 | return str.replace(/(:|\.|\/)/g, '\\$1'); 165 | }; 166 | 167 | var link = this; 168 | var $link = $(this); 169 | var thisOpts = $.extend({}, opts, $link.data('ssOpts') || {}); 170 | var exclude = opts.exclude; 171 | var excludeWithin = thisOpts.excludeWithin; 172 | var elCounter = 0; 173 | var ewlCounter = 0; 174 | var include = true; 175 | var clickOpts = {}; 176 | var locationPath = $.smoothScroll.filterPath(location.pathname); 177 | var linkPath = $.smoothScroll.filterPath(link.pathname); 178 | var hostMatch = location.hostname === link.hostname || !link.hostname; 179 | var pathMatch = thisOpts.scrollTarget || (linkPath === locationPath); 180 | var thisHash = escapeSelector(link.hash); 181 | 182 | if (thisHash && !$(thisHash).length) { 183 | include = false; 184 | } 185 | 186 | if (!thisOpts.scrollTarget && (!hostMatch || !pathMatch || !thisHash)) { 187 | include = false; 188 | } else { 189 | while (include && elCounter < exclude.length) { 190 | if ($link.is(escapeSelector(exclude[elCounter++]))) { 191 | include = false; 192 | } 193 | } 194 | 195 | while (include && ewlCounter < excludeWithin.length) { 196 | if ($link.closest(excludeWithin[ewlCounter++]).length) { 197 | include = false; 198 | } 199 | } 200 | } 201 | 202 | if (include) { 203 | if (thisOpts.preventDefault) { 204 | event.preventDefault(); 205 | } 206 | 207 | $.extend(clickOpts, thisOpts, { 208 | scrollTarget: thisOpts.scrollTarget || thisHash, 209 | link: link 210 | }); 211 | 212 | $.smoothScroll(clickOpts); 213 | } 214 | }; 215 | 216 | if (options.delegateSelector !== null) { 217 | this 218 | .off('click.smoothscroll', options.delegateSelector) 219 | .on('click.smoothscroll', options.delegateSelector, clickHandler); 220 | } else { 221 | this 222 | .off('click.smoothscroll') 223 | .on('click.smoothscroll', clickHandler); 224 | } 225 | 226 | return this; 227 | } 228 | }); 229 | 230 | var getExplicitOffset = function(val) { 231 | var explicit = {relative: ''}; 232 | var parts = typeof val === 'string' && rRelative.exec(val); 233 | 234 | if (typeof val === 'number') { 235 | explicit.px = val; 236 | } else if (parts) { 237 | explicit.relative = parts[1]; 238 | explicit.px = parseFloat(parts[2]) || 0; 239 | } 240 | 241 | return explicit; 242 | }; 243 | 244 | var onAfterScroll = function(opts) { 245 | var $tgt = $(opts.scrollTarget); 246 | 247 | if (opts.autoFocus && $tgt.length) { 248 | $tgt[0].focus(); 249 | 250 | if (!$tgt.is(document.activeElement)) { 251 | $tgt.prop({tabIndex: -1}); 252 | $tgt[0].focus(); 253 | } 254 | } 255 | 256 | opts.afterScroll.call(opts.link, opts); 257 | }; 258 | 259 | $.smoothScroll = function(options, px) { 260 | if (options === 'options' && typeof px === 'object') { 261 | return $.extend(optionOverrides, px); 262 | } 263 | var opts, $scroller, speed, delta; 264 | var explicitOffset = getExplicitOffset(options); 265 | var scrollTargetOffset = {}; 266 | var scrollerOffset = 0; 267 | var offPos = 'offset'; 268 | var scrollDir = 'scrollTop'; 269 | var aniProps = {}; 270 | var aniOpts = {}; 271 | 272 | if (explicitOffset.px) { 273 | opts = $.extend({link: null}, $.fn.smoothScroll.defaults, optionOverrides); 274 | } else { 275 | opts = $.extend({link: null}, $.fn.smoothScroll.defaults, options || {}, optionOverrides); 276 | 277 | if (opts.scrollElement) { 278 | offPos = 'position'; 279 | 280 | if (opts.scrollElement.css('position') === 'static') { 281 | opts.scrollElement.css('position', 'relative'); 282 | } 283 | } 284 | 285 | if (px) { 286 | explicitOffset = getExplicitOffset(px); 287 | } 288 | } 289 | 290 | scrollDir = opts.direction === 'left' ? 'scrollLeft' : scrollDir; 291 | 292 | if (opts.scrollElement) { 293 | $scroller = opts.scrollElement; 294 | 295 | if (!explicitOffset.px && !(/^(?:HTML|BODY)$/).test($scroller[0].nodeName)) { 296 | scrollerOffset = $scroller[scrollDir](); 297 | } 298 | } else { 299 | $scroller = $('html, body').firstScrollable(opts.direction); 300 | } 301 | 302 | // beforeScroll callback function must fire before calculating offset 303 | opts.beforeScroll.call($scroller, opts); 304 | 305 | scrollTargetOffset = explicitOffset.px ? explicitOffset : { 306 | relative: '', 307 | px: ($(opts.scrollTarget)[offPos]() && $(opts.scrollTarget)[offPos]()[opts.direction]) || 0 308 | }; 309 | 310 | aniProps[scrollDir] = scrollTargetOffset.relative + (scrollTargetOffset.px + scrollerOffset + opts.offset); 311 | 312 | speed = opts.speed; 313 | 314 | // automatically calculate the speed of the scroll based on distance / coefficient 315 | if (speed === 'auto') { 316 | 317 | // $scroller[scrollDir]() is position before scroll, aniProps[scrollDir] is position after 318 | // When delta is greater, speed will be greater. 319 | delta = Math.abs(aniProps[scrollDir] - $scroller[scrollDir]()); 320 | 321 | // Divide the delta by the coefficient 322 | speed = delta / opts.autoCoefficient; 323 | } 324 | 325 | aniOpts = { 326 | duration: speed, 327 | easing: opts.easing, 328 | complete: function() { 329 | onAfterScroll(opts); 330 | } 331 | }; 332 | 333 | if (opts.step) { 334 | aniOpts.step = opts.step; 335 | } 336 | 337 | if ($scroller.length) { 338 | $scroller.stop().animate(aniProps, aniOpts); 339 | } else { 340 | onAfterScroll(opts); 341 | } 342 | }; 343 | 344 | $.smoothScroll.version = version; 345 | $.smoothScroll.filterPath = function(string) { 346 | string = string || ''; 347 | 348 | return string 349 | .replace(/^\//, '') 350 | .replace(/(?:index|default).[a-zA-Z]{3,4}$/, '') 351 | .replace(/\/$/, ''); 352 | }; 353 | 354 | // default options 355 | $.fn.smoothScroll.defaults = defaults; 356 | 357 | })); 358 | 359 | -------------------------------------------------------------------------------- /jquery.smooth-scroll.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Smooth Scroll - v2.2.0 - 2017-05-05 3 | * https://github.com/kswedberg/jquery-smooth-scroll 4 | * Copyright (c) 2017 Karl Swedberg 5 | * Licensed MIT 6 | */ 7 | 8 | 9 | !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof module&&module.exports?require("jquery"):jQuery)}(function(a){var b={},c={exclude:[],excludeWithin:[],offset:0,direction:"top",delegateSelector:null,scrollElement:null,scrollTarget:null,autoFocus:!1,beforeScroll:function(){},afterScroll:function(){},easing:"swing",speed:400,autoCoefficient:2,preventDefault:!0},d=function(b){var c=[],d=!1,e=b.dir&&"left"===b.dir?"scrollLeft":"scrollTop";return this.each(function(){var b=a(this);if(this!==document&&this!==window)return!document.scrollingElement||this!==document.documentElement&&this!==document.body?void(b[e]()>0?c.push(this):(b[e](1),d=b[e]()>0,d&&c.push(this),b[e](0))):(c.push(document.scrollingElement),!1)}),c.length||this.each(function(){this===document.documentElement&&"smooth"===a(this).css("scrollBehavior")&&(c=[this]),c.length||"BODY"!==this.nodeName||(c=[this])}),"first"===b.el&&c.length>1&&(c=[c[0]]),c},e=/^([\-\+]=)(\d+)/;a.fn.extend({scrollable:function(a){var b=d.call(this,{dir:a});return this.pushStack(b)},firstScrollable:function(a){var b=d.call(this,{el:"first",dir:a});return this.pushStack(b)},smoothScroll:function(b,c){if("options"===(b=b||{}))return c?this.each(function(){var b=a(this),d=a.extend(b.data("ssOpts")||{},c);a(this).data("ssOpts",d)}):this.first().data("ssOpts");var d=a.extend({},a.fn.smoothScroll.defaults,b),e=function(b){var c=function(a){return a.replace(/(:|\.|\/)/g,"\\$1")},e=this,f=a(this),g=a.extend({},d,f.data("ssOpts")||{}),h=d.exclude,i=g.excludeWithin,j=0,k=0,l=!0,m={},n=a.smoothScroll.filterPath(location.pathname),o=a.smoothScroll.filterPath(e.pathname),p=location.hostname===e.hostname||!e.hostname,q=g.scrollTarget||o===n,r=c(e.hash);if(r&&!a(r).length&&(l=!1),g.scrollTarget||p&&q&&r){for(;l&&j in BBQ, which was the main reason for the 50 | // previous release! 51 | // 1.2 - (2/16/2010) Integrated v1.2, which fixes a 52 | // Safari bug, the event can now be bound before DOM ready, and IE6/7 53 | // page should no longer scroll when the event is first bound. Also 54 | // added the method, and reworked the 55 | // internal "add" method to be compatible with 56 | // changes made to the jQuery 1.4.2 special events API. 57 | // 1.1.1 - (1/22/2010) Integrated v1.1, which fixes an 58 | // obscure IE8 EmulateIE7 meta tag compatibility mode bug. 59 | // 1.1 - (1/9/2010) Broke out the jQuery BBQ event.special 60 | // functionality into a separate plugin for users who want just the 61 | // basic event & back button support, without all the extra awesomeness 62 | // that BBQ provides. This plugin will be included as part of jQuery BBQ, 63 | // but also be available separately. See 64 | // plugin for more information. Also added the 65 | // method and added additional examples. 66 | // 1.0.3 - (12/2/2009) Fixed an issue in IE 6 where location.search and 67 | // location.hash would report incorrectly if the hash contained the ? 68 | // character. Also and 69 | // will no longer parse params out of a URL that doesn't contain ? or #, 70 | // respectively. 71 | // 1.0.2 - (10/10/2009) Fixed an issue in IE 6/7 where the hidden IFRAME caused 72 | // a "This page contains both secure and nonsecure items." warning when 73 | // used on an https:// page. 74 | // 1.0.1 - (10/7/2009) Fixed an issue in IE 8. Since both "IE7" and "IE8 75 | // Compatibility View" modes erroneously report that the browser 76 | // supports the native window.onhashchange event, a slightly more 77 | // robust test needed to be added. 78 | // 1.0 - (10/2/2009) Initial release 79 | 80 | (function($,window){ 81 | '$:nomunge'; // Used by YUI compressor. 82 | 83 | // Some convenient shortcuts. 84 | var undefined, 85 | aps = Array.prototype.slice, 86 | decode = decodeURIComponent, 87 | 88 | // Method / object references. 89 | jq_param = $.param, 90 | jq_param_fragment, 91 | jq_deparam, 92 | jq_deparam_fragment, 93 | jq_bbq = $.bbq = $.bbq || {}, 94 | jq_bbq_pushState, 95 | jq_bbq_getState, 96 | jq_elemUrlAttr, 97 | jq_event_special = $.event.special, 98 | 99 | // Reused strings. 100 | str_hashchange = 'hashchange', 101 | str_querystring = 'querystring', 102 | str_fragment = 'fragment', 103 | str_elemUrlAttr = 'elemUrlAttr', 104 | str_location = 'location', 105 | str_href = 'href', 106 | str_src = 'src', 107 | 108 | // Reused RegExp. 109 | re_trim_querystring = /^.*\?|#.*$/g, 110 | re_trim_fragment = /^.*\#/, 111 | re_no_escape, 112 | 113 | // Used by jQuery.elemUrlAttr. 114 | elemUrlAttr_cache = {}; 115 | 116 | // A few commonly used bits, broken out to help reduce minified file size. 117 | 118 | function is_string( arg ) { 119 | return typeof arg === 'string'; 120 | }; 121 | 122 | // Why write the same function twice? Let's curry! Mmmm, curry.. 123 | 124 | function curry( func ) { 125 | var args = aps.call( arguments, 1 ); 126 | 127 | return function() { 128 | return func.apply( this, args.concat( aps.call( arguments ) ) ); 129 | }; 130 | }; 131 | 132 | // Get location.hash (or what you'd expect location.hash to be) sans any 133 | // leading #. Thanks for making this necessary, Firefox! 134 | function get_fragment( url ) { 135 | return url.replace( /^[^#]*#?(.*)$/, '$1' ); 136 | }; 137 | 138 | // Get location.search (or what you'd expect location.search to be) sans any 139 | // leading #. Thanks for making this necessary, IE6! 140 | function get_querystring( url ) { 141 | return url.replace( /(?:^[^?#]*\?([^#]*).*$)?.*/, '$1' ); 142 | }; 143 | 144 | // Section: Param (to string) 145 | // 146 | // Method: jQuery.param.querystring 147 | // 148 | // Retrieve the query string from a URL or if no arguments are passed, the 149 | // current window.location. 150 | // 151 | // Usage: 152 | // 153 | // > jQuery.param.querystring( [ url ] ); 154 | // 155 | // Arguments: 156 | // 157 | // url - (String) A URL containing query string params to be parsed. If url 158 | // is not passed, the current window.location is used. 159 | // 160 | // Returns: 161 | // 162 | // (String) The parsed query string, with any leading "?" removed. 163 | // 164 | 165 | // Method: jQuery.param.querystring (build url) 166 | // 167 | // Merge a URL, with or without pre-existing query string params, plus any 168 | // object, params string or URL containing query string params into a new URL. 169 | // 170 | // Usage: 171 | // 172 | // > jQuery.param.querystring( url, params [, merge_mode ] ); 173 | // 174 | // Arguments: 175 | // 176 | // url - (String) A valid URL for params to be merged into. This URL may 177 | // contain a query string and/or fragment (hash). 178 | // params - (String) A params string or URL containing query string params to 179 | // be merged into url. 180 | // params - (Object) A params object to be merged into url. 181 | // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not 182 | // specified, and is as-follows: 183 | // 184 | // * 0: params in the params argument will override any query string 185 | // params in url. 186 | // * 1: any query string params in url will override params in the params 187 | // argument. 188 | // * 2: params argument will completely replace any query string in url. 189 | // 190 | // Returns: 191 | // 192 | // (String) Either a params string with urlencoded data or a URL with a 193 | // urlencoded query string in the format 'a=b&c=d&e=f'. 194 | 195 | // Method: jQuery.param.fragment 196 | // 197 | // Retrieve the fragment (hash) from a URL or if no arguments are passed, the 198 | // current window.location. 199 | // 200 | // Usage: 201 | // 202 | // > jQuery.param.fragment( [ url ] ); 203 | // 204 | // Arguments: 205 | // 206 | // url - (String) A URL containing fragment (hash) params to be parsed. If 207 | // url is not passed, the current window.location is used. 208 | // 209 | // Returns: 210 | // 211 | // (String) The parsed fragment (hash) string, with any leading "#" removed. 212 | 213 | // Method: jQuery.param.fragment (build url) 214 | // 215 | // Merge a URL, with or without pre-existing fragment (hash) params, plus any 216 | // object, params string or URL containing fragment (hash) params into a new 217 | // URL. 218 | // 219 | // Usage: 220 | // 221 | // > jQuery.param.fragment( url, params [, merge_mode ] ); 222 | // 223 | // Arguments: 224 | // 225 | // url - (String) A valid URL for params to be merged into. This URL may 226 | // contain a query string and/or fragment (hash). 227 | // params - (String) A params string or URL containing fragment (hash) params 228 | // to be merged into url. 229 | // params - (Object) A params object to be merged into url. 230 | // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not 231 | // specified, and is as-follows: 232 | // 233 | // * 0: params in the params argument will override any fragment (hash) 234 | // params in url. 235 | // * 1: any fragment (hash) params in url will override params in the 236 | // params argument. 237 | // * 2: params argument will completely replace any query string in url. 238 | // 239 | // Returns: 240 | // 241 | // (String) Either a params string with urlencoded data or a URL with a 242 | // urlencoded fragment (hash) in the format 'a=b&c=d&e=f'. 243 | 244 | function jq_param_sub( is_fragment, get_func, url, params, merge_mode ) { 245 | var result, 246 | qs, 247 | matches, 248 | url_params, 249 | hash; 250 | 251 | if ( params !== undefined ) { 252 | // Build URL by merging params into url string. 253 | 254 | // matches[1] = url part that precedes params, not including trailing ?/# 255 | // matches[2] = params, not including leading ?/# 256 | // matches[3] = if in 'querystring' mode, hash including leading #, otherwise '' 257 | matches = url.match( is_fragment ? /^([^#]*)\#?(.*)$/ : /^([^#?]*)\??([^#]*)(#?.*)/ ); 258 | 259 | // Get the hash if in 'querystring' mode, and it exists. 260 | hash = matches[3] || ''; 261 | 262 | if ( merge_mode === 2 && is_string( params ) ) { 263 | // If merge_mode is 2 and params is a string, merge the fragment / query 264 | // string into the URL wholesale, without converting it into an object. 265 | qs = params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' ); 266 | 267 | } else { 268 | // Convert relevant params in url to object. 269 | url_params = jq_deparam( matches[2] ); 270 | 271 | params = is_string( params ) 272 | 273 | // Convert passed params string into object. 274 | ? jq_deparam[ is_fragment ? str_fragment : str_querystring ]( params ) 275 | 276 | // Passed params object. 277 | : params; 278 | 279 | qs = merge_mode === 2 ? params // passed params replace url params 280 | : merge_mode === 1 ? $.extend( {}, params, url_params ) // url params override passed params 281 | : $.extend( {}, url_params, params ); // passed params override url params 282 | 283 | // Convert params object to a string. 284 | qs = jq_param( qs ); 285 | 286 | // Unescape characters specified via $.param.noEscape. Since only hash- 287 | // history users have requested this feature, it's only enabled for 288 | // fragment-related params strings. 289 | if ( is_fragment ) { 290 | qs = qs.replace( re_no_escape, decode ); 291 | } 292 | } 293 | 294 | // Build URL from the base url, querystring and hash. In 'querystring' 295 | // mode, ? is only added if a query string exists. In 'fragment' mode, # 296 | // is always added. 297 | result = matches[1] + ( is_fragment ? '#' : qs || !matches[1] ? '?' : '' ) + qs + hash; 298 | 299 | } else { 300 | // If URL was passed in, parse params from URL string, otherwise parse 301 | // params from window.location. 302 | result = get_func( url !== undefined ? url : window[ str_location ][ str_href ] ); 303 | } 304 | 305 | return result; 306 | }; 307 | 308 | jq_param[ str_querystring ] = curry( jq_param_sub, 0, get_querystring ); 309 | jq_param[ str_fragment ] = jq_param_fragment = curry( jq_param_sub, 1, get_fragment ); 310 | 311 | // Method: jQuery.param.fragment.noEscape 312 | // 313 | // Specify characters that will be left unescaped when fragments are created 314 | // or merged using , or when the fragment is modified 315 | // using . This option only applies to serialized data 316 | // object fragments, and not set-as-string fragments. Does not affect the 317 | // query string. Defaults to ",/" (comma, forward slash). 318 | // 319 | // Note that this is considered a purely aesthetic option, and will help to 320 | // create URLs that "look pretty" in the address bar or bookmarks, without 321 | // affecting functionality in any way. That being said, be careful to not 322 | // unescape characters that are used as delimiters or serve a special 323 | // purpose, such as the "#?&=+" (octothorpe, question mark, ampersand, 324 | // equals, plus) characters. 325 | // 326 | // Usage: 327 | // 328 | // > jQuery.param.fragment.noEscape( [ chars ] ); 329 | // 330 | // Arguments: 331 | // 332 | // chars - (String) The characters to not escape in the fragment. If 333 | // unspecified, defaults to empty string (escape all characters). 334 | // 335 | // Returns: 336 | // 337 | // Nothing. 338 | 339 | jq_param_fragment.noEscape = function( chars ) { 340 | chars = chars || ''; 341 | var arr = $.map( chars.split(''), encodeURIComponent ); 342 | re_no_escape = new RegExp( arr.join('|'), 'g' ); 343 | }; 344 | 345 | // A sensible default. These are the characters people seem to complain about 346 | // "uglifying up the URL" the most. 347 | jq_param_fragment.noEscape( ',/' ); 348 | 349 | // Section: Deparam (from string) 350 | // 351 | // Method: jQuery.deparam 352 | // 353 | // Deserialize a params string into an object, optionally coercing numbers, 354 | // booleans, null and undefined values; this method is the counterpart to the 355 | // internal jQuery.param method. 356 | // 357 | // Usage: 358 | // 359 | // > jQuery.deparam( params [, coerce ] ); 360 | // 361 | // Arguments: 362 | // 363 | // params - (String) A params string to be parsed. 364 | // coerce - (Boolean) If true, coerces any numbers or true, false, null, and 365 | // undefined to their actual value. Defaults to false if omitted. 366 | // 367 | // Returns: 368 | // 369 | // (Object) An object representing the deserialized params string. 370 | 371 | $.deparam = jq_deparam = function( params, coerce ) { 372 | var obj = {}, 373 | coerce_types = { 'true': !0, 'false': !1, 'null': null }; 374 | 375 | // Iterate over all name=value pairs. 376 | $.each( params.replace( /\+/g, ' ' ).split( '&' ), function(j,v){ 377 | var param = v.split( '=' ), 378 | key = decode( param[0] ), 379 | val, 380 | cur = obj, 381 | i = 0, 382 | 383 | // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it 384 | // into its component parts. 385 | keys = key.split( '][' ), 386 | keys_last = keys.length - 1; 387 | 388 | // If the first keys part contains [ and the last ends with ], then [] 389 | // are correctly balanced. 390 | if ( /\[/.test( keys[0] ) && /\]$/.test( keys[ keys_last ] ) ) { 391 | // Remove the trailing ] from the last keys part. 392 | keys[ keys_last ] = keys[ keys_last ].replace( /\]$/, '' ); 393 | 394 | // Split first keys part into two parts on the [ and add them back onto 395 | // the beginning of the keys array. 396 | keys = keys.shift().split('[').concat( keys ); 397 | 398 | keys_last = keys.length - 1; 399 | } else { 400 | // Basic 'foo' style key. 401 | keys_last = 0; 402 | } 403 | 404 | // Are we dealing with a name=value pair, or just a name? 405 | if ( param.length === 2 ) { 406 | val = decode( param[1] ); 407 | 408 | // Coerce values. 409 | if ( coerce ) { 410 | val = val && !isNaN(val) ? +val // number 411 | : val === 'undefined' ? undefined // undefined 412 | : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null 413 | : val; // string 414 | } 415 | 416 | if ( keys_last ) { 417 | // Complex key, build deep object structure based on a few rules: 418 | // * The 'cur' pointer starts at the object top-level. 419 | // * [] = array push (n is set to array length), [n] = array if n is 420 | // numeric, otherwise object. 421 | // * If at the last keys part, set the value. 422 | // * For each keys part, if the current level is undefined create an 423 | // object or array based on the type of the next keys part. 424 | // * Move the 'cur' pointer to the next level. 425 | // * Rinse & repeat. 426 | for ( ; i <= keys_last; i++ ) { 427 | key = keys[i] === '' ? cur.length : keys[i]; 428 | cur = cur[key] = i < keys_last 429 | ? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] ) 430 | : val; 431 | } 432 | 433 | } else { 434 | // Simple key, even simpler rules, since only scalars and shallow 435 | // arrays are allowed. 436 | 437 | if ( $.isArray( obj[key] ) ) { 438 | // val is already an array, so push on the next value. 439 | obj[key].push( val ); 440 | 441 | } else if ( obj[key] !== undefined ) { 442 | // val isn't an array, but since a second value has been specified, 443 | // convert val into an array. 444 | obj[key] = [ obj[key], val ]; 445 | 446 | } else { 447 | // val is a scalar. 448 | obj[key] = val; 449 | } 450 | } 451 | 452 | } else if ( key ) { 453 | // No value was defined, so set something meaningful. 454 | obj[key] = coerce 455 | ? undefined 456 | : ''; 457 | } 458 | }); 459 | 460 | return obj; 461 | }; 462 | 463 | // Method: jQuery.deparam.querystring 464 | // 465 | // Parse the query string from a URL or the current window.location, 466 | // deserializing it into an object, optionally coercing numbers, booleans, 467 | // null and undefined values. 468 | // 469 | // Usage: 470 | // 471 | // > jQuery.deparam.querystring( [ url ] [, coerce ] ); 472 | // 473 | // Arguments: 474 | // 475 | // url - (String) An optional params string or URL containing query string 476 | // params to be parsed. If url is omitted, the current window.location 477 | // is used. 478 | // coerce - (Boolean) If true, coerces any numbers or true, false, null, and 479 | // undefined to their actual value. Defaults to false if omitted. 480 | // 481 | // Returns: 482 | // 483 | // (Object) An object representing the deserialized params string. 484 | 485 | // Method: jQuery.deparam.fragment 486 | // 487 | // Parse the fragment (hash) from a URL or the current window.location, 488 | // deserializing it into an object, optionally coercing numbers, booleans, 489 | // null and undefined values. 490 | // 491 | // Usage: 492 | // 493 | // > jQuery.deparam.fragment( [ url ] [, coerce ] ); 494 | // 495 | // Arguments: 496 | // 497 | // url - (String) An optional params string or URL containing fragment (hash) 498 | // params to be parsed. If url is omitted, the current window.location 499 | // is used. 500 | // coerce - (Boolean) If true, coerces any numbers or true, false, null, and 501 | // undefined to their actual value. Defaults to false if omitted. 502 | // 503 | // Returns: 504 | // 505 | // (Object) An object representing the deserialized params string. 506 | 507 | function jq_deparam_sub( is_fragment, url_or_params, coerce ) { 508 | if ( url_or_params === undefined || typeof url_or_params === 'boolean' ) { 509 | // url_or_params not specified. 510 | coerce = url_or_params; 511 | url_or_params = jq_param[ is_fragment ? str_fragment : str_querystring ](); 512 | } else { 513 | url_or_params = is_string( url_or_params ) 514 | ? url_or_params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' ) 515 | : url_or_params; 516 | } 517 | 518 | return jq_deparam( url_or_params, coerce ); 519 | }; 520 | 521 | jq_deparam[ str_querystring ] = curry( jq_deparam_sub, 0 ); 522 | jq_deparam[ str_fragment ] = jq_deparam_fragment = curry( jq_deparam_sub, 1 ); 523 | 524 | // Section: Element manipulation 525 | // 526 | // Method: jQuery.elemUrlAttr 527 | // 528 | // Get the internal "Default URL attribute per tag" list, or augment the list 529 | // with additional tag-attribute pairs, in case the defaults are insufficient. 530 | // 531 | // In the and methods, this list 532 | // is used to determine which attribute contains the URL to be modified, if 533 | // an "attr" param is not specified. 534 | // 535 | // Default Tag-Attribute List: 536 | // 537 | // a - href 538 | // base - href 539 | // iframe - src 540 | // img - src 541 | // input - src 542 | // form - action 543 | // link - href 544 | // script - src 545 | // 546 | // Usage: 547 | // 548 | // > jQuery.elemUrlAttr( [ tag_attr ] ); 549 | // 550 | // Arguments: 551 | // 552 | // tag_attr - (Object) An object containing a list of tag names and their 553 | // associated default attribute names in the format { tag: 'attr', ... } to 554 | // be merged into the internal tag-attribute list. 555 | // 556 | // Returns: 557 | // 558 | // (Object) An object containing all stored tag-attribute values. 559 | 560 | // Only define function and set defaults if function doesn't already exist, as 561 | // the urlInternal plugin will provide this method as well. 562 | $[ str_elemUrlAttr ] || ($[ str_elemUrlAttr ] = function( obj ) { 563 | return $.extend( elemUrlAttr_cache, obj ); 564 | })({ 565 | a: str_href, 566 | base: str_href, 567 | iframe: str_src, 568 | img: str_src, 569 | input: str_src, 570 | form: 'action', 571 | link: str_href, 572 | script: str_src 573 | }); 574 | 575 | jq_elemUrlAttr = $[ str_elemUrlAttr ]; 576 | 577 | // Method: jQuery.fn.querystring 578 | // 579 | // Update URL attribute in one or more elements, merging the current URL (with 580 | // or without pre-existing query string params) plus any params object or 581 | // string into a new URL, which is then set into that attribute. Like 582 | // , but for all elements in a jQuery 583 | // collection. 584 | // 585 | // Usage: 586 | // 587 | // > jQuery('selector').querystring( [ attr, ] params [, merge_mode ] ); 588 | // 589 | // Arguments: 590 | // 591 | // attr - (String) Optional name of an attribute that will contain a URL to 592 | // merge params or url into. See for a list of default 593 | // attributes. 594 | // params - (Object) A params object to be merged into the URL attribute. 595 | // params - (String) A URL containing query string params, or params string 596 | // to be merged into the URL attribute. 597 | // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not 598 | // specified, and is as-follows: 599 | // 600 | // * 0: params in the params argument will override any params in attr URL. 601 | // * 1: any params in attr URL will override params in the params argument. 602 | // * 2: params argument will completely replace any query string in attr 603 | // URL. 604 | // 605 | // Returns: 606 | // 607 | // (jQuery) The initial jQuery collection of elements, but with modified URL 608 | // attribute values. 609 | 610 | // Method: jQuery.fn.fragment 611 | // 612 | // Update URL attribute in one or more elements, merging the current URL (with 613 | // or without pre-existing fragment/hash params) plus any params object or 614 | // string into a new URL, which is then set into that attribute. Like 615 | // , but for all elements in a jQuery 616 | // collection. 617 | // 618 | // Usage: 619 | // 620 | // > jQuery('selector').fragment( [ attr, ] params [, merge_mode ] ); 621 | // 622 | // Arguments: 623 | // 624 | // attr - (String) Optional name of an attribute that will contain a URL to 625 | // merge params into. See for a list of default 626 | // attributes. 627 | // params - (Object) A params object to be merged into the URL attribute. 628 | // params - (String) A URL containing fragment (hash) params, or params 629 | // string to be merged into the URL attribute. 630 | // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not 631 | // specified, and is as-follows: 632 | // 633 | // * 0: params in the params argument will override any params in attr URL. 634 | // * 1: any params in attr URL will override params in the params argument. 635 | // * 2: params argument will completely replace any fragment (hash) in attr 636 | // URL. 637 | // 638 | // Returns: 639 | // 640 | // (jQuery) The initial jQuery collection of elements, but with modified URL 641 | // attribute values. 642 | 643 | function jq_fn_sub( mode, force_attr, params, merge_mode ) { 644 | if ( !is_string( params ) && typeof params !== 'object' ) { 645 | // force_attr not specified. 646 | merge_mode = params; 647 | params = force_attr; 648 | force_attr = undefined; 649 | } 650 | 651 | return this.each(function(){ 652 | var that = $(this), 653 | 654 | // Get attribute specified, or default specified via $.elemUrlAttr. 655 | attr = force_attr || jq_elemUrlAttr()[ ( this.nodeName || '' ).toLowerCase() ] || '', 656 | 657 | // Get URL value. 658 | url = attr && that.attr( attr ) || ''; 659 | 660 | // Update attribute with new URL. 661 | that.attr( attr, jq_param[ mode ]( url, params, merge_mode ) ); 662 | }); 663 | 664 | }; 665 | 666 | $.fn[ str_querystring ] = curry( jq_fn_sub, str_querystring ); 667 | $.fn[ str_fragment ] = curry( jq_fn_sub, str_fragment ); 668 | 669 | // Section: History, hashchange event 670 | // 671 | // Method: jQuery.bbq.pushState 672 | // 673 | // Adds a 'state' into the browser history at the current position, setting 674 | // location.hash and triggering any bound callbacks 675 | // (provided the new state is different than the previous state). 676 | // 677 | // If no arguments are passed, an empty state is created, which is just a 678 | // shortcut for jQuery.bbq.pushState( {}, 2 ). 679 | // 680 | // Usage: 681 | // 682 | // > jQuery.bbq.pushState( [ params [, merge_mode ] ] ); 683 | // 684 | // Arguments: 685 | // 686 | // params - (String) A serialized params string or a hash string beginning 687 | // with # to merge into location.hash. 688 | // params - (Object) A params object to merge into location.hash. 689 | // merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not 690 | // specified (unless a hash string beginning with # is specified, in which 691 | // case merge behavior defaults to 2), and is as-follows: 692 | // 693 | // * 0: params in the params argument will override any params in the 694 | // current state. 695 | // * 1: any params in the current state will override params in the params 696 | // argument. 697 | // * 2: params argument will completely replace current state. 698 | // 699 | // Returns: 700 | // 701 | // Nothing. 702 | // 703 | // Additional Notes: 704 | // 705 | // * Setting an empty state may cause the browser to scroll. 706 | // * Unlike the fragment and querystring methods, if a hash string beginning 707 | // with # is specified as the params agrument, merge_mode defaults to 2. 708 | 709 | jq_bbq.pushState = jq_bbq_pushState = function( params, merge_mode ) { 710 | if ( is_string( params ) && /^#/.test( params ) && merge_mode === undefined ) { 711 | // Params string begins with # and merge_mode not specified, so completely 712 | // overwrite window.location.hash. 713 | merge_mode = 2; 714 | } 715 | 716 | var has_args = params !== undefined, 717 | // Merge params into window.location using $.param.fragment. 718 | url = jq_param_fragment( window[ str_location ][ str_href ], 719 | has_args ? params : {}, has_args ? merge_mode : 2 ); 720 | 721 | // Set new window.location.href. If hash is empty, use just # to prevent 722 | // browser from reloading the page. Note that Safari 3 & Chrome barf on 723 | // location.hash = '#'. 724 | window[ str_location ][ str_href ] = url + ( /#/.test( url ) ? '' : '#' ); 725 | }; 726 | 727 | // Method: jQuery.bbq.getState 728 | // 729 | // Retrieves the current 'state' from the browser history, parsing 730 | // location.hash for a specific key or returning an object containing the 731 | // entire state, optionally coercing numbers, booleans, null and undefined 732 | // values. 733 | // 734 | // Usage: 735 | // 736 | // > jQuery.bbq.getState( [ key ] [, coerce ] ); 737 | // 738 | // Arguments: 739 | // 740 | // key - (String) An optional state key for which to return a value. 741 | // coerce - (Boolean) If true, coerces any numbers or true, false, null, and 742 | // undefined to their actual value. Defaults to false. 743 | // 744 | // Returns: 745 | // 746 | // (Anything) If key is passed, returns the value corresponding with that key 747 | // in the location.hash 'state', or undefined. If not, an object 748 | // representing the entire 'state' is returned. 749 | 750 | jq_bbq.getState = jq_bbq_getState = function( key, coerce ) { 751 | return key === undefined || typeof key === 'boolean' 752 | ? jq_deparam_fragment( key ) // 'key' really means 'coerce' here 753 | : jq_deparam_fragment( coerce )[ key ]; 754 | }; 755 | 756 | // Method: jQuery.bbq.removeState 757 | // 758 | // Remove one or more keys from the current browser history 'state', creating 759 | // a new state, setting location.hash and triggering any bound 760 | // callbacks (provided the new state is different than 761 | // the previous state). 762 | // 763 | // If no arguments are passed, an empty state is created, which is just a 764 | // shortcut for jQuery.bbq.pushState( {}, 2 ). 765 | // 766 | // Usage: 767 | // 768 | // > jQuery.bbq.removeState( [ key [, key ... ] ] ); 769 | // 770 | // Arguments: 771 | // 772 | // key - (String) One or more key values to remove from the current state, 773 | // passed as individual arguments. 774 | // key - (Array) A single array argument that contains a list of key values 775 | // to remove from the current state. 776 | // 777 | // Returns: 778 | // 779 | // Nothing. 780 | // 781 | // Additional Notes: 782 | // 783 | // * Setting an empty state may cause the browser to scroll. 784 | 785 | jq_bbq.removeState = function( arr ) { 786 | var state = {}; 787 | 788 | // If one or more arguments is passed.. 789 | if ( arr !== undefined ) { 790 | 791 | // Get the current state. 792 | state = jq_bbq_getState(); 793 | 794 | // For each passed key, delete the corresponding property from the current 795 | // state. 796 | $.each( $.isArray( arr ) ? arr : arguments, function(i,v){ 797 | delete state[ v ]; 798 | }); 799 | } 800 | 801 | // Set the state, completely overriding any existing state. 802 | jq_bbq_pushState( state, 2 ); 803 | }; 804 | 805 | // Event: hashchange event (BBQ) 806 | // 807 | // Usage in jQuery 1.4 and newer: 808 | // 809 | // In jQuery 1.4 and newer, the event object passed into any hashchange event 810 | // callback is augmented with a copy of the location.hash fragment at the time 811 | // the event was triggered as its event.fragment property. In addition, the 812 | // event.getState method operates on this property (instead of location.hash) 813 | // which allows this fragment-as-a-state to be referenced later, even after 814 | // window.location may have changed. 815 | // 816 | // Note that event.fragment and event.getState are not defined according to 817 | // W3C (or any other) specification, but will still be available whether or 818 | // not the hashchange event exists natively in the browser, because of the 819 | // utility they provide. 820 | // 821 | // The event.fragment property contains the output of 822 | // and the event.getState method is equivalent to the 823 | // method. 824 | // 825 | // > $(window).bind( 'hashchange', function( event ) { 826 | // > var hash_str = event.fragment, 827 | // > param_obj = event.getState(), 828 | // > param_val = event.getState( 'param_name' ), 829 | // > param_val_coerced = event.getState( 'param_name', true ); 830 | // > ... 831 | // > }); 832 | // 833 | // Usage in jQuery 1.3.2: 834 | // 835 | // In jQuery 1.3.2, the event object cannot to be augmented as in jQuery 1.4+, 836 | // so the fragment state isn't bound to the event object and must instead be 837 | // parsed using the and methods. 838 | // 839 | // > $(window).bind( 'hashchange', function( event ) { 840 | // > var hash_str = $.param.fragment(), 841 | // > param_obj = $.bbq.getState(), 842 | // > param_val = $.bbq.getState( 'param_name' ), 843 | // > param_val_coerced = $.bbq.getState( 'param_name', true ); 844 | // > ... 845 | // > }); 846 | // 847 | // Additional Notes: 848 | // 849 | // * Due to changes in the special events API, jQuery BBQ v1.2 or newer is 850 | // required to enable the augmented event object in jQuery 1.4.2 and newer. 851 | // * See for more detailed information. 852 | 853 | jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], { 854 | 855 | // Augmenting the event object with the .fragment property and .getState 856 | // method requires jQuery 1.4 or newer. Note: with 1.3.2, everything will 857 | // work, but the event won't be augmented) 858 | add: function( handleObj ) { 859 | var old_handler; 860 | 861 | function new_handler(e) { 862 | // e.fragment is set to the value of location.hash (with any leading # 863 | // removed) at the time the event is triggered. 864 | var hash = e[ str_fragment ] = jq_param_fragment(); 865 | 866 | // e.getState() works just like $.bbq.getState(), but uses the 867 | // e.fragment property stored on the event object. 868 | e.getState = function( key, coerce ) { 869 | return key === undefined || typeof key === 'boolean' 870 | ? jq_deparam( hash, key ) // 'key' really means 'coerce' here 871 | : jq_deparam( hash, coerce )[ key ]; 872 | }; 873 | 874 | old_handler.apply( this, arguments ); 875 | }; 876 | 877 | // This may seem a little complicated, but it normalizes the special event 878 | // .add method between jQuery 1.4/1.4.1 and 1.4.2+ 879 | if ( $.isFunction( handleObj ) ) { 880 | // 1.4, 1.4.1 881 | old_handler = handleObj; 882 | return new_handler; 883 | } else { 884 | // 1.4.2+ 885 | old_handler = handleObj.handler; 886 | handleObj.handler = new_handler; 887 | } 888 | } 889 | 890 | }); 891 | 892 | })(jQuery,this); 893 | 894 | /*! 895 | * jQuery hashchange event - v1.2 - 2/11/2010 896 | * http://benalman.com/projects/jquery-hashchange-plugin/ 897 | * 898 | * Copyright (c) 2010 "Cowboy" Ben Alman 899 | * Dual licensed under the MIT and GPL licenses. 900 | * http://benalman.com/about/license/ 901 | */ 902 | 903 | // Script: jQuery hashchange event 904 | // 905 | // *Version: 1.2, Last updated: 2/11/2010* 906 | // 907 | // Project Home - http://benalman.com/projects/jquery-hashchange-plugin/ 908 | // GitHub - http://github.com/cowboy/jquery-hashchange/ 909 | // Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js 910 | // (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (1.1kb) 911 | // 912 | // About: License 913 | // 914 | // Copyright (c) 2010 "Cowboy" Ben Alman, 915 | // Dual licensed under the MIT and GPL licenses. 916 | // http://benalman.com/about/license/ 917 | // 918 | // About: Examples 919 | // 920 | // This working example, complete with fully commented code, illustrate one way 921 | // in which this plugin can be used. 922 | // 923 | // hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/ 924 | // 925 | // About: Support and Testing 926 | // 927 | // Information about what version or versions of jQuery this plugin has been 928 | // tested with, what browsers it has been tested in, and where the unit tests 929 | // reside (so you can test it yourself). 930 | // 931 | // jQuery Versions - 1.3.2, 1.4.1, 1.4.2 932 | // Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, Chrome, Opera 9.6-10.1. 933 | // Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/ 934 | // 935 | // About: Known issues 936 | // 937 | // While this jQuery hashchange event implementation is quite stable and robust, 938 | // there are a few unfortunate browser bugs surrounding expected hashchange 939 | // event-based behaviors, independent of any JavaScript window.onhashchange 940 | // abstraction. See the following examples for more information: 941 | // 942 | // Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/ 943 | // Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/ 944 | // WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/ 945 | // Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/ 946 | // 947 | // About: Release History 948 | // 949 | // 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin 950 | // from a page on another domain would cause an error in Safari 4. Also, 951 | // IE6/7 Iframe is now inserted after the body (this actually works), 952 | // which prevents the page from scrolling when the event is first bound. 953 | // Event can also now be bound before DOM ready, but it won't be usable 954 | // before then in IE6/7. 955 | // 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug 956 | // where browser version is incorrectly reported as 8.0, despite 957 | // inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag. 958 | // 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special 959 | // window.onhashchange functionality into a separate plugin for users 960 | // who want just the basic event & back button support, without all the 961 | // extra awesomeness that BBQ provides. This plugin will be included as 962 | // part of jQuery BBQ, but also be available separately. 963 | 964 | (function($,window,undefined){ 965 | '$:nomunge'; // Used by YUI compressor. 966 | 967 | // Method / object references. 968 | var fake_onhashchange, 969 | jq_event_special = $.event.special, 970 | 971 | // Reused strings. 972 | str_location = 'location', 973 | str_hashchange = 'hashchange', 974 | str_href = 'href', 975 | 976 | // IE6/7 specifically need some special love when it comes to back-button 977 | // support, so let's do a little browser sniffing.. 978 | browser = $.browser, 979 | mode = document.documentMode, 980 | is_old_ie = browser.msie && ( mode === undefined || mode < 8 ), 981 | 982 | // Does the browser support window.onhashchange? Test for IE version, since 983 | // IE8 incorrectly reports this when in "IE7" or "IE8 Compatibility View"! 984 | supports_onhashchange = 'on' + str_hashchange in window && !is_old_ie; 985 | 986 | // Get location.hash (or what you'd expect location.hash to be) sans any 987 | // leading #. Thanks for making this necessary, Firefox! 988 | function get_fragment( url ) { 989 | url = url || window[ str_location ][ str_href ]; 990 | return url.replace( /^[^#]*#?(.*)$/, '$1' ); 991 | }; 992 | 993 | // Property: jQuery.hashchangeDelay 994 | // 995 | // The numeric interval (in milliseconds) at which the 996 | // polling loop executes. Defaults to 100. 997 | 998 | $[ str_hashchange + 'Delay' ] = 100; 999 | 1000 | // Event: hashchange event 1001 | // 1002 | // Fired when location.hash changes. In browsers that support it, the native 1003 | // window.onhashchange event is used (IE8, FF3.6), otherwise a polling loop is 1004 | // initialized, running every milliseconds to see if 1005 | // the hash has changed. In IE 6 and 7, a hidden Iframe is created to allow 1006 | // the back button and hash-based history to work. 1007 | // 1008 | // Usage: 1009 | // 1010 | // > $(window).bind( 'hashchange', function(e) { 1011 | // > var hash = location.hash; 1012 | // > ... 1013 | // > }); 1014 | // 1015 | // Additional Notes: 1016 | // 1017 | // * The polling loop and Iframe are not created until at least one callback 1018 | // is actually bound to 'hashchange'. 1019 | // * If you need the bound callback(s) to execute immediately, in cases where 1020 | // the page 'state' exists on page load (via bookmark or page refresh, for 1021 | // example) use $(window).trigger( 'hashchange' ); 1022 | // * The event can be bound before DOM ready, but since it won't be usable 1023 | // before then in IE6/7 (due to the necessary Iframe), recommended usage is 1024 | // to bind it inside a $(document).ready() callback. 1025 | 1026 | jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], { 1027 | 1028 | // Called only when the first 'hashchange' event is bound to window. 1029 | setup: function() { 1030 | // If window.onhashchange is supported natively, there's nothing to do.. 1031 | if ( supports_onhashchange ) { return false; } 1032 | 1033 | // Otherwise, we need to create our own. And we don't want to call this 1034 | // until the user binds to the event, just in case they never do, since it 1035 | // will create a polling loop and possibly even a hidden Iframe. 1036 | $( fake_onhashchange.start ); 1037 | }, 1038 | 1039 | // Called only when the last 'hashchange' event is unbound from window. 1040 | teardown: function() { 1041 | // If window.onhashchange is supported natively, there's nothing to do.. 1042 | if ( supports_onhashchange ) { return false; } 1043 | 1044 | // Otherwise, we need to stop ours (if possible). 1045 | $( fake_onhashchange.stop ); 1046 | } 1047 | 1048 | }); 1049 | 1050 | // fake_onhashchange does all the work of triggering the window.onhashchange 1051 | // event for browsers that don't natively support it, including creating a 1052 | // polling loop to watch for hash changes and in IE 6/7 creating a hidden 1053 | // Iframe to enable back and forward. 1054 | fake_onhashchange = (function(){ 1055 | var self = {}, 1056 | timeout_id, 1057 | iframe, 1058 | set_history, 1059 | get_history; 1060 | 1061 | // Initialize. In IE 6/7, creates a hidden Iframe for history handling. 1062 | function init(){ 1063 | // Most browsers don't need special methods here.. 1064 | set_history = get_history = function(val){ return val; }; 1065 | 1066 | // But IE6/7 do! 1067 | if ( is_old_ie ) { 1068 | 1069 | // Create hidden Iframe after the end of the body to prevent initial 1070 | // page load from scrolling unnecessarily. 1071 | iframe = $('