├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmignore ├── .npmrc ├── .nvmrc ├── .sass-lint.yml ├── .travis.yml ├── CHANGELOG.md ├── Gruntfile.js ├── LICENSE.md ├── README.md ├── bower.json ├── composer.json ├── dependencies ├── css │ └── highlightjs-github-theme.css └── js │ ├── bootstrap.min.js │ ├── highlight.min.js │ ├── jquery.min.js │ ├── modernizr.js │ └── popper.min.js ├── dist ├── bootstrap-slider.js ├── bootstrap-slider.min.js └── css │ ├── bootstrap-slider.css │ └── bootstrap-slider.min.css ├── package.json ├── scripts ├── build-preview.sh ├── release.sh └── update-gh-pages.sh ├── src ├── js │ └── bootstrap-slider.js └── sass │ ├── _mixins.scss │ ├── _rules.scss │ ├── _variables.scss │ └── bootstrap-slider.scss ├── test ├── phantom_bind_polyfill.js └── specs │ ├── AccessibilitySpec.js │ ├── AriaValueTextFormatterSpec.js │ ├── AutoRegisterDataProvideSpec.js │ ├── ConflictingOptionsSpec.js │ ├── DestroyMethodTests.js │ ├── DraggingHandlesSpec.js │ ├── ElementDataAttributesSpec.js │ ├── EventsSpec.js │ ├── FocusOptionSpec.js │ ├── KeyboardSupportSpec.js │ ├── LockToTicksSpec.js │ ├── LogarithmicScaleSpec.js │ ├── LowAndHighTrackSpec.js │ ├── NamespaceSpec.js │ ├── OrientationSpec.js │ ├── PublicMethodsSpec.js │ ├── RangeHighlightsSpec.js │ ├── RefreshMethodSpec.js │ ├── ResizeSpec.js │ ├── RtlOptionsSpec.js │ ├── ScrollableBodySpec.js │ ├── ScrollableContainerSpec.js │ ├── StepReachMaxValueSpec.js │ ├── TickClickingBehaviorSpec.js │ ├── TickLabelSpec.js │ ├── TickMarksSpec.js │ ├── TooltipMouseOverOptionSpec.js │ ├── TooltipPositionOptionSpec.js │ ├── TooltipSplitOptionSpec.js │ ├── TouchCapableSpec.js │ └── offMethodSpec.js └── tpl ├── SpecRunner.tpl └── index.tpl /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Guidelines 2 | ============= 3 | * The application JavaScript source code is transpiled using [Babel](https://babeljs.io/) 4 | * When you are ready to submit your PR, please rebase your commits against the latest master branch so they are easier to examine! 5 | * Please make sure you're not committing your re-built `dist` files, either. We'll do that! 6 | * Also, please note, your code will not be merged if it does not pass our CI test. Thanks for your contribution! 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Issues 2 | ============= 3 | **NOTE:** Before filing a new issue, please search through the open issues list and check to see if an existing issue already exists that describes your problem. If so, leave a comment within that issue with the checklist items described below. 4 | 5 | Please make sure you include the following in your issue report where appropriate: 6 | 7 | - [ ] JSFiddle (or an equivalent such as CodePen, Plunker, etc) with the an example demonstrating the bug 8 | - [ ] Instructions to replicate the bug in the Fiddle 9 | 10 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Pull Requests 2 | ============= 3 | Please accompany all pull requests with the following (where appropriate): 4 | 5 | - [ ] unit tests (we use [Jasmine 2.x.x](https://jasmine.github.io/2.2/introduction)) 6 | - [ ] JSFiddle (or an equivalent such as CodePen, Plunker, etc) or screenshot/GIF with new feature or bug-fix 7 | - [ ] Link to original Github issue (if this is a bug-fix) 8 | - [ ] documentation updates to README file 9 | - [ ] examples within [/tpl/index.tpl](https://github.com/seiyria/bootstrap-slider/blob/master/tpl/index.tpl) (for new options being added) 10 | - [ ] Passes CI-server checks (runs automated tests, JS source-code linting, etc..). To run these on your local machine, type `grunt test` in your Terminal within the bootstrap-slider repository directory 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | *.bak* 3 | temp 4 | node_modules 5 | bower_components 6 | .grunt/* 7 | _SpecRunner.html 8 | npm-debug.log 9 | .DS_STORE 10 | index.html 11 | dist 12 | package-lock.json 13 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | temp 3 | node_modules 4 | bower_components 5 | .grunt/* 6 | _SpecRunner.html 7 | npm-debug.log 8 | .DS_STORE 9 | index.html -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14.17.0 2 | -------------------------------------------------------------------------------- /.sass-lint.yml: -------------------------------------------------------------------------------- 1 | ######################### 2 | ## Sass Lint File 3 | ######################### 4 | # Linter Options 5 | options: 6 | # Don't merge default rules 7 | merge-default-rules: false 8 | # Raise an error if more than 50 warnings are generated 9 | max-warnings: 50 10 | # File Options 11 | files: 12 | include: 'src/sass/**/*.s+(a|c)ss' 13 | # Rule Configuration 14 | rules: 15 | extends-before-mixins: 2 16 | extends-before-declarations: 2 17 | placeholder-in-extend: 2 18 | mixins-before-declarations: 19 | - 2 20 | - 21 | exclude: 22 | - breakpoint 23 | - mq 24 | 25 | no-warn: 1 26 | no-debug: 1 27 | no-ids: 2 28 | no-important: 2 29 | hex-notation: 30 | - 2 31 | - 32 | style: uppercase 33 | indentation: 34 | - 2 35 | - 36 | size: 2 37 | property-sort-order: 38 | - 1 39 | - 40 | order: 41 | - display 42 | - margin 43 | ignore-custom-properties: true -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "9.11.0" 4 | before_install: 5 | - npm install -g grunt-cli bower 6 | - npm install 7 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module:false*/ 2 | module.exports = function(grunt) { 3 | 4 | var packageJSON = grunt.file.readJSON('package.json'); 5 | var bumpFiles = ["package.json", "bower.json", "composer.json"]; 6 | var commitFiles = bumpFiles.concat(["./dist/*"]); 7 | 8 | // Project configuration. 9 | grunt.initConfig({ 10 | // Metadata 11 | pkg: packageJSON, 12 | // Task configuration. 13 | header: { 14 | dist: { 15 | options: { 16 | text: "/*! =======================================================\n VERSION <%= pkg.version %> \n========================================================= */" 17 | }, 18 | files: { 19 | '<%= pkg.gruntConfig.dist.js %>': '<%= pkg.gruntConfig.temp.js %>', 20 | '<%= pkg.gruntConfig.dist.jsMin %>': '<%= pkg.gruntConfig.temp.jsMin %>', 21 | '<%= pkg.gruntConfig.dist.css %>': '<%= pkg.gruntConfig.temp.css %>', 22 | '<%= pkg.gruntConfig.dist.cssMin %>': '<%= pkg.gruntConfig.temp.cssMin %>' 23 | } 24 | } 25 | }, 26 | uglify: { 27 | options: { 28 | preserveComments: 'some' 29 | }, 30 | dist: { 31 | src: '<%= pkg.gruntConfig.temp.js %>', 32 | dest: '<%= pkg.gruntConfig.temp.jsMin %>' 33 | } 34 | }, 35 | babel: { 36 | options: { 37 | presets: ['es2015'] 38 | }, 39 | dist: { 40 | src: '<%= pkg.gruntConfig.js.slider %>', 41 | dest: '<%= pkg.gruntConfig.temp.js %>' 42 | } 43 | }, 44 | jshint: { 45 | ignore_warning: { 46 | options: { 47 | '-W099': true 48 | }, 49 | src: '<%= pkg.gruntConfig.js.slider %>' 50 | }, 51 | options: { 52 | esnext: true, 53 | curly: true, 54 | eqeqeq: true, 55 | immed: true, 56 | latedef: false, 57 | newcap: true, 58 | noarg: true, 59 | sub: true, 60 | undef: true, 61 | unused: true, 62 | boss: true, 63 | eqnull: true, 64 | browser: true, 65 | globals: { 66 | $ : true, 67 | Modernizr : true, 68 | console: true, 69 | define: true, 70 | module: true, 71 | require: true 72 | }, 73 | "-W099": true 74 | }, 75 | gruntfile: { 76 | src: 'Gruntfile.js' 77 | }, 78 | js: { 79 | src: '<%= pkg.gruntConfig.js.slider %>' 80 | }, 81 | spec : { 82 | src: '<%= pkg.gruntConfig.spec %>', 83 | options : { 84 | globals : { 85 | document: true, 86 | console: false, 87 | Slider: false, 88 | $: false, 89 | jQuery: false, 90 | _: false, 91 | _V_: false, 92 | afterEach: false, 93 | beforeEach: false, 94 | confirm: false, 95 | context: false, 96 | describe: false, 97 | expect: false, 98 | it: false, 99 | jasmine: false, 100 | JSHINT: false, 101 | mostRecentAjaxRequest: false, 102 | qq: false, 103 | runs: false, 104 | spyOn: false, 105 | spyOnEvent: false, 106 | waitsFor: false, 107 | xdescribe: false 108 | } 109 | } 110 | } 111 | }, 112 | sasslint: { 113 | options: { 114 | configFile: './.sass-lint.yml', 115 | }, 116 | target: ['./src/sass/**/*.scss'] 117 | }, 118 | jasmine : { 119 | src : '<%= pkg.gruntConfig.temp.js %>', 120 | options : { 121 | specs : '<%= pkg.gruntConfig.spec %>', 122 | vendor : ['<%= pkg.gruntConfig.js.jquery %>', '<%= pkg.gruntConfig.js.popper %>', '<%= pkg.gruntConfig.js.bootstrap %>', '<%= pkg.gruntConfig.js.bindPolyfill %>'], 123 | styles : ['<%= pkg.gruntConfig.css.bootstrap %>', '<%= pkg.gruntConfig.temp.css %>'], 124 | template : '<%= pkg.gruntConfig.tpl.SpecRunner %>' 125 | } 126 | }, 127 | template : { 128 | 'generate-index-page' : { 129 | options : { 130 | data : { 131 | js : { 132 | highlightjs: '<%= pkg.gruntConfig.js.highlightjs %>', 133 | modernizr : '<%= pkg.gruntConfig.js.modernizr %>', 134 | jquery : '<%= pkg.gruntConfig.js.jquery %>', 135 | popper : '<%= pkg.gruntConfig.js.popper %>', 136 | bootstrap : '<%= pkg.gruntConfig.js.bootstrap %>', 137 | slider : '<%= pkg.gruntConfig.temp.js %>' 138 | }, 139 | css : { 140 | highlightjs: '<%= pkg.gruntConfig.css.highlightjs %>', 141 | bootstrap : '<%= pkg.gruntConfig.css.bootstrap %>', 142 | slider : '<%= pkg.gruntConfig.temp.css %>' 143 | } 144 | } 145 | }, 146 | files : { 147 | 'index.html' : ['<%= pkg.gruntConfig.tpl.index %>'] 148 | } 149 | }, 150 | 'generate-gh-pages' : { 151 | options : { 152 | data : { 153 | js : { 154 | highlightjs: '<%= pkg.gruntConfig.js.ghpages.highlightjs %>', 155 | modernizr : '<%= pkg.gruntConfig.js.ghpages.modernizr %>', 156 | jquery : '<%= pkg.gruntConfig.js.ghpages.jquery %>', 157 | popper : '<%= pkg.gruntConfig.js.ghpages.popper %>', 158 | bootstrap : '<%= pkg.gruntConfig.js.ghpages.bootstrap %>', 159 | slider : 'js/bootstrap-slider.js' 160 | }, 161 | css : { 162 | highlightjs: '<%= pkg.gruntConfig.css.highlightjs %>', 163 | bootstrap : 'css/bootstrap.min.css', 164 | slider : 'css/bootstrap-slider.css' 165 | } 166 | } 167 | }, 168 | files : { 169 | 'index.html' : ['<%= pkg.gruntConfig.tpl.index %>'] 170 | } 171 | } 172 | }, 173 | watch: { 174 | options: { 175 | livereload: true 176 | }, 177 | js: { 178 | files: '<%= pkg.gruntConfig.js.slider %>', 179 | tasks: ['jshint:js', 'babel', 'jasmine'] 180 | }, 181 | gruntfile: { 182 | files: '<%= jshint.gruntfile %>', 183 | tasks: ['jshint:gruntfile'] 184 | }, 185 | spec: { 186 | files: '<%= pkg.gruntConfig.spec %>', 187 | tasks: ['jshint:spec', 'jasmine:src'] 188 | }, 189 | css: { 190 | files: [ 191 | '<%= pkg.gruntConfig.sass.slider %>', 192 | '<%= pkg.gruntConfig.sass.variables %>', 193 | '<%= pkg.gruntConfig.sass.mixins %>', 194 | '<%= pkg.gruntConfig.sass.rules %>' 195 | ], 196 | tasks: ['sass:development'] 197 | }, 198 | index: { 199 | files: '<%= pkg.gruntConfig.tpl.index %>', 200 | tasks: ['template:generate-index-page'] 201 | } 202 | }, 203 | connect: { 204 | server: { 205 | options: { 206 | port: "<%= pkg.gruntConfig.devPort %>" 207 | } 208 | } 209 | }, 210 | open : { 211 | development : { 212 | path: 'http://localhost:<%= connect.server.options.port %>' 213 | } 214 | }, 215 | sass: { 216 | development: { 217 | options: { 218 | sourceMap: true, 219 | outputStyle: 'expanded' 220 | }, 221 | files: { 222 | '<%= pkg.gruntConfig.temp.css %>': '<%= pkg.gruntConfig.sass.slider %>' 223 | } 224 | }, 225 | production: { 226 | options: { 227 | sourceMap: true, 228 | outputStyle: 'expanded' 229 | }, 230 | files: { 231 | '<%= pkg.gruntConfig.temp.css %>': '<%= pkg.gruntConfig.sass.slider %>' 232 | } 233 | }, 234 | "production-min": { 235 | options: { 236 | sourceMap: true, 237 | outputStyle: 'compressed' 238 | }, 239 | files: { 240 | '<%= pkg.gruntConfig.temp.cssMin %>': '<%= pkg.gruntConfig.sass.slider %>' 241 | } 242 | } 243 | }, 244 | clean: { 245 | dist: ["dist"], 246 | temp: ["temp"] 247 | }, 248 | bump: { 249 | options: { 250 | files: bumpFiles, 251 | updateConfigs: [], 252 | commit: true, 253 | commitMessage: 'Release v%VERSION%', 254 | commitFiles: commitFiles, 255 | createTag: true, 256 | tagName: 'v%VERSION%', 257 | tagMessage: 'Version %VERSION%', 258 | push: false, 259 | pushTo: 'origin' 260 | } 261 | } 262 | }); 263 | 264 | // These plugins provide necessary tasks. 265 | grunt.loadNpmTasks('grunt-contrib-uglify'); 266 | grunt.loadNpmTasks('grunt-contrib-jshint'); 267 | grunt.loadNpmTasks('grunt-contrib-jasmine'); 268 | grunt.loadNpmTasks('grunt-contrib-watch'); 269 | grunt.loadNpmTasks('grunt-contrib-connect'); 270 | grunt.loadNpmTasks('grunt-contrib-clean'); 271 | grunt.loadNpmTasks('grunt-sass'); 272 | grunt.loadNpmTasks('grunt-open'); 273 | grunt.loadNpmTasks('grunt-template'); 274 | grunt.loadNpmTasks('grunt-header'); 275 | grunt.loadNpmTasks('grunt-bump'); 276 | grunt.loadNpmTasks('grunt-babel'); 277 | grunt.loadNpmTasks('grunt-sass-lint'); 278 | 279 | // Create custom tasks 280 | grunt.registerTask('append-header', ['header', 'clean:temp']); 281 | grunt.registerTask('lint', [ 282 | 'jshint', 283 | 'sasslint' 284 | ]); 285 | grunt.registerTask('test', [ 286 | 'babel', 287 | 'sass:development', 288 | 'jasmine', 289 | 'clean:temp' 290 | ]); 291 | grunt.registerTask('build', [ 292 | 'sass:development', 293 | 'test', 294 | 'template:generate-index-page' 295 | ]); 296 | grunt.registerTask('build-gh-pages', [ 297 | 'sass:development', 298 | 'babel', 299 | 'template:generate-gh-pages' 300 | ]); 301 | grunt.registerTask('dist', [ 302 | 'clean:dist', 303 | 'sass:production', 304 | 'sass:production-min', 305 | 'babel', 306 | 'uglify', 307 | 'append-header' 308 | ]); 309 | grunt.registerTask('development', [ 310 | 'sass:development', 311 | 'babel', 312 | 'template:generate-index-page', 313 | 'connect', 314 | 'open:development', 315 | 'watch' 316 | ]); 317 | grunt.registerTask('production', ['dist']); 318 | grunt.registerTask('dev', 'development'); 319 | grunt.registerTask('prod', 'production'); 320 | grunt.registerTask('default', ['build']); 321 | 322 | }; // End of module 323 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------- 2 | bootstrap-slider is released under the MIT License 3 | Copyright (c) 2019 Kyle Kemp, Rohit Kalkur, and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "seiyria-bootstrap-slider", 3 | "version": "11.0.3", 4 | "homepage": "https://github.com/seiyria/bootstrap-slider", 5 | "authors": [ 6 | "Kyle Kemp ", 7 | "Oleksii Kuznietsov ", 8 | "Rohit Kalkur " 9 | ], 10 | "description": "a slider element for bootstrap 4", 11 | "main": [ 12 | "dist/bootstrap-slider.js", 13 | "dist/css/bootstrap-slider.css" 14 | ], 15 | "keywords": [ 16 | "slider", 17 | "bootstrap4", 18 | "bootstrap" 19 | ], 20 | "license": "MIT", 21 | "ignore": [ 22 | "**/.*", 23 | "node_modules", 24 | "bower_components" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "seiyria/bootstrap-slider", 3 | "type": "library", 4 | "version": "11.0.3", 5 | "description": "A less buggy fork of the original bootstrap slider found on http://www.eyecon.ro/ by Stefan Petre. It was forked so we could update the slider since the original wasn't under version control.", 6 | "keywords": ["slider", "css", "bootstrap", "javascript"], 7 | "homepage": "https://github.com/seiyria/bootstrap-slider", 8 | "require": {}, 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Kyle Kemp", 13 | "email": "kyle@seiyria.com", 14 | "homepage": "http://seiyria.com", 15 | "role": "Developer" 16 | }, 17 | { 18 | "name": "Rohit Kalkur", 19 | "email": "rohit.kalkur@gmail.com", 20 | "homepage": "http://www.rovolutionary.com", 21 | "role": "Developer" 22 | }, 23 | { 24 | "name": "Oleksii Kuznietsov", 25 | "email": "utilmind@gmail.com", 26 | "homepage": "https://utilmind.com", 27 | "role": "Developer" 28 | }, 29 | { 30 | "name": "Lucas Zardo", 31 | "email": "lucas@deliverymuch.com.br", 32 | "homepage": "https://deliverymuch.com.br", 33 | "role": "Packagist Editor" 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /dependencies/css/highlightjs-github-theme.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;overflow-x:auto;padding:0.5em;color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:bold}.hljs-number,.hljs-literal,.hljs-variable,.hljs-template-variable,.hljs-tag .hljs-attr{color:#008080}.hljs-string,.hljs-doctag{color:#d14}.hljs-title,.hljs-section,.hljs-selector-id{color:#900;font-weight:bold}.hljs-subst{font-weight:normal}.hljs-type,.hljs-class .hljs-title{color:#458;font-weight:bold}.hljs-tag,.hljs-name,.hljs-attribute{color:#000080;font-weight:normal}.hljs-regexp,.hljs-link{color:#009926}.hljs-symbol,.hljs-bullet{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:bold}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold} -------------------------------------------------------------------------------- /dist/css/bootstrap-slider.css: -------------------------------------------------------------------------------- 1 | /*! ======================================================= 2 | VERSION 11.0.3 3 | ========================================================= */ 4 | /*! ========================================================= 5 | * bootstrap-slider.js 6 | * 7 | * Maintainers: 8 | * Kyle Kemp 9 | * - Twitter: @seiyria 10 | * - Github: seiyria 11 | * Rohit Kalkur 12 | * - Twitter: @Rovolutionary 13 | * - Github: rovolution 14 | * 15 | * ========================================================= 16 | * 17 | * bootstrap-slider is released under the MIT License 18 | * Copyright (c) 2019 Kyle Kemp, Rohit Kalkur, and contributors 19 | * 20 | * Permission is hereby granted, free of charge, to any person 21 | * obtaining a copy of this software and associated documentation 22 | * files (the "Software"), to deal in the Software without 23 | * restriction, including without limitation the rights to use, 24 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | * copies of the Software, and to permit persons to whom the 26 | * Software is furnished to do so, subject to the following 27 | * conditions: 28 | * 29 | * The above copyright notice and this permission notice shall be 30 | * included in all copies or substantial portions of the Software. 31 | * 32 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 33 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 34 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 35 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 36 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 37 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 38 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 39 | * OTHER DEALINGS IN THE SOFTWARE. 40 | * 41 | * ========================================================= */ 42 | .slider { 43 | display: inline-block; 44 | vertical-align: middle; 45 | position: relative; 46 | } 47 | 48 | .slider.slider-horizontal { 49 | width: 210px; 50 | height: 20px; 51 | } 52 | 53 | .slider.slider-horizontal .slider-track { 54 | height: 10px; 55 | width: 100%; 56 | margin-top: -5px; 57 | top: 50%; 58 | left: 0; 59 | } 60 | 61 | .slider.slider-horizontal .slider-selection, .slider.slider-horizontal .slider-track-low, .slider.slider-horizontal .slider-track-high { 62 | height: 100%; 63 | top: 0; 64 | bottom: 0; 65 | } 66 | 67 | .slider.slider-horizontal .slider-tick, 68 | .slider.slider-horizontal .slider-handle { 69 | margin-left: -10px; 70 | } 71 | 72 | .slider.slider-horizontal .slider-tick.triangle, 73 | .slider.slider-horizontal .slider-handle.triangle { 74 | position: relative; 75 | top: 50%; 76 | transform: translateY(-50%); 77 | border-width: 0 10px 10px 10px; 78 | width: 0; 79 | height: 0; 80 | border-bottom-color: #036fa5; 81 | margin-top: 0; 82 | } 83 | 84 | .slider.slider-horizontal .slider-tick-container { 85 | white-space: nowrap; 86 | position: absolute; 87 | top: 0; 88 | left: 0; 89 | width: 100%; 90 | } 91 | 92 | .slider.slider-horizontal .slider-tick-label-container { 93 | white-space: nowrap; 94 | margin-top: 20px; 95 | } 96 | 97 | .slider.slider-horizontal .slider-tick-label-container .slider-tick-label { 98 | display: inline-block; 99 | text-align: center; 100 | } 101 | 102 | .slider.slider-horizontal.slider-rtl .slider-track { 103 | left: initial; 104 | right: 0; 105 | } 106 | 107 | .slider.slider-horizontal.slider-rtl .slider-tick, 108 | .slider.slider-horizontal.slider-rtl .slider-handle { 109 | margin-left: initial; 110 | margin-right: -10px; 111 | } 112 | 113 | .slider.slider-horizontal.slider-rtl .slider-tick-container { 114 | left: initial; 115 | right: 0; 116 | } 117 | 118 | .slider.slider-vertical { 119 | height: 210px; 120 | width: 20px; 121 | } 122 | 123 | .slider.slider-vertical .slider-track { 124 | width: 10px; 125 | height: 100%; 126 | left: 25%; 127 | top: 0; 128 | } 129 | 130 | .slider.slider-vertical .slider-selection { 131 | width: 100%; 132 | left: 0; 133 | top: 0; 134 | bottom: 0; 135 | } 136 | 137 | .slider.slider-vertical .slider-track-low, .slider.slider-vertical .slider-track-high { 138 | width: 100%; 139 | left: 0; 140 | right: 0; 141 | } 142 | 143 | .slider.slider-vertical .slider-tick, 144 | .slider.slider-vertical .slider-handle { 145 | margin-top: -10px; 146 | } 147 | 148 | .slider.slider-vertical .slider-tick.triangle, 149 | .slider.slider-vertical .slider-handle.triangle { 150 | border-width: 10px 0 10px 10px; 151 | width: 1px; 152 | height: 1px; 153 | border-left-color: #036fa5; 154 | margin-left: 0; 155 | } 156 | 157 | .slider.slider-vertical .slider-tick-label-container { 158 | white-space: nowrap; 159 | } 160 | 161 | .slider.slider-vertical .slider-tick-label-container .slider-tick-label { 162 | padding-left: 4px; 163 | } 164 | 165 | .slider.slider-vertical.slider-rtl .slider-track { 166 | left: initial; 167 | right: 25%; 168 | } 169 | 170 | .slider.slider-vertical.slider-rtl .slider-selection { 171 | left: initial; 172 | right: 0; 173 | } 174 | 175 | .slider.slider-vertical.slider-rtl .slider-tick.triangle, 176 | .slider.slider-vertical.slider-rtl .slider-handle.triangle { 177 | border-width: 10px 10px 10px 0; 178 | } 179 | 180 | .slider.slider-vertical.slider-rtl .slider-tick-label-container .slider-tick-label { 181 | padding-left: initial; 182 | padding-right: 4px; 183 | } 184 | 185 | .slider.slider-disabled .slider-handle { 186 | background-color: #cfcfcf; 187 | background-image: linear-gradient(to bottom, #DFDFDF, #BEBEBE); 188 | background-repeat: repeat-x; 189 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#DFDFDF', endColorstr='#BEBEBE', GradientType=0); 190 | } 191 | 192 | .slider.slider-disabled .slider-track { 193 | background-color: #e7e7e7; 194 | background-image: linear-gradient(to bottom, #E5E5E5, #E9E9E9); 195 | background-repeat: repeat-x; 196 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#E5E5E5', endColorstr='#E9E9E9', GradientType=0); 197 | cursor: not-allowed; 198 | } 199 | 200 | .slider input { 201 | display: none; 202 | } 203 | 204 | .slider .tooltip-inner { 205 | white-space: nowrap; 206 | max-width: none; 207 | } 208 | 209 | .slider .bs-tooltip-top .tooltip-inner, 210 | .slider .bs-tooltip-bottom .tooltip-inner { 211 | position: relative; 212 | left: -50%; 213 | } 214 | 215 | .slider.bs-tooltip-left .tooltip-inner, .slider.bs-tooltip-right .tooltip-inner { 216 | position: relative; 217 | top: -100%; 218 | } 219 | 220 | .slider .tooltip { 221 | pointer-events: none; 222 | } 223 | 224 | .slider .tooltip.bs-tooltip-top .arrow, .slider .tooltip.bs-tooltip-bottom .arrow { 225 | left: -.4rem; 226 | } 227 | 228 | .slider .tooltip.bs-tooltip-top { 229 | margin-top: -44px; 230 | } 231 | 232 | .slider .tooltip.bs-tooltip-bottom { 233 | margin-top: 2px; 234 | } 235 | 236 | .slider .tooltip.bs-tooltip-left, .slider .tooltip.bs-tooltip-right { 237 | margin-top: -14px; 238 | } 239 | 240 | .slider .tooltip.bs-tooltip-left .arrow, .slider .tooltip.bs-tooltip-right .arrow { 241 | top: 8px; 242 | } 243 | 244 | .slider .hide { 245 | display: none; 246 | } 247 | 248 | .slider-track { 249 | background-color: #f7f7f7; 250 | background-image: linear-gradient(to bottom, #F5F5F5, #F9F9F9); 251 | background-repeat: repeat-x; 252 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F5F5F5', endColorstr='#F9F9F9', GradientType=0); 253 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); 254 | border-radius: 4px; 255 | position: absolute; 256 | cursor: pointer; 257 | } 258 | 259 | .slider-selection { 260 | background-color: #f7f7f7; 261 | background-image: linear-gradient(to bottom, #F9F9F9, #F5F5F5); 262 | background-repeat: repeat-x; 263 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F9F9F9', endColorstr='#F5F5F5', GradientType=0); 264 | box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); 265 | box-sizing: border-box; 266 | border-radius: 4px; 267 | position: absolute; 268 | } 269 | 270 | .slider-selection.tick-slider-selection { 271 | background-color: #46c1fe; 272 | background-image: linear-gradient(to bottom, #52c5ff, #3abcfd); 273 | background-repeat: repeat-x; 274 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#52c5ff', endColorstr='#3abcfd', GradientType=0); 275 | } 276 | 277 | .slider-track-low, .slider-track-high { 278 | box-sizing: border-box; 279 | border-radius: 4px; 280 | position: absolute; 281 | background: transparent; 282 | } 283 | 284 | .slider-handle { 285 | background-color: #0478b2; 286 | background-image: linear-gradient(to bottom, #0480BE, #036fa5); 287 | background-repeat: repeat-x; 288 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0480BE', endColorstr='#036fa5', GradientType=0); 289 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 290 | position: absolute; 291 | top: 0; 292 | width: 20px; 293 | height: 20px; 294 | background-color: #0480BE; 295 | border: 0px solid transparent; 296 | } 297 | 298 | .slider-handle:hover { 299 | cursor: pointer; 300 | } 301 | 302 | .slider-handle.round { 303 | border-radius: 20px; 304 | } 305 | 306 | .slider-handle.triangle { 307 | background: transparent none; 308 | } 309 | 310 | .slider-handle.custom { 311 | background: transparent none; 312 | } 313 | 314 | .slider-handle.custom::before { 315 | line-height: 20px; 316 | font-size: 20px; 317 | content: '\2605'; 318 | color: #726204; 319 | } 320 | 321 | .slider-tick { 322 | background-color: #f7f7f7; 323 | background-image: linear-gradient(to bottom, #F5F5F5, #F9F9F9); 324 | background-repeat: repeat-x; 325 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F5F5F5', endColorstr='#F9F9F9', GradientType=0); 326 | box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); 327 | box-sizing: border-box; 328 | position: absolute; 329 | cursor: pointer; 330 | width: 20px; 331 | height: 20px; 332 | filter: none; 333 | opacity: 0.8; 334 | border: 0px solid transparent; 335 | } 336 | 337 | .slider-tick.round { 338 | border-radius: 50%; 339 | } 340 | 341 | .slider-tick.triangle { 342 | background: transparent none; 343 | } 344 | 345 | .slider-tick.custom { 346 | background: transparent none; 347 | } 348 | 349 | .slider-tick.custom::before { 350 | line-height: 20px; 351 | font-size: 20px; 352 | content: '\2605'; 353 | color: #726204; 354 | } 355 | 356 | .slider-tick.in-selection { 357 | background-color: #46c1fe; 358 | background-image: linear-gradient(to bottom, #52c5ff, #3abcfd); 359 | background-repeat: repeat-x; 360 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#52c5ff', endColorstr='#3abcfd', GradientType=0); 361 | opacity: 1; 362 | } 363 | 364 | /*# sourceMappingURL=bootstrap-slider.css.map */ -------------------------------------------------------------------------------- /dist/css/bootstrap-slider.min.css: -------------------------------------------------------------------------------- 1 | /*! ======================================================= 2 | VERSION 11.0.3 3 | ========================================================= */ 4 | /*! ========================================================= 5 | * bootstrap-slider.js 6 | * 7 | * Maintainers: 8 | * Kyle Kemp 9 | * - Twitter: @seiyria 10 | * - Github: seiyria 11 | * Rohit Kalkur 12 | * - Twitter: @Rovolutionary 13 | * - Github: rovolution 14 | * 15 | * ========================================================= 16 | * 17 | * bootstrap-slider is released under the MIT License 18 | * Copyright (c) 2019 Kyle Kemp, Rohit Kalkur, and contributors 19 | * 20 | * Permission is hereby granted, free of charge, to any person 21 | * obtaining a copy of this software and associated documentation 22 | * files (the "Software"), to deal in the Software without 23 | * restriction, including without limitation the rights to use, 24 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | * copies of the Software, and to permit persons to whom the 26 | * Software is furnished to do so, subject to the following 27 | * conditions: 28 | * 29 | * The above copyright notice and this permission notice shall be 30 | * included in all copies or substantial portions of the Software. 31 | * 32 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 33 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 34 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 35 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 36 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 37 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 38 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 39 | * OTHER DEALINGS IN THE SOFTWARE. 40 | * 41 | * ========================================================= */.slider{display:inline-block;vertical-align:middle;position:relative}.slider.slider-horizontal{width:210px;height:20px}.slider.slider-horizontal .slider-track{height:10px;width:100%;margin-top:-5px;top:50%;left:0}.slider.slider-horizontal .slider-selection,.slider.slider-horizontal .slider-track-low,.slider.slider-horizontal .slider-track-high{height:100%;top:0;bottom:0}.slider.slider-horizontal .slider-tick,.slider.slider-horizontal .slider-handle{margin-left:-10px}.slider.slider-horizontal .slider-tick.triangle,.slider.slider-horizontal .slider-handle.triangle{position:relative;top:50%;transform:translateY(-50%);border-width:0 10px 10px 10px;width:0;height:0;border-bottom-color:#036fa5;margin-top:0}.slider.slider-horizontal .slider-tick-container{white-space:nowrap;position:absolute;top:0;left:0;width:100%}.slider.slider-horizontal .slider-tick-label-container{white-space:nowrap;margin-top:20px}.slider.slider-horizontal .slider-tick-label-container .slider-tick-label{display:inline-block;text-align:center}.slider.slider-horizontal.slider-rtl .slider-track{left:initial;right:0}.slider.slider-horizontal.slider-rtl .slider-tick,.slider.slider-horizontal.slider-rtl .slider-handle{margin-left:initial;margin-right:-10px}.slider.slider-horizontal.slider-rtl .slider-tick-container{left:initial;right:0}.slider.slider-vertical{height:210px;width:20px}.slider.slider-vertical .slider-track{width:10px;height:100%;left:25%;top:0}.slider.slider-vertical .slider-selection{width:100%;left:0;top:0;bottom:0}.slider.slider-vertical .slider-track-low,.slider.slider-vertical .slider-track-high{width:100%;left:0;right:0}.slider.slider-vertical .slider-tick,.slider.slider-vertical .slider-handle{margin-top:-10px}.slider.slider-vertical .slider-tick.triangle,.slider.slider-vertical .slider-handle.triangle{border-width:10px 0 10px 10px;width:1px;height:1px;border-left-color:#036fa5;margin-left:0}.slider.slider-vertical .slider-tick-label-container{white-space:nowrap}.slider.slider-vertical .slider-tick-label-container .slider-tick-label{padding-left:4px}.slider.slider-vertical.slider-rtl .slider-track{left:initial;right:25%}.slider.slider-vertical.slider-rtl .slider-selection{left:initial;right:0}.slider.slider-vertical.slider-rtl .slider-tick.triangle,.slider.slider-vertical.slider-rtl .slider-handle.triangle{border-width:10px 10px 10px 0}.slider.slider-vertical.slider-rtl .slider-tick-label-container .slider-tick-label{padding-left:initial;padding-right:4px}.slider.slider-disabled .slider-handle{background-color:#cfcfcf;background-image:linear-gradient(to bottom, #DFDFDF, #BEBEBE);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#DFDFDF', endColorstr='#BEBEBE', GradientType=0)}.slider.slider-disabled .slider-track{background-color:#e7e7e7;background-image:linear-gradient(to bottom, #E5E5E5, #E9E9E9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#E5E5E5', endColorstr='#E9E9E9', GradientType=0);cursor:not-allowed}.slider input{display:none}.slider .tooltip-inner{white-space:nowrap;max-width:none}.slider .bs-tooltip-top .tooltip-inner,.slider .bs-tooltip-bottom .tooltip-inner{position:relative;left:-50%}.slider.bs-tooltip-left .tooltip-inner,.slider.bs-tooltip-right .tooltip-inner{position:relative;top:-100%}.slider .tooltip{pointer-events:none}.slider .tooltip.bs-tooltip-top .arrow,.slider .tooltip.bs-tooltip-bottom .arrow{left:-.4rem}.slider .tooltip.bs-tooltip-top{margin-top:-44px}.slider .tooltip.bs-tooltip-bottom{margin-top:2px}.slider .tooltip.bs-tooltip-left,.slider .tooltip.bs-tooltip-right{margin-top:-14px}.slider .tooltip.bs-tooltip-left .arrow,.slider .tooltip.bs-tooltip-right .arrow{top:8px}.slider .hide{display:none}.slider-track{background-color:#f7f7f7;background-image:linear-gradient(to bottom, #f5f5f5, #F9F9F9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#F9F9F9', GradientType=0);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);border-radius:4px;position:absolute;cursor:pointer}.slider-selection{background-color:#f7f7f7;background-image:linear-gradient(to bottom, #F9F9F9, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#F9F9F9', endColorstr='#f5f5f5', GradientType=0);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-sizing:border-box;border-radius:4px;position:absolute}.slider-selection.tick-slider-selection{background-color:#46c1fe;background-image:linear-gradient(to bottom, #52c5ff, #3abcfd);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#52c5ff', endColorstr='#3abcfd', GradientType=0)}.slider-track-low,.slider-track-high{box-sizing:border-box;border-radius:4px;position:absolute;background:transparent}.slider-handle{background-color:#0478b2;background-image:linear-gradient(to bottom, #0480BE, #036fa5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0480BE', endColorstr='#036fa5', GradientType=0);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);position:absolute;top:0;width:20px;height:20px;background-color:#0480BE;border:0px solid transparent}.slider-handle:hover{cursor:pointer}.slider-handle.round{border-radius:20px}.slider-handle.triangle{background:transparent none}.slider-handle.custom{background:transparent none}.slider-handle.custom::before{line-height:20px;font-size:20px;content:'\2605';color:#726204}.slider-tick{background-color:#f7f7f7;background-image:linear-gradient(to bottom, #f5f5f5, #F9F9F9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#F9F9F9', GradientType=0);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-sizing:border-box;position:absolute;cursor:pointer;width:20px;height:20px;filter:none;opacity:0.8;border:0px solid transparent}.slider-tick.round{border-radius:50%}.slider-tick.triangle{background:transparent none}.slider-tick.custom{background:transparent none}.slider-tick.custom::before{line-height:20px;font-size:20px;content:'\2605';color:#726204}.slider-tick.in-selection{background-color:#46c1fe;background-image:linear-gradient(to bottom, #52c5ff, #3abcfd);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#52c5ff', endColorstr='#3abcfd', GradientType=0);opacity:1} 42 | 43 | /*# sourceMappingURL=bootstrap-slider.min.css.map */ -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap-slider", 3 | "version": "11.0.3", 4 | "description": "Slider view component for Twitter Bootstrap.", 5 | "main": "dist/bootstrap-slider.js", 6 | "style": "dist/css/bootstrap-slider.css", 7 | "scripts": { 8 | "pretest": "grunt lint", 9 | "test": "grunt test", 10 | "release": "sh ./scripts/release.sh", 11 | "update-gh-pages": "sh ./scripts/update-gh-pages.sh" 12 | }, 13 | "homepage": "http://github.com/seiyria/bootstrap-slider", 14 | "repository": { 15 | "type": "git", 16 | "url": "git://github.com/seiyria/bootstrap-slider.git" 17 | }, 18 | "bugs": { 19 | "url": "http://github.com/seiyria/bootstrap-slider/issues" 20 | }, 21 | "author": "bootstrap-slider ", 22 | "contributors": [ 23 | { 24 | "name": "Kyle Kemp", 25 | "twitter": "@seiyria", 26 | "github": "seiyria" 27 | }, 28 | { 29 | "name": "Rohit Kalkur", 30 | "twitter": "@Rovolutionary", 31 | "github": "rovolution" 32 | }, 33 | { 34 | "name": "Oleksii Kuznietsov", 35 | "twitter": "@utilmind", 36 | "github": "utilmind" 37 | } 38 | ], 39 | "keywords": [ 40 | "slider", 41 | "bootstrap", 42 | "twitter", 43 | "slide" 44 | ], 45 | "license": "MIT", 46 | "readmeFilename": "README.md", 47 | "gitHead": "67eb8fe3c26205efc94ae95b3ef37a469eef0b81", 48 | "dependencies": {}, 49 | "engines": { 50 | "node": ">=14.17.0" 51 | }, 52 | "devDependencies": { 53 | "babel-preset-es2015": "6.3.13", 54 | "bootstrap": "^4.1.1", 55 | "grunt": "^0.4.5", 56 | "grunt-babel": "6.0.0", 57 | "grunt-bump": "0.0.16", 58 | "grunt-cli": "^1.3.2", 59 | "grunt-contrib-clean": "0.6.0", 60 | "grunt-contrib-connect": "0.5.0", 61 | "grunt-contrib-jasmine": "1.0.3", 62 | "grunt-contrib-jshint": "0.11.3", 63 | "grunt-contrib-uglify": "0.2.4", 64 | "grunt-contrib-watch": "0.5.3", 65 | "grunt-header": "1.0.0", 66 | "grunt-open": "0.2.2", 67 | "grunt-sass": "^2.1.0", 68 | "grunt-sass-lint": "^0.2.2", 69 | "grunt-template": "0.2.0", 70 | "jquery": "1.9.1 - 3", 71 | "node-sass": "^4.9.0", 72 | "popper.js": "^1.14.3" 73 | }, 74 | "gruntConfig": { 75 | "devPort": 9000, 76 | "js": { 77 | "highlightjs": "dependencies/js/highlight.min.js", 78 | "modernizr": "dependencies/js/modernizr.js", 79 | "jquery": "node_modules/jquery/dist/jquery.min.js", 80 | "popper": "node_modules/popper.js/dist/umd/popper.min.js", 81 | "bootstrap": "node_modules/bootstrap/dist/js/bootstrap.min.js", 82 | "bindPolyfill": "test/phantom_bind_polyfill.js", 83 | "slider": "src/js/bootstrap-slider.js", 84 | "ghpages": { 85 | "highlightjs": "dependencies/js/highlight.min.js", 86 | "modernizr": "dependencies/js/modernizr.js", 87 | "jquery": "dependencies/js/jquery.min.js", 88 | "popper": "dependencies/js/popper.min.js", 89 | "bootstrap": "dependencies/js/bootstrap.min.js", 90 | "bindPolyfill": "test/phantom_bind_polyfill.js", 91 | "slider": "src/js/bootstrap-slider.js" 92 | } 93 | }, 94 | "sass": { 95 | "slider": "src/sass/bootstrap-slider.scss", 96 | "variables": "src/sass/_variables.scss", 97 | "mixins": "src/sass/_mixins.scss", 98 | "rules": "src/sass/_rules.scss" 99 | }, 100 | "css": { 101 | "bootstrap": "node_modules/bootstrap/dist/css/bootstrap.min.css", 102 | "highlightjs": "dependencies/css/highlightjs-github-theme.css" 103 | }, 104 | "tpl": { 105 | "SpecRunner": "tpl/SpecRunner.tpl", 106 | "index": "tpl/index.tpl" 107 | }, 108 | "temp": { 109 | "js": "temp/bootstrap-slider.js", 110 | "jsMin": "temp/bootstrap-slider.min.js", 111 | "css": "temp/bootstrap-slider.css", 112 | "cssMin": "temp/bootstrap-slider.min.css" 113 | }, 114 | "dist": { 115 | "js": "dist/bootstrap-slider.js", 116 | "jsMin": "dist/bootstrap-slider.min.js", 117 | "css": "dist/css/bootstrap-slider.css", 118 | "cssMin": "dist/css/bootstrap-slider.min.css" 119 | }, 120 | "spec": "test/specs/**/*.js" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /scripts/build-preview.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # this is run by netlify. there is no need to run this manually. 4 | 5 | # log 6 | # Generate index.html and /temp assets for GH Pages branch 7 | npm i 8 | grunt build 9 | grunt build-gh-pages 10 | 11 | mkdir css 12 | mkdir js 13 | 14 | cp node_modules/bootstrap/dist/css/bootstrap.min.css css/bootstrap.min.css 15 | mv temp/bootstrap-slider.css css/bootstrap-slider.css 16 | mv temp/bootstrap-slider.js js/bootstrap-slider.js -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if required CLI tools are available 4 | if ! [ -x "$(command -v grunt)" ]; then 5 | echo "Error: grunt-cli is not installed. Please type 'npm install grunt-cli -g' to install" >&2 6 | exit 1 7 | fi 8 | 9 | # Validate arguments 10 | versionBumpType=${1:-patch}; 11 | 12 | if [ "$versionBumpType" != "major" ] && [ "$versionBumpType" != "minor" ] && [ "$versionBumpType" != "patch" ]; then 13 | echo "Invalid version bump argument: ${versionBumpType}. Option must be one of the following: major, minor, patch" >&2 14 | exit 1 15 | else 16 | echo "Publishing and bumping with ${versionBumpType} version bump" 17 | fi 18 | 19 | echo "Running version bump + publish script..." 20 | echo "." 21 | echo "." 22 | echo "Generating /dist and push changes + tags to Github remote 'origin'" 23 | # Checkout master branch 24 | git checkout master 25 | # Version bump 26 | grunt bump-only:"$versionBumpType" 27 | # Generate new dist 28 | grunt prod 29 | # Generate new index.html page 30 | grunt template 31 | # Force add dist contents 32 | git add dist/* --force 33 | # Commit new release tag 34 | grunt bump-commit 35 | # Push commits/tags to master branch on remote 'origin' 36 | git push origin master:master && git push --tags 37 | 38 | ## Update Github.io page 39 | sh ./scripts/update-gh-pages.sh 40 | 41 | ## Publish to NPM 42 | echo "." 43 | echo "." 44 | echo "Publishing to NPM" 45 | echo "." 46 | echo "." 47 | npm publish 48 | 49 | # Notify script is complete 50 | echo "." 51 | echo "." 52 | echo "Script complete" 53 | echo "" -------------------------------------------------------------------------------- /scripts/update-gh-pages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # log 4 | echo "..." 5 | echo "Updating Github.io page" 6 | echo "..." 7 | # Generate index.html and /temp assets for GH Pages branch 8 | grunt build-gh-pages 9 | # Create temporary copy of index file 10 | cp index.html index-temp.html 11 | # Checkout to `gh-pages` branch 12 | git checkout -B gh-pages origin/gh-pages 13 | git pull -r origin gh-pages 14 | # Update dependencies 15 | cp node_modules/jquery/dist/jquery.min.js dependencies/js/jquery.min.js 16 | cp node_modules/popper.js/dist/umd/popper.min.js dependencies/js/popper.min.js 17 | cp node_modules/bootstrap/dist/js/bootstrap.min.js dependencies/js/bootstrap.min.js 18 | # Replace current files with temporary files 19 | mv index-temp.html index.html 20 | cp node_modules/bootstrap/dist/css/bootstrap.min.css css/bootstrap.min.css 21 | mv temp/bootstrap-slider.css css/bootstrap-slider.css 22 | mv temp/bootstrap-slider.js js/bootstrap-slider.js 23 | # Remove /temp directory 24 | rm -rf temp 25 | # Stage new files for commit 26 | git add index.html css/bootstrap-slider.css js/bootstrap-slider.js css/bootstrap.min.css dependencies/* 27 | # Create commit with new files 28 | git commit -m "updates" 29 | # Push new source code to gh-pages branch 30 | git push origin gh-pages:gh-pages -f 31 | # Switch back to master branch 32 | git checkout master 33 | # log 34 | echo "..." 35 | echo "Github.io page updated" 36 | echo "..." 37 | -------------------------------------------------------------------------------- /src/sass/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin slider-background-image($colorstart: #F5F5F5, $colorend: #F9F9F9, $backcolor: #F7F7F7) { 2 | background-color: $backcolor; 3 | background-image: linear-gradient(to bottom, $colorstart, $colorend); 4 | background-repeat: repeat-x; 5 | // Fallback for IE9 and below 6 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$colorstart}', endColorstr='#{$colorend}', GradientType=0); 7 | } 8 | 9 | @mixin slider-box-sizing($value) { 10 | box-sizing: $value; 11 | } 12 | 13 | @mixin slider-box-shadow($value...) { 14 | box-shadow: $value; 15 | } 16 | 17 | @mixin slider-border-radius($value) { 18 | border-radius: $value; 19 | } 20 | -------------------------------------------------------------------------------- /src/sass/_rules.scss: -------------------------------------------------------------------------------- 1 | .slider { 2 | display: inline-block; 3 | vertical-align: middle; 4 | position: relative; 5 | &.slider-horizontal { 6 | width: $slider-horizontal-width; 7 | height: $slider-line-height; 8 | .slider-track { 9 | height: $slider-line-height/2; 10 | width: 100%; 11 | margin-top: -$slider-line-height/4; 12 | top: 50%; 13 | left: 0; 14 | } 15 | .slider-selection, .slider-track-low, .slider-track-high { 16 | height: 100%; 17 | top: 0; 18 | bottom: 0; 19 | } 20 | .slider-tick, 21 | .slider-handle { 22 | margin-left: -$slider-line-height/2; 23 | &.triangle { 24 | position: relative; 25 | top: 50%; 26 | transform: translateY(-50%); 27 | border-width: 0 $slider-line-height/2 $slider-line-height/2 $slider-line-height/2; 28 | width: 0; 29 | height: 0; 30 | border-bottom-color: $slider-primary-bottom; 31 | margin-top: 0; 32 | } 33 | } 34 | .slider-tick-container { 35 | white-space: nowrap; 36 | position: absolute; 37 | top: 0; 38 | left: 0; 39 | width: 100%; 40 | } 41 | .slider-tick-label-container { 42 | white-space: nowrap; 43 | margin-top: $slider-line-height; 44 | .slider-tick-label { 45 | display: inline-block; 46 | text-align: center; 47 | } 48 | } 49 | &.slider-rtl { 50 | .slider-track { 51 | left: initial; 52 | right: 0; 53 | } 54 | .slider-tick, 55 | .slider-handle { 56 | margin-left: initial; 57 | margin-right: -$slider-line-height/2; 58 | } 59 | .slider-tick-container { 60 | left: initial; 61 | right: 0; 62 | } 63 | } 64 | } 65 | &.slider-vertical { 66 | height: $slider-vertical-height; 67 | width: $slider-line-height; 68 | .slider-track { 69 | width: $slider-line-height/2; 70 | height: 100%; 71 | left: 25%; 72 | top: 0; 73 | } 74 | .slider-selection { 75 | width: 100%; 76 | left: 0; 77 | top: 0; 78 | bottom: 0; 79 | } 80 | .slider-track-low, .slider-track-high { 81 | width: 100%; 82 | left: 0; 83 | right: 0; 84 | } 85 | .slider-tick, 86 | .slider-handle { 87 | margin-top: -$slider-line-height/2; 88 | &.triangle { 89 | border-width: $slider-line-height/2 0 $slider-line-height/2 $slider-line-height/2; 90 | width: 1px; 91 | height: 1px; 92 | border-left-color: $slider-primary-bottom; 93 | margin-left: 0; 94 | } 95 | } 96 | .slider-tick-label-container { 97 | white-space: nowrap; 98 | .slider-tick-label { 99 | padding-left: $slider-line-height * .2; 100 | } 101 | } 102 | &.slider-rtl { 103 | .slider-track { 104 | left: initial; 105 | right: 25%; 106 | } 107 | .slider-selection { 108 | left: initial; 109 | right: 0; 110 | } 111 | .slider-tick, 112 | .slider-handle { 113 | &.triangle { 114 | border-width: $slider-line-height/2 $slider-line-height/2 $slider-line-height/2 0; 115 | } 116 | } 117 | .slider-tick-label-container { 118 | .slider-tick-label { 119 | padding-left: initial; 120 | padding-right: $slider-line-height * .2; 121 | } 122 | } 123 | } 124 | } 125 | &.slider-disabled { 126 | .slider-handle { 127 | @include slider_background-image($slider-gray-2, $slider-gray-1, $slider-handle-background-color-disabled); 128 | } 129 | .slider-track { 130 | @include slider_background-image($slider-gray-3, $slider-gray-4, $slider-track-background-color-disabled); 131 | cursor: not-allowed; 132 | } 133 | } 134 | input { 135 | display: none; 136 | } 137 | .tooltip-inner { 138 | white-space: nowrap; 139 | max-width: none; 140 | } 141 | .bs-tooltip-top, 142 | .bs-tooltip-bottom { 143 | .tooltip-inner { 144 | position: relative; 145 | left: -50%; 146 | } 147 | } 148 | &.bs-tooltip-left, 149 | &.bs-tooltip-right { 150 | .tooltip-inner { 151 | position: relative; 152 | top: -100%; 153 | } 154 | } 155 | 156 | .tooltip { 157 | pointer-events: none; 158 | 159 | &.bs-tooltip-top, 160 | &.bs-tooltip-bottom { 161 | .arrow { 162 | left: -.4rem; // $tooltip-arrow-width / 2. 163 | } 164 | } 165 | &.bs-tooltip-top { 166 | margin-top: -44px; 167 | } 168 | &.bs-tooltip-bottom { 169 | margin-top: 2px; 170 | } 171 | &.bs-tooltip-left, 172 | &.bs-tooltip-right { 173 | margin-top: -14px; 174 | .arrow { 175 | top: 8px; 176 | } 177 | } 178 | } 179 | .hide { 180 | display: none; 181 | } 182 | } 183 | 184 | .slider-track { 185 | @include slider_background-image($slider-gray-5, $slider-gray-6, $slider-track-background-color); 186 | @include slider_box-shadow(inset 0 1px 2px rgba(0,0,0,0.1)); 187 | @include slider_border-radius($slider-border-radius); 188 | 189 | position: absolute; 190 | cursor: pointer; 191 | } 192 | 193 | .slider-selection { 194 | @include slider_background-image($slider-gray-6, $slider-gray-5, $slider-selection-background-color); 195 | @include slider_box-shadow(inset 0 -1px 0 rgba(0,0,0,0.15)); 196 | @include slider_box-sizing(border-box); 197 | @include slider_border-radius($slider-border-radius); 198 | 199 | position: absolute; 200 | } 201 | .slider-selection.tick-slider-selection { 202 | @include slider_background-image($slider-secondary-top, $slider-secondary-bottom, $slider-selection-tick-background-color); 203 | } 204 | 205 | .slider-track-low, .slider-track-high { 206 | @include slider_box-sizing(border-box); 207 | @include slider_border-radius($slider-border-radius); 208 | 209 | position: absolute; 210 | background: transparent; 211 | } 212 | 213 | .slider-handle { 214 | @include slider_background-image($slider-primary-top, $slider-primary-bottom, $slider-handle-background-color); 215 | @include slider_box-shadow(inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05)); 216 | 217 | position: absolute; 218 | top: 0; 219 | width: $slider-line-height; 220 | height: $slider-line-height; 221 | background-color: $slider-primary; 222 | border: 0 solid transparent; 223 | &:hover { 224 | cursor: pointer; 225 | } 226 | &.round { 227 | @include slider_border-radius($slider-line-height); 228 | } 229 | &.triangle { 230 | background: transparent none; 231 | } 232 | &.custom { 233 | background: transparent none; 234 | &::before{ 235 | line-height: $slider-line-height; 236 | font-size: 20px; 237 | content: '\2605'; //unicode star character 238 | color: $slider-unicode-color; 239 | } 240 | } 241 | } 242 | 243 | .slider-tick { 244 | @include slider_background-image($slider-gray-5, $slider-gray-6, $slider-tick-background-color); 245 | @include slider_box-shadow(inset 0 -1px 0 rgba(0,0,0,0.15)); 246 | @include slider_box-sizing(border-box); 247 | 248 | position: absolute; 249 | cursor: pointer; 250 | width: $slider-line-height; 251 | height: $slider-line-height; 252 | filter: none; 253 | opacity: 0.8; 254 | border: 0 solid transparent; 255 | 256 | &.round { 257 | border-radius: 50%; 258 | } 259 | &.triangle { 260 | background: transparent none; 261 | } 262 | &.custom { 263 | background: transparent none; 264 | &::before { 265 | line-height: $slider-line-height; 266 | font-size: 20px; 267 | content: '\2605'; //unicode star character 268 | color: $slider-unicode-color; 269 | } 270 | } 271 | &.in-selection { 272 | @include slider_background-image($slider-secondary-top, $slider-secondary-bottom, $slider-tick-in-selection-background-color); 273 | opacity: 1; 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /src/sass/_variables.scss: -------------------------------------------------------------------------------- 1 | $slider-line-height: 20px !default; 2 | $slider-border-radius: 4px !default; 3 | $slider-horizontal-width: 210px !default; 4 | $slider-vertical-height: 210px !default; 5 | 6 | // Primary colors 7 | $slider-primary: null !default; 8 | @if variable-exists(brand-primary) { 9 | $slider-primary: $brand-primary !default; 10 | } @else { 11 | $slider-primary: #0480BE !default; 12 | } 13 | 14 | $slider-primary-top: $slider-primary !default; 15 | $slider-primary-bottom: darken($slider-primary, 5%) !default; 16 | $slider-secondary-top: saturate(lighten($slider-primary, 28%), 20%) !default; 17 | $slider-secondary-bottom: saturate(lighten($slider-primary, 23%), 2%) !default; 18 | 19 | // grays for slider channel and disabled states 20 | $slider-gray-1: #BEBEBE !default; 21 | $slider-gray-2: #DFDFDF !default; 22 | $slider-gray-3: #E5E5E5 !default; 23 | $slider-gray-4: #E9E9E9 !default; 24 | $slider-gray-5: #F5F5F5 !default; 25 | $slider-gray-6: #F9F9F9 !default; 26 | 27 | // unicode color for demo page 28 | $slider-unicode-color: #726204 !default; 29 | 30 | // components 31 | $slider-selection-background-color: mix($slider-gray-6, $slider-gray-5) !default; 32 | $slider-selection-tick-background-color: mix($slider-secondary-top, $slider-secondary-bottom) !default; 33 | $slider-tick-background-color: mix($slider-gray-5, $slider-gray-6) !default; 34 | $slider-tick-in-selection-background-color: mix($slider-secondary-top, $slider-secondary-bottom) !default; 35 | $slider-handle-background-color: mix($slider-primary-top, $slider-primary-bottom) !default; 36 | $slider-handle-background-color-disabled: mix($slider-gray-2, $slider-gray-1) !default; 37 | $slider-track-background-color: mix($slider-gray-5, $slider-gray-6) !default; 38 | $slider-track-background-color-disabled: mix($slider-gray-3, $slider-gray-4) !default; -------------------------------------------------------------------------------- /src/sass/bootstrap-slider.scss: -------------------------------------------------------------------------------- 1 | /*! ========================================================= 2 | * bootstrap-slider.js 3 | * 4 | * Maintainers: 5 | * Kyle Kemp 6 | * - Twitter: @seiyria 7 | * - Github: seiyria 8 | * Rohit Kalkur 9 | * - Twitter: @Rovolutionary 10 | * - Github: rovolution 11 | * 12 | * ========================================================= 13 | * 14 | * bootstrap-slider is released under the MIT License 15 | * Copyright (c) 2019 Kyle Kemp, Rohit Kalkur, and contributors 16 | * 17 | * Permission is hereby granted, free of charge, to any person 18 | * obtaining a copy of this software and associated documentation 19 | * files (the "Software"), to deal in the Software without 20 | * restriction, including without limitation the rights to use, 21 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 22 | * copies of the Software, and to permit persons to whom the 23 | * Software is furnished to do so, subject to the following 24 | * conditions: 25 | * 26 | * The above copyright notice and this permission notice shall be 27 | * included in all copies or substantial portions of the Software. 28 | * 29 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 30 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 31 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 32 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 33 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 34 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 35 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 36 | * OTHER DEALINGS IN THE SOFTWARE. 37 | * 38 | * ========================================================= */ 39 | 40 | @import "variables"; 41 | @import "mixins"; 42 | @import "rules"; 43 | -------------------------------------------------------------------------------- /test/phantom_bind_polyfill.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////// 2 | // Taken from ariya/phantomjs#10522 3 | // 4 | 5 | 6 | Function.prototype.bind = function bind(that) { // .length is 1 7 | var target = this; 8 | if (typeof target != "function") { 9 | throw new TypeError("Function.prototype.bind called on incompatible " + target); 10 | } 11 | var args = Array.prototype.slice.call(arguments, 1); // for normal call 12 | var bound = function () { 13 | 14 | if (this instanceof bound) { 15 | 16 | var result = target.apply( 17 | this, 18 | args.concat(Array.prototype.slice.call(arguments)) 19 | ); 20 | if (Object(result) === result) { 21 | return result; 22 | } 23 | return this; 24 | 25 | } else { 26 | return target.apply( 27 | that, 28 | args.concat(Array.prototype.slice.call(arguments)) 29 | ); 30 | 31 | } 32 | 33 | }; 34 | function Empty() {}; 35 | if(target.prototype) { 36 | Empty.prototype = target.prototype; 37 | bound.prototype = new Empty(); 38 | Empty.prototype = null; 39 | } 40 | return bound; 41 | }; -------------------------------------------------------------------------------- /test/specs/AccessibilitySpec.js: -------------------------------------------------------------------------------- 1 | describe("Accessibility Tests", function() { 2 | var sliderA; 3 | var sliderB; 4 | 5 | it("Should have the slider role", function() { 6 | sliderA = $('#accessibilitySliderA').slider(); 7 | sliderB = $('#accessibilitySliderB').slider(); 8 | var $sliderElementA = $(sliderA.slider('getElement')); 9 | var $sliderElementB = $(sliderB.slider('getElement')); 10 | 11 | expect($sliderElementA.find('.min-slider-handle').attr('role')).toBe('slider'); 12 | expect($sliderElementB.find('.min-slider-handle').attr('role')).toBe('slider'); 13 | expect($sliderElementB.find('.max-slider-handle').attr('role')).toBe('slider'); 14 | 15 | expect($sliderElementA.find('.tooltip-main').attr('role')).toBe('presentation'); 16 | expect($sliderElementA.find('.tooltip-min').attr('role')).toBe('presentation'); 17 | expect($sliderElementA.find('.tooltip-max').attr('role')).toBe('presentation'); 18 | }); 19 | 20 | it('Should have an aria-labelledby attribute', function() { 21 | sliderA = $('#accessibilitySliderA').slider(); 22 | sliderB = $('#accessibilitySliderB').slider(); 23 | 24 | expect($(sliderA.slider('getElement')).find('.min-slider-handle').attr('aria-labelledby')).toBe('accessibilitySliderLabelA'); 25 | expect($(sliderB.slider('getElement')).find('.min-slider-handle').attr('aria-labelledby')).toBe('accessibilitySliderLabelA'); 26 | expect($(sliderB.slider('getElement')).find('.max-slider-handle').attr('aria-labelledby')).toBe('accessibilitySliderLabelB'); 27 | }); 28 | 29 | it('Should have an aria-valuemax and aria-valuemin value', function() { 30 | sliderA = $('#accessibilitySliderA').slider({ min: 5, max: 10 }); 31 | sliderB = $('#accessibilitySliderB').slider({ min: 5, max: 10 }); 32 | var $sliderElementA = $(sliderA.slider('getElement')); 33 | var $sliderElementB = $(sliderB.slider('getElement')); 34 | 35 | expect($sliderElementA.find('.min-slider-handle').attr('aria-valuemin')).toBe('5'); 36 | expect($sliderElementA.find('.min-slider-handle').attr('aria-valuemax')).toBe('10'); 37 | expect($sliderElementB.find('.min-slider-handle').attr('aria-valuemin')).toBe('5'); 38 | expect($sliderElementB.find('.min-slider-handle').attr('aria-valuemax')).toBe('10'); 39 | expect($sliderElementB.find('.max-slider-handle').attr('aria-valuemin')).toBe('5'); 40 | expect($sliderElementB.find('.max-slider-handle').attr('aria-valuemax')).toBe('10'); 41 | }); 42 | 43 | it('Should have an aria-valuenow with the current value', function() { 44 | sliderA = $('#accessibilitySliderA').slider({ min: 5, value: 7 }); 45 | sliderB = $('#accessibilitySliderB').slider({ min: 5, value: [2, 8] }); 46 | var $sliderElementA = $(sliderA.slider('getElement')); 47 | var $sliderElementB = $(sliderB.slider('getElement')); 48 | 49 | expect($sliderElementA.find('.min-slider-handle').attr('aria-valuenow')).toBe('7'); 50 | expect($sliderElementB.find('.min-slider-handle').attr('aria-valuenow')).toBe('5'); 51 | expect($sliderElementB.find('.max-slider-handle').attr('aria-valuenow')).toBe('8'); 52 | 53 | // Change the value and check if aria-valuenow is still the same 54 | sliderA.slider('setValue', 1); 55 | sliderB.slider('setValue', [4, 9]); 56 | 57 | expect($sliderElementA.find('.min-slider-handle').attr('aria-valuenow')).toBe('5'); 58 | expect($sliderElementB.find('.min-slider-handle').attr('aria-valuenow')).toBe('5'); 59 | expect($sliderElementB.find('.max-slider-handle').attr('aria-valuenow')).toBe('9'); 60 | }); 61 | 62 | afterEach(function() { 63 | if(sliderA) { sliderA.slider('destroy'); } 64 | if(sliderB) { sliderB.slider('destroy'); } 65 | }); 66 | 67 | }); 68 | -------------------------------------------------------------------------------- /test/specs/AriaValueTextFormatterSpec.js: -------------------------------------------------------------------------------- 1 | describe("Aria-valuetext Tests", function() { 2 | it("Sets the aria-valuetext to 'formatter' value", function() { 3 | var textValArrayA = new Array('Monday','Wednesday','Friday'); 4 | var tooltipFormatterA = function(value) { 5 | var arrActiveValueA = value; 6 | return textValArrayA[arrActiveValueA-1]; 7 | }; 8 | 9 | //Formatter is used 10 | var testSliderA = $("#accessibilitySliderA").slider({ 11 | formatter : tooltipFormatterA 12 | }); 13 | testSliderA.slider('setValue', 2); 14 | 15 | var tooltipMessageA = $("#accessibilitySliderA").prev(".slider").children(".min-slider-handle").attr("aria-valuetext"); 16 | var expectedMessageA = tooltipFormatterA(2); 17 | expect(tooltipMessageA).toBe(expectedMessageA); 18 | 19 | $("#accessibilitySliderA").slider('destroy'); 20 | }); 21 | 22 | it("Does not use aria-valuetext if 'formatter' is not used", function() { 23 | 24 | //Formatter is not used 25 | var testSliderB = $("#accessibilitySliderB").slider({}); 26 | testSliderB.slider('setValue', 1); 27 | 28 | var ariaValueTextB = $("#accessibilitySliderB").prev(".slider").children(".min-slider-handle").attr("aria-valuetext"); 29 | expect(ariaValueTextB).not.toBeDefined(); 30 | 31 | $("#accessibilitySliderB").slider('destroy'); 32 | }); 33 | 34 | it("aria-valuetext if 'formatter' is used and has min & max value", function() { 35 | var textValArrayC = new Array('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'); 36 | var tooltipFormatterC = function(value) { 37 | if(value[1]){ 38 | var arrActiveValueC0 = value[0]; 39 | var arrActiveValueC1 = value[1]; 40 | return [ textValArrayC[arrActiveValueC0-1], textValArrayC[arrActiveValueC1-1] ]; 41 | } else { 42 | var arrActiveValueC = value; 43 | return textValArrayC[arrActiveValueC-1]; 44 | } 45 | }; 46 | 47 | //Formatter is used for ranges 48 | var testSliderC = $("#accessibilitySliderC").slider({ 49 | range: true, 50 | formatter : tooltipFormatterC 51 | }); 52 | var valuesToSet = [2,4]; 53 | testSliderC.slider('setValue', valuesToSet); 54 | var expectedMessageC = tooltipFormatterC([2,4]); 55 | var ttminMessage = $("#accessibilitySliderC").prev(".slider").children(".min-slider-handle").attr("aria-valuetext"); 56 | var ttmaxMessage = $("#accessibilitySliderC").prev(".slider").children(".max-slider-handle").attr("aria-valuetext"); 57 | expect(ttminMessage).toBe(expectedMessageC[0]); 58 | expect(ttmaxMessage).toBe(expectedMessageC[1]); 59 | 60 | $('#accessibilitySliderC').slider('destroy'); 61 | }); 62 | 63 | describe("Unset 'aria-valuetext' attribute when value can be represented as a number", function() { 64 | var $testSliderC; 65 | var dayOfWeek; 66 | 67 | var dayFormatter = function(value) { 68 | if (value[1]) { 69 | return [ dayOfWeek[value[0]-1], dayOfWeek[value[1]-1] ]; 70 | } 71 | return dayOfWeek[value-1]; 72 | }; 73 | 74 | beforeEach(function() { 75 | dayOfWeek = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; 76 | 77 | $testSliderC = $('#accessibilitySliderC').slider({ 78 | id: 'testAccessbilitySlider', 79 | min: 1, 80 | max: 7, 81 | formatter : dayFormatter 82 | }); 83 | }); 84 | 85 | afterEach(function() { 86 | if ($testSliderC) { 87 | $testSliderC.slider('destroy'); 88 | } 89 | }); 90 | 91 | it("Should unset 'aria-valuetext' attribute", function() { 92 | dayOfWeek[0] = '1'; 93 | 94 | var valueToSet = 1; 95 | $testSliderC.slider('setValue', valueToSet); 96 | var ariaValueText = $('#testAccessbilitySlider').find('.min-slider-handle')[0].getAttribute('aria-valuetext'); 97 | expect(ariaValueText).toBeNull(); 98 | }); 99 | 100 | it("Should unset 'aria-valuetext' attributes for range sliders", function() { 101 | dayOfWeek[0] = '1'; 102 | dayOfWeek[6] = '7'; 103 | $testSliderC.slider('setAttribute', 'range', true); 104 | $testSliderC.slider('refresh'); 105 | 106 | var valuesToSet = [1, 7]; 107 | $testSliderC.slider('setValue', valuesToSet); 108 | var ariaValueText1 = $('#testAccessbilitySlider').find('.min-slider-handle')[0].getAttribute('aria-valuetext'); 109 | var ariaValueText2 = $('#testAccessbilitySlider').find('.max-slider-handle')[0].getAttribute('aria-valuetext'); 110 | expect(ariaValueText1).toBeNull(); 111 | expect(ariaValueText2).toBeNull(); 112 | }); 113 | }); 114 | }); 115 | -------------------------------------------------------------------------------- /test/specs/AutoRegisterDataProvideSpec.js: -------------------------------------------------------------------------------- 1 | describe("Auto register data-provide Tests", function() { 2 | it("checks that the autoregister Slider was automatically registerd", function() { 3 | var $el = $("#autoregisterSlider"); 4 | 5 | var sliderInstancesExists = $el.siblings().is(".slider"); 6 | expect(sliderInstancesExists).toBeTruthy(); 7 | 8 | var sliderInstancesCount = $el.siblings(".slider").length; 9 | expect(sliderInstancesCount).toEqual(1); 10 | }); 11 | 12 | it("checks that the autoregistered Slider can be accessed", function() { 13 | var $el = $("#autoregisterSlider"); 14 | 15 | expect($el.slider('getValue')).toBe(1); 16 | 17 | $el.slider('setValue', 2); 18 | 19 | expect($el.slider('getValue')).toBe(2); 20 | }); 21 | }); -------------------------------------------------------------------------------- /test/specs/ConflictingOptionsSpec.js: -------------------------------------------------------------------------------- 1 | /* 2 | ************************* 3 | 4 | Conflicting Options Tests 5 | 6 | ************************* 7 | 8 | This spec has tests for checking if two or more options do not conflict with one another 9 | As option conflicts are reported and resolved, write tests for them here. 10 | This will help ensure that they are accounted for and do not arise again. 11 | */ 12 | describe("Conflicting Options Tests", function() { 13 | 14 | var testSlider; 15 | 16 | it("Should have the value zero when it is slided to zero", function() { 17 | testSlider = $("#testSlider1").slider({ 18 | value: 0, 19 | step: 1 20 | }); 21 | var flag = false; 22 | var mouse = document.createEvent('MouseEvents'); 23 | 24 | testSlider.on('slide', function(slideEvt) { 25 | expect(slideEvt.value).toBe(0); 26 | flag = true; 27 | }); 28 | 29 | testSlider.data('slider')._mousemove(mouse); 30 | expect(flag).toBeTruthy(); 31 | }); 32 | 33 | it("should set the `precision` to be the number of digits after the decimal of the `step` (assuming no `precision` is specified)", function() { 34 | // Create Slider 35 | testSlider = $("#testSlider1").slider({ 36 | value: 8.115, 37 | step: 0.01 38 | }); 39 | // Retrieve slider value 40 | var value = testSlider.slider("getValue"); 41 | // Run tests 42 | expect(value).toBe(8.12); 43 | }); 44 | 45 | it("should properly allow for a slider that has `range` set to true and `reversed` set to true", function() { 46 | // Create Slider 47 | testSlider = new Slider("#testSlider1", { 48 | reversed: true, 49 | range: true, 50 | min: -5, 51 | max: 20 52 | }); 53 | 54 | // Set Value 55 | testSlider.setValue([-5, 20]); 56 | 57 | // Assert that selection slider section is 100% of slider width 58 | var selectedSectionWidth = testSlider.sliderElem.querySelector(".slider-selection").style.width; 59 | expect(selectedSectionWidth).toBe("100%"); 60 | 61 | // Cleanup 62 | testSlider.destroy(); 63 | testSlider = null; 64 | }); 65 | 66 | afterEach(function() { 67 | if(testSlider) { 68 | testSlider.slider('destroy'); 69 | testSlider = null; 70 | } 71 | }); 72 | 73 | }); 74 | -------------------------------------------------------------------------------- /test/specs/DestroyMethodTests.js: -------------------------------------------------------------------------------- 1 | describe("'destroy()' Method tests", function() { 2 | var testSlider; 3 | 4 | function createSliderFn() { 5 | testSlider = new Slider("#testSlider1", { 6 | id: "destroyMethodTestSlider" 7 | }); 8 | } 9 | 10 | it("removes the extra DOM elements associated with a slider", function() { 11 | 12 | createSliderFn(); 13 | 14 | testSlider.destroy(); 15 | 16 | var sliderParentElement = $("#testSlider1").parent('div.slider').length; 17 | var sliderChildrenElements = $("#testSlider1").siblings('div.slider-track, div.tooltip').length; 18 | 19 | expect(sliderParentElement).toBe(0); 20 | expect(sliderChildrenElements).toBe(0); 21 | }); 22 | 23 | describe("Destroy slider instance associated with element", function() { 24 | var sourceJS = "temp/bootstrap-slider.js"; 25 | var defaultNamespace = 'slider'; 26 | var alternateNamespace = 'bootstrapSlider'; 27 | 28 | it("Should remove the instance associated with the DOM element", function() { 29 | var $testSlider = $('#testSlider1').slider(); 30 | 31 | var sliderInst = $testSlider.data(defaultNamespace); 32 | expect(sliderInst).toBeTruthy(); 33 | 34 | $testSlider.slider('destroy'); 35 | sliderInst = $testSlider.data(defaultNamespace); 36 | expect(sliderInst).toBeUndefined(); 37 | }); 38 | 39 | describe("Check alternate namespace", function() { 40 | 41 | afterEach(function(done) { 42 | $.fn.bootstrapSlider = undefined; 43 | $.fn.slider = undefined; 44 | 45 | $.getScript(sourceJS, function() { 46 | done(); 47 | }); 48 | }); 49 | 50 | it("Should remove the instance associated with the DOM element with alternate namespace", function(done) { 51 | $.fn.slider = function() {}; 52 | 53 | $.getScript(sourceJS, function() { 54 | var $testSlider = $('#testSlider1').bootstrapSlider(); 55 | 56 | $testSlider.bootstrapSlider('destroy'); 57 | 58 | var sliderInst = $testSlider.data(alternateNamespace); 59 | expect(sliderInst).toBeUndefined(); 60 | 61 | done(); 62 | }); 63 | }); 64 | }); 65 | }); 66 | 67 | describe("unbinds all slider events", function() { 68 | var flag, evtName; 69 | 70 | beforeEach(function() { 71 | createSliderFn(); 72 | flag = false; 73 | }); 74 | 75 | it("unbinds from 'slideStart' event", function() { 76 | evtName = 'slideStart'; 77 | $("#destroyMethodTestSlider").on(evtName, function() { 78 | flag = true; 79 | }); 80 | testSlider.destroy(); 81 | $("#destroyMethodTestSlider").trigger(evtName); 82 | expect(flag).toBeFalsy(); 83 | }); 84 | 85 | it("unbinds from 'slide' event", function() { 86 | evtName = 'slide'; 87 | $("#destroyMethodTestSlider").on(evtName, function() { 88 | flag = true; 89 | }); 90 | testSlider.destroy(); 91 | $("#destroyMethodTestSlider").trigger(evtName); 92 | expect(flag).toBeFalsy(); 93 | }); 94 | 95 | it("unbinds from 'slideStop' event", function() { 96 | evtName = 'slideStop'; 97 | $("#destroyMethodTestSlider").on(evtName, function() { 98 | flag = true; 99 | }); 100 | testSlider.destroy(); 101 | $("#destroyMethodTestSlider").trigger(evtName); 102 | expect(flag).toBeFalsy(); 103 | }); 104 | 105 | it("unbinds from 'slideChange' event", function() { 106 | evtName = 'slideChange'; 107 | $("#destroyMethodTestSlider").on(evtName, function() { 108 | flag = true; 109 | }); 110 | testSlider.destroy(); 111 | $("#destroyMethodTestSlider").trigger(evtName); 112 | expect(flag).toBeFalsy(); 113 | }); 114 | 115 | it("unbinds all slider events and allows you to re-create the slider without runtime error", function() { 116 | // Setup 117 | var createSliderAndBindEvent = function () { 118 | $("#testSlider1").bootstrapSlider({ 119 | min: 0, 120 | max: 1000 * 1000, 121 | step: 1000 122 | }); 123 | testSlider = $("#testSlider1").data("bootstrapSlider"); 124 | testSlider.on("slideStop", function() {}); 125 | }; 126 | // Destroy existing slider from default bootstrap step 127 | testSlider.destroy(); 128 | 129 | // Create new Slider 130 | createSliderAndBindEvent(); 131 | 132 | // Destroy slider 133 | testSlider.destroy(); 134 | 135 | // Re-create Slider and try to re-bind event 136 | var throwsRuntimeError = false; 137 | 138 | try { 139 | createSliderAndBindEvent(); 140 | } 141 | catch (e) { 142 | throwsRuntimeError = true; 143 | } 144 | 145 | testSlider.destroy(); 146 | 147 | // reCreateSliderAndBindEvent(): Assert error is not thrown 148 | expect(throwsRuntimeError).toBeFalsy(); 149 | }); 150 | }); 151 | 152 | describe("DOM event listener removal tests", function() { 153 | describe("When tooltips are always hidden for single value sliders", function() { 154 | beforeEach(function() { 155 | // Create slider 156 | testSlider = new Slider("#testSlider1", { 157 | id: "destroyMethodTestSlider", 158 | tooltip: "hide" 159 | }); 160 | }); 161 | 162 | it("does not try to remove 'focus' event listener from handle1", function() { 163 | // Set up spy on 'removeEventListener' 164 | spyOn(testSlider.handle1, "removeEventListener"); 165 | 166 | // Destroy slider 167 | testSlider.destroy(); 168 | 169 | // Assert 170 | expect(testSlider.handle1.removeEventListener).not.toHaveBeenCalledWith("focus", undefined, false); 171 | }); 172 | 173 | it("does not try to remove 'blur' event listener from handle1", function() { 174 | // Set up spy on 'removeEventListener' 175 | spyOn(testSlider.handle1, "removeEventListener"); 176 | 177 | // Destroy slider 178 | testSlider.destroy(); 179 | 180 | // Assert 181 | expect(testSlider.handle1.removeEventListener).not.toHaveBeenCalledWith("blur", undefined, false); 182 | }); 183 | 184 | it("does not try to remove 'mouseenter' event listener from slider", function() { 185 | // Set up spy on 'removeEventListener' 186 | spyOn(testSlider.sliderElem, "removeEventListener"); 187 | 188 | // Destroy slider 189 | testSlider.destroy(); 190 | 191 | // Assert 192 | expect(testSlider.sliderElem.removeEventListener).not.toHaveBeenCalledWith("mouseenter", undefined, false); 193 | }); 194 | 195 | it("does not try to remove 'mouseleave' event listener from slider", function() { 196 | // Set up spy on 'removeEventListener' 197 | spyOn(testSlider.sliderElem, "removeEventListener"); 198 | 199 | // Destroy slider 200 | testSlider.destroy(); 201 | 202 | // Assert 203 | expect(testSlider.sliderElem.removeEventListener).not.toHaveBeenCalledWith("mouseleave", undefined, false); 204 | }); 205 | }); 206 | 207 | describe("When tooltips are always shown for single value sliders", function() { 208 | beforeEach(function() { 209 | // Create slider 210 | testSlider = new Slider("#testSlider1", { 211 | id: "destroyMethodTestSlider", 212 | tooltip: "always" 213 | }); 214 | }); 215 | 216 | it("does not try to remove 'focus' event listener from handle1 when tooltip is always shown for single handle sliders", function() { 217 | // Set up spy on 'removeEventListener' 218 | spyOn(testSlider.handle1, "removeEventListener"); 219 | 220 | // Destroy slider 221 | testSlider.destroy(); 222 | 223 | // Assert 224 | expect(testSlider.handle1.removeEventListener).not.toHaveBeenCalledWith("focus", undefined, false); 225 | }); 226 | 227 | it("does not try to remove 'blur' event listener from handle1 when tooltip is always shown for single handle sliders", function() { 228 | // Set up spy on 'removeEventListener' 229 | spyOn(testSlider.handle1, "removeEventListener"); 230 | 231 | // Destroy slider 232 | testSlider.destroy(); 233 | 234 | // Assert 235 | expect(testSlider.handle1.removeEventListener).not.toHaveBeenCalledWith("blur", undefined, false); 236 | }); 237 | 238 | it("does not try to remove 'mouseenter' event listener from slider is always shown for single handle slider", function() { 239 | // Set up spy on 'removeEventListener' 240 | spyOn(testSlider.handle1, "removeEventListener"); 241 | 242 | // Destroy slider 243 | testSlider.destroy(); 244 | 245 | // Assert 246 | expect(testSlider.handle1.removeEventListener).not.toHaveBeenCalledWith("mouseenter", undefined, false); 247 | }); 248 | 249 | it("does not try to remove 'mouseleave' event listener from slider is always shown for single handle slider", function() { 250 | // Set up spy on 'removeEventListener' 251 | spyOn(testSlider.sliderElem, "removeEventListener"); 252 | 253 | // Destroy slider 254 | testSlider.destroy(); 255 | 256 | // Assert 257 | expect(testSlider.sliderElem.removeEventListener).not.toHaveBeenCalledWith("mouseleave", undefined, false); 258 | }); 259 | }); 260 | 261 | describe("When tooltips are always hidden for range sliders", function() { 262 | beforeEach(function() { 263 | // Create slider 264 | testSlider = new Slider("#testSlider1", { 265 | id: "destroyMethodTestSlider", 266 | tooltip: "always", 267 | value: [2,5] 268 | }); 269 | }); 270 | 271 | it("does not try to remove 'focus' event listener from handle1", function() { 272 | // Set up spy on 'removeEventListener' 273 | spyOn(testSlider.handle1, "removeEventListener"); 274 | 275 | // Destroy slider 276 | testSlider.destroy(); 277 | 278 | // Assert 279 | expect(testSlider.handle1.removeEventListener).not.toHaveBeenCalledWith("focus", undefined, false); 280 | }); 281 | 282 | it("does not try to remove 'focus' event listener from handle2", function() { 283 | // Set up spy on 'removeEventListener' 284 | spyOn(testSlider.handle2, "removeEventListener"); 285 | 286 | // Destroy slider 287 | testSlider.destroy(); 288 | 289 | // Assert 290 | expect(testSlider.handle2.removeEventListener).not.toHaveBeenCalledWith("focus", undefined, false); 291 | }); 292 | 293 | it("does not try to remove 'blur' event listener from handle1", function() { 294 | // Set up spy on 'removeEventListener' 295 | spyOn(testSlider.handle1, "removeEventListener"); 296 | 297 | // Destroy slider 298 | testSlider.destroy(); 299 | 300 | // Assert 301 | expect(testSlider.handle1.removeEventListener).not.toHaveBeenCalledWith("blur", undefined, false); 302 | }); 303 | 304 | it("does not try to remove 'blur' event listener from handle2", function() { 305 | // Set up spy on 'removeEventListener' 306 | spyOn(testSlider.handle2, "removeEventListener"); 307 | 308 | // Destroy slider 309 | testSlider.destroy(); 310 | 311 | // Assert 312 | expect(testSlider.handle2.removeEventListener).not.toHaveBeenCalledWith("blur", undefined, false); 313 | }); 314 | 315 | it("does not try to remove 'mouseenter' event listener from slider", function() { 316 | // Set up spy on 'removeEventListener' 317 | spyOn(testSlider.sliderElem, "removeEventListener"); 318 | 319 | // Destroy slider 320 | testSlider.destroy(); 321 | 322 | // Assert 323 | expect(testSlider.sliderElem.removeEventListener).not.toHaveBeenCalledWith("mouseenter", undefined, false); 324 | }); 325 | 326 | it("does not try to remove 'mouseleave' event listener from slider", function() { 327 | // Set up spy on 'removeEventListener' 328 | spyOn(testSlider.sliderElem, "removeEventListener"); 329 | 330 | // Destroy slider 331 | testSlider.destroy(); 332 | 333 | // Assert 334 | expect(testSlider.sliderElem.removeEventListener).not.toHaveBeenCalledWith("mouseleave", undefined, false); 335 | }); 336 | }); 337 | 338 | describe("When tooltips are always shown for range sliders", function() { 339 | beforeEach(function() { 340 | // Create slider 341 | testSlider = new Slider("#testSlider1", { 342 | id: "destroyMethodTestSlider", 343 | tooltip: "always", 344 | value: [2,5] 345 | }); 346 | }); 347 | 348 | it("does not try to remove 'focus' event listener from handle1", function() { 349 | // Set up spy on 'removeEventListener' 350 | spyOn(testSlider.handle1, "removeEventListener"); 351 | 352 | // Destroy slider 353 | testSlider.destroy(); 354 | 355 | // Assert 356 | expect(testSlider.handle1.removeEventListener).not.toHaveBeenCalledWith("focus", undefined, false); 357 | }); 358 | 359 | it("does not try to remove 'focus' event listener from handle2", function() { 360 | // Set up spy on 'removeEventListener' 361 | spyOn(testSlider.handle2, "removeEventListener"); 362 | 363 | // Destroy slider 364 | testSlider.destroy(); 365 | 366 | // Assert 367 | expect(testSlider.handle2.removeEventListener).not.toHaveBeenCalledWith("focus", undefined, false); 368 | }); 369 | 370 | it("does not try to remove 'blur' event listener from handle1", function() { 371 | // Set up spy on 'removeEventListener' 372 | spyOn(testSlider.handle1, "removeEventListener"); 373 | 374 | // Destroy slider 375 | testSlider.destroy(); 376 | 377 | // Assert 378 | expect(testSlider.handle1.removeEventListener).not.toHaveBeenCalledWith("blur", undefined, false); 379 | }); 380 | 381 | it("does not try to remove 'blur' event listener from handle1 and handle2", function() { 382 | // Set up spy on 'removeEventListener' 383 | spyOn(testSlider.handle2, "removeEventListener"); 384 | 385 | // Destroy slider 386 | testSlider.destroy(); 387 | 388 | // Assert 389 | expect(testSlider.handle2.removeEventListener).not.toHaveBeenCalledWith("blur", undefined, false); 390 | }); 391 | 392 | it("does not try to remove 'mouseenter' event listener from slider", function() { 393 | // Set up spy on 'removeEventListener' 394 | spyOn(testSlider.sliderElem, "removeEventListener"); 395 | 396 | // Destroy slider 397 | testSlider.destroy(); 398 | 399 | // Assert 400 | expect(testSlider.sliderElem.removeEventListener).not.toHaveBeenCalledWith("mouseenter", undefined, false); 401 | }); 402 | 403 | it("does not try to remove 'mouseleave' event listener from slider", function() { 404 | // Set up spy on 'removeEventListener' 405 | spyOn(testSlider.sliderElem, "removeEventListener"); 406 | 407 | // Destroy slider 408 | testSlider.destroy(); 409 | 410 | // Assert 411 | expect(testSlider.sliderElem.removeEventListener).not.toHaveBeenCalledWith("mouseleave", undefined, false); 412 | }); 413 | }); 414 | }); 415 | 416 | }); -------------------------------------------------------------------------------- /test/specs/DraggingHandlesSpec.js: -------------------------------------------------------------------------------- 1 | describe("Dragging handles tests", function() { 2 | var testSlider; 3 | var mouseEventArguments; 4 | var tickOffsets; 5 | 6 | // Create mouse events 7 | function mouseEvent(type, offset) { 8 | var ev = document.createEvent("MouseEvents"); 9 | mouseEventArguments[0] = type; 10 | mouseEventArguments[7] = offset; 11 | ev.initMouseEvent.apply(ev, mouseEventArguments); 12 | return ev; 13 | } 14 | 15 | beforeEach(function() { 16 | // Create slider 17 | testSlider = new Slider(document.getElementById("testSlider1"), { 18 | ticks: [0, 1, 2, 3, 4, 5, 6], 19 | value: [4, 5], 20 | step: 1, 21 | range: true, 22 | }); 23 | // Set up default set of mouse event arguments 24 | mouseEventArguments = [ 25 | 'mousemove', // type 26 | true, // canBubble 27 | true, // cancelable 28 | document, // view, 29 | 0, // detail 30 | 0, // screenX 31 | 0, // screenY 32 | undefined, // clientX 33 | testSlider.sliderElem.offsetTop, // clientY, 34 | false, // ctrlKey 35 | false, // altKey 36 | false, // shiftKey 37 | false, // metaKey, 38 | 0, // button 39 | null // relatedTarget 40 | ]; 41 | // Calculate and store the 'clientX' for each tick in the slider 42 | tickOffsets = testSlider.ticks.map(function (tick) { 43 | return tick.offsetLeft + testSlider.sliderElem.offsetLeft; 44 | }); 45 | }); 46 | 47 | afterEach(function() { 48 | if(testSlider) { 49 | if(testSlider instanceof Slider) { testSlider.destroy(); } 50 | testSlider = null; 51 | } 52 | }); 53 | 54 | describe("Dragging handles over each other", function() { 55 | it("should swap reliably given imprecision", function() { 56 | // Create mouse event with position to the left of problem tick 57 | var mouseLeft = document.createEvent('MouseEvents'); 58 | mouseEventArguments[7] = tickOffsets[4]; // clientX 59 | mouseLeft.initMouseEvent.apply(mouseLeft, mouseEventArguments); 60 | // Create mouse event with position on problem tick 61 | var mouseOverlap = document.createEvent('MouseEvents'); 62 | mouseEventArguments[7] = tickOffsets[5]; // clientX 63 | mouseOverlap.initMouseEvent.apply(mouseOverlap, mouseEventArguments); 64 | // Create mouse event with position to the right of problem tick 65 | var mouseRight = document.createEvent('MouseEvents'); 66 | mouseEventArguments[7] = tickOffsets[6]; // clientX 67 | mouseRight.initMouseEvent.apply(mouseRight, mouseEventArguments); 68 | // Same offset as 'mouseLeft' 69 | var mouseUp = document.createEvent('MouseEvents'); 70 | mouseEventArguments[7] = testSlider.ticks[4].offsetLeft + testSlider.sliderElem.offsetLeft; // clientX 71 | mouseUp.initMouseEvent.apply(mouseUp, mouseEventArguments); 72 | // Simulate drag without swapping 73 | testSlider.mousedown(mouseLeft); 74 | expect(testSlider._state.dragged).toBe(0); 75 | expect(testSlider.getValue()).toEqual([4, 5]); 76 | // Simulate handle overlap 77 | testSlider.mousemove(mouseOverlap); 78 | expect(testSlider._state.dragged).toBe(0); 79 | expect(testSlider.getValue()).toEqual([5, 5]); 80 | // Simulate left over right drag with imprecision in reported percentage 81 | testSlider.mousemove(mouseRight); 82 | expect(testSlider._state.dragged).toBe(1); 83 | expect(testSlider.getValue()).toEqual([5, 6]); 84 | // Simulate handle overlap 85 | testSlider.mousemove(mouseOverlap); 86 | expect(testSlider._state.dragged).toBe(1); 87 | expect(testSlider.getValue()).toEqual([5, 5]); 88 | // Simulator handle overlap with click 89 | testSlider.mousemove(mouseOverlap); 90 | testSlider.mousedown(mouseLeft); 91 | expect(testSlider._state.dragged).toBe(0); 92 | expect(testSlider.getValue()).toEqual([4, 5]); 93 | // Simulate right over left drag with imprecision in reported percentage 94 | testSlider.mousemove(mouseLeft); 95 | expect(testSlider._state.dragged).toBe(0); 96 | expect(testSlider.getValue()).toEqual([4, 5]); 97 | // End with mouse up 98 | testSlider.mouseup(mouseUp); 99 | expect(testSlider._state.dragged).toBeNull(); 100 | expect(testSlider.getValue()).toEqual([4, 5]); 101 | }); 102 | }); 103 | 104 | describe("Drag handles over each other and use keyboard to move handles over each other", function() { 105 | var keyboardEvent; 106 | 107 | function createMouseEvent(type, tickIdx) { 108 | var mouseEvent = document.createEvent('MouseEvent'); 109 | mouseEventArguments[0] = type; 110 | mouseEventArguments[7] = tickOffsets[tickIdx]; 111 | mouseEvent.initMouseEvent.apply(mouseEvent, mouseEventArguments); 112 | return mouseEvent; 113 | } 114 | 115 | beforeEach(function() { 116 | // Create keyboard event 117 | keyboardEvent = document.createEvent('Event'); 118 | keyboardEvent.initEvent('keydown', true, true); 119 | }); 120 | 121 | afterEach(function() { 122 | keyboardEvent = null; 123 | }); 124 | 125 | it("should drag and keydown handles properly to the right then back to the left", function() { 126 | // Simulate drag without swapping 127 | testSlider.mousedown(createMouseEvent('mousedown', 4)); 128 | expect(testSlider._state.dragged).toBe(0); 129 | expect(testSlider.getValue()).toEqual([4, 5]); 130 | 131 | // Simulate handle overlap 132 | testSlider.mousemove(createMouseEvent('mousemove', 5)); 133 | expect(testSlider._state.dragged).toBe(0); 134 | expect(testSlider.getValue()).toEqual([5, 5]); 135 | 136 | // Simulate left over right drag 137 | testSlider.mousemove(createMouseEvent('mousemove', 6)); 138 | expect(testSlider._state.dragged).toBe(1); 139 | expect(testSlider.getValue()).toEqual([5, 6]); 140 | 141 | // End with mouse up 142 | testSlider.mouseup(createMouseEvent('mouseup', 6)); 143 | expect(testSlider._state.dragged).toBeNull(); 144 | expect(testSlider.getValue()).toEqual([5, 6]); 145 | 146 | // Now move the handles past each other with the Left arrow key 147 | keyboardEvent.keyCode = keyboardEvent.which = 37; 148 | 149 | // Move handle2 to the left with keyboard 150 | testSlider.handle2Keydown(keyboardEvent); 151 | expect(testSlider._state.keyCtrl).toBeUndefined(); 152 | expect(testSlider.getValue()).toEqual([5, 5]); 153 | 154 | // Move handle2 to the left again 155 | testSlider.handle2Keydown(keyboardEvent); 156 | expect(testSlider._state.keyCtrl).toBeUndefined(); 157 | expect(testSlider.getValue()).toEqual([4, 5]); 158 | }); 159 | 160 | it("should drag and keydown handles properly to the left then back to the right", function() { 161 | // Simulate drag without swapping 162 | testSlider.mousedown(createMouseEvent('mousedown', 5)); 163 | expect(testSlider._state.dragged).toBe(1); 164 | expect(testSlider.getValue()).toEqual([4, 5]); 165 | 166 | // Simulate handle overlap 167 | testSlider.mousemove(createMouseEvent('mousemove', 4)); 168 | expect(testSlider._state.dragged).toBe(1); 169 | expect(testSlider.getValue()).toEqual([4, 4]); 170 | 171 | // Simulate left over right drag 172 | testSlider.mousemove(createMouseEvent('mousemove', 3)); 173 | expect(testSlider._state.dragged).toBe(0); 174 | expect(testSlider.getValue()).toEqual([3, 4]); 175 | 176 | // End with mouse up 177 | testSlider.mouseup(createMouseEvent('mouseup', 3)); 178 | expect(testSlider._state.dragged).toBeNull(); 179 | expect(testSlider.getValue()).toEqual([3, 4]); 180 | 181 | // Now move the handles past each other with the Right arrow key 182 | keyboardEvent.keyCode = keyboardEvent.which = 39; 183 | 184 | // Move handle1 to the right with keyboard 185 | testSlider.handle1Keydown(keyboardEvent); 186 | expect(testSlider._state.keyCtrl).toBeUndefined(); 187 | expect(testSlider.getValue()).toEqual([4, 4]); 188 | 189 | // Move handle1 to the right again 190 | testSlider.handle1Keydown(keyboardEvent); 191 | expect(testSlider._state.keyCtrl).toBeUndefined(); 192 | expect(testSlider.getValue()).toEqual([4, 5]); 193 | }); 194 | }); 195 | 196 | it("Should snap to a tick within tick bounds when using the mouse navigation", function() { 197 | 198 | testSlider.setAttribute('range', true); 199 | testSlider.setAttribute('ticks_snap_bounds', 0.45); 200 | testSlider.setAttribute('step', 0.1); 201 | testSlider.refresh(); 202 | 203 | // Create mouse events 204 | var mouseDown = document.createEvent("MouseEvents"); 205 | mouseEventArguments[7] = tickOffsets[1]; 206 | mouseDown.initMouseEvent.apply(mouseDown, mouseEventArguments); 207 | 208 | var mouseRight = document.createEvent("MouseEvents"); 209 | mouseEventArguments[7] = tickOffsets[2] - 2; 210 | mouseRight.initMouseEvent.apply(mouseRight, mouseEventArguments); 211 | 212 | testSlider.mousedown(mouseDown); 213 | expect(testSlider.getValue()).toEqual([0.7, 5]); 214 | 215 | testSlider.mousemove(mouseRight); 216 | expect(testSlider.getValue()).toEqual([2, 5]); 217 | 218 | // FIXME: Use 'mouseup' event type 219 | // End with mouse up 220 | testSlider.mouseup(mouseRight); 221 | expect(testSlider.getValue()).toEqual([2, 5]); 222 | }); 223 | 224 | it("Should trigger change on mouseup", function(done) { 225 | var changes = 0; 226 | 227 | testSlider.on('slideStop', function(){ 228 | expect(changes).toBe(1); 229 | expect(testSlider.getValue()).toEqual([2, 5]); 230 | done(); 231 | }); 232 | 233 | testSlider.mousedown(mouseEvent('mousedown', tickOffsets[1])); 234 | expect(testSlider.getValue()).toEqual([1, 5]); 235 | 236 | testSlider.on('change', function(){ 237 | changes++; 238 | }); 239 | 240 | testSlider.mouseup(mouseEvent('mouseup', tickOffsets[2])); 241 | }); 242 | 243 | describe("Test 'mousemove' and 'mouseup' produces correct results", function() { 244 | var $mySlider; 245 | var $handle1; 246 | 247 | function arraysEqual(a, b) { 248 | if (a === b) { return true; } 249 | if (a == null || b == null) { return false; } 250 | if (a.length !== b.length) { return false; } 251 | 252 | for (var i = 0; i < a.length; ++i) { 253 | if (a[i] !== b[i]) { return false; } 254 | } 255 | return true; 256 | } 257 | 258 | it("Last value changed in 'change' event should equal 'mouseup' event value for slider", function(done) { 259 | // Change attributes for 'testSlider' 260 | testSlider.setAttribute('value', 3); 261 | testSlider.setAttribute('range', false); 262 | testSlider.refresh(); 263 | 264 | $mySlider = $('#testSlider1'); 265 | 266 | function createMouseEvent(type, tickIdx) { 267 | var mouseEvent = document.createEvent('MouseEvent'); 268 | mouseEventArguments[0] = type; 269 | mouseEventArguments[7] = tickOffsets[tickIdx]; 270 | mouseEvent.initMouseEvent.apply(mouseEvent, mouseEventArguments); 271 | return mouseEvent; 272 | } 273 | 274 | var lastValue = 99; // Dummy value 275 | $mySlider.on('change', function(eventData) { 276 | lastValue = eventData.value.newValue; 277 | }); 278 | 279 | $mySlider.on('slideStop', function(eventData) { 280 | var value = eventData.value; 281 | var isEqual = Array.isArray(value) ? arraysEqual(lastValue, value) : value === lastValue; 282 | expect(isEqual).toBe(true); 283 | done(); 284 | }); 285 | 286 | // Simulate drag and release from tick[1] to tick[4] 287 | $handle1 = testSlider.$sliderElem.find('.slider-handle:first'); 288 | $handle1[0].dispatchEvent(createMouseEvent('mousedown', 1)); 289 | $handle1[0].dispatchEvent(createMouseEvent('mousemove', 4)); 290 | $handle1[0].dispatchEvent(createMouseEvent('mouseup', 4)); 291 | }); 292 | }); 293 | }); 294 | -------------------------------------------------------------------------------- /test/specs/ElementDataAttributesSpec.js: -------------------------------------------------------------------------------- 1 | describe("Element Data Attributes Tests", function() { 2 | var slider; 3 | 4 | it("reads the 'data-slider-min' property and sets it on slider", function() { 5 | slider = $("#minSlider").slider(); 6 | slider.slider('setValue', 1); 7 | 8 | var sliderValue = slider.slider('getValue'); 9 | expect(sliderValue).toBe(5); 10 | }); 11 | 12 | it("reads the 'data-slider-max' property and sets it on slider", function() { 13 | slider = $("#maxSlider").slider(); 14 | slider.slider('setValue', 10); 15 | 16 | var sliderValue = slider.slider('getValue'); 17 | expect(sliderValue).toBe(5); 18 | }); 19 | 20 | it("reads the 'data-slider-step' property and sets it on slider", function() { 21 | 22 | slider = $("#stepSlider").slider(); 23 | //TODO How do you test this? Maybe manually trigger a slideChange event? 24 | expect(true).toBeTruthy(); 25 | }); 26 | 27 | it("reads the 'data-slider-precision' property (which is set to 2) and sets it on slider", function() { 28 | slider = $("#precisionSlider").slider(); 29 | slider.slider('setValue', 8.115); 30 | 31 | var sliderValue = slider.slider('getValue'); 32 | expect(sliderValue).toBe(8.12); 33 | }); 34 | 35 | it("reads the 'data-slider-orientation' property and sets it on slider", function() { 36 | slider = $("#orientationSlider").slider(); 37 | 38 | var orientationIsVertical = $("#orientationSlider").data('slider').options.orientation === 'vertical'; 39 | expect(orientationIsVertical).toBeTruthy(); 40 | }); 41 | 42 | it("reads the 'data-slider-value' property and sets it on slider", function() { 43 | slider = $("#valueSlider").slider(); 44 | 45 | var sliderValue = slider.slider('getValue'); 46 | expect(sliderValue).toBe(5); 47 | }); 48 | 49 | it("reads the 'data-slider-ticks-labels' property and sets it on slider", function() { 50 | slider = $("#sliderWithTickMarksAndLabels").slider(); 51 | 52 | var ticksLabelsAreCorrect = arraysEqual($("#sliderWithTickMarksAndLabels").data('slider').options.ticks_labels, ['$0', '$100', '$200', '$300', '$400']); 53 | expect(ticksLabelsAreCorrect).toBeTruthy(); 54 | 55 | function arraysEqual(a, b) { 56 | if (a === b) {return true;} 57 | if (a == null || b == null){return false;} 58 | if (a.length !== b.length) {return false;} 59 | 60 | for (var i = 0; i < a.length; ++i) { 61 | if (a[i] !== b[i]) {return false;} 62 | } 63 | return true; 64 | } 65 | }); 66 | 67 | it("reads the 'data-slider-selection' property and sets it on slider", function() { 68 | slider = $("#selectionSlider").slider({ 69 | id: "selectionSliderId" 70 | }); 71 | slider.slider('setValue', 0); 72 | 73 | var newSliderValue = slider.slider('getValue'); 74 | expect(newSliderValue).toBe(0); 75 | }); 76 | 77 | it("reads the 'data-slider-tooltip' property and sets it on slider", function() { 78 | slider = $("#tooltipSlider").slider({ 79 | id: "tooltipSliderElem" 80 | }); 81 | var tooltipIsHidden = $("#tooltipSliderElem").children("div.tooltip").hasClass("hide"); 82 | expect(tooltipIsHidden).toBeTruthy(); 83 | }); 84 | 85 | describe("reads the 'data-slider-handle' property and sets it on slider", function() { 86 | it("applies 'triangle' class tag to handle", function() { 87 | slider = $("#handleSlider").slider({ 88 | id: "handleSliderElem" 89 | }); 90 | var handleIsSetToTriangle = $("#handleSliderElem div.slider-handle").hasClass("triangle"); 91 | expect(handleIsSetToTriangle).toBeTruthy(); 92 | }); 93 | 94 | it("applies 'custom' class tag to handle", function() { 95 | slider = $("#customHandleSlider").slider({ 96 | id: "customHandleSliderElem" 97 | }); 98 | var handleIsSetToCustom = $("#customHandleSliderElem div.slider-handle").hasClass("custom"); 99 | expect(handleIsSetToCustom).toBeTruthy(); 100 | }); 101 | }); 102 | 103 | it("reads the 'data-slider-reversed' property and sets it on slider", function() { 104 | slider = $("#reversedSlider").slider({ 105 | id: "reversedSliderElem" 106 | }); 107 | slider.slider('setValue', 10); 108 | 109 | var sliderSelectionHeightAtMaxValue = $("#reversedSliderElem div.slider-track").children("div.slider-selection").width(); 110 | expect(sliderSelectionHeightAtMaxValue).toBe(0); 111 | }); 112 | 113 | it("reads the 'data-slider-enabled' property and sets it on slider", function() { 114 | slider = $("#disabledSlider").slider(); 115 | var isEnabled = slider.slider('isEnabled'); 116 | expect(isEnabled).not.toBeTruthy(); 117 | }); 118 | 119 | it("always sets the 'value' attribute of the original element to be the current slider value", function() { 120 | var $slider = $("#testSliderGeneric"); 121 | var val = 7; 122 | 123 | slider = $slider.slider({ 124 | value: val 125 | }); 126 | var sliderValueAttrib = $slider.val(); 127 | var valAsString = val.toString(); 128 | 129 | expect(sliderValueAttrib).toBe(valAsString); 130 | }); 131 | 132 | it("always sets the 'data-value' attribute of the original element to be the current slider value", function() { 133 | // Setup 134 | var sliderInputElem = document.getElementById("testSliderGeneric"); 135 | var val = 7; 136 | 137 | slider = new Slider(sliderInputElem, { 138 | value: val 139 | }); 140 | 141 | // Assert 142 | expect(sliderInputElem.dataset.value).toBe( val.toString() ); 143 | 144 | // Cleanup 145 | slider.destroy(); 146 | slider = null; 147 | }); 148 | 149 | afterEach(function() { 150 | if(slider) { slider.slider('destroy'); } 151 | }); 152 | 153 | describe("Test element attribute values after calling 'setValue()'", function() { 154 | var sliderObj; 155 | 156 | afterEach(function() { 157 | if (sliderObj) { 158 | sliderObj.destroy(); 159 | sliderObj = null; 160 | } 161 | }); 162 | 163 | it("The 'data-value' attribute of the original element should equal the new value", function() { 164 | // Setup 165 | var sliderInputElem = document.getElementById("testSliderGeneric"); 166 | var newVal = 7; 167 | 168 | sliderObj = new Slider(sliderInputElem, { 169 | min: 0, 170 | max: 10, 171 | value: 5 172 | }); 173 | 174 | sliderObj.setValue(newVal); 175 | 176 | expect(sliderInputElem.dataset.value).toBe(newVal.toString()); 177 | }); 178 | 179 | it("The 'value' attribute of the original element should equal the new value", function() { 180 | var sliderInputElem = document.getElementById("testSliderGeneric"); 181 | var newVal = 7; 182 | 183 | sliderObj = new Slider(sliderInputElem, { 184 | min: 0, 185 | max: 10, 186 | value: 5 187 | }); 188 | 189 | sliderObj.setValue(newVal); 190 | 191 | var sliderValueAttrib = sliderInputElem.getAttribute('value'); 192 | 193 | expect(sliderValueAttrib).toBe(newVal.toString()); 194 | }); 195 | 196 | it("The 'value' property of the original element should equal the new value", function() { 197 | var sliderInputElem = document.getElementById("testSliderGeneric"); 198 | var newVal = 7; 199 | 200 | sliderObj = new Slider(sliderInputElem, { 201 | min: 0, 202 | max: 10, 203 | value: 5 204 | }); 205 | 206 | sliderObj.setValue(newVal); 207 | 208 | expect(sliderInputElem.value).toBe(newVal.toString()); 209 | }); 210 | }); 211 | }); -------------------------------------------------------------------------------- /test/specs/EventsSpec.js: -------------------------------------------------------------------------------- 1 | describe("Event Tests", function() { 2 | var testSlider, flag, mouse; 3 | var sliderElem; 4 | 5 | beforeEach(function() { 6 | flag = false; 7 | mouse = document.createEvent('MouseEvents'); 8 | }); 9 | 10 | describe("JQuery version", function() { 11 | beforeEach(function() { 12 | testSlider = $("#testSlider2").slider({ 13 | value: 1 14 | }); 15 | sliderElem = testSlider.slider('getElement'); 16 | }); 17 | 18 | afterEach(function() { 19 | if(testSlider) { 20 | testSlider.slider('destroy'); 21 | testSlider = null; 22 | } 23 | sliderElem = null; 24 | }); 25 | 26 | describe("Mouse Events", function() { 27 | var spy; 28 | 29 | beforeEach(function() { 30 | spy = jasmine.createSpy('spy'); 31 | }); 32 | 33 | it("'slideStart' event is triggered properly and can be binded to", function(done) { 34 | testSlider.on('slideStart', spy); 35 | testSlider.data('slider')._mousedown(mouse); 36 | setTimeout(function() { 37 | expect(spy).toHaveBeenCalled(); 38 | done(); 39 | }); 40 | }); 41 | 42 | it("'slide' event is triggered properly and can be binded to", function(done) { 43 | testSlider.on('slide', spy); 44 | testSlider.data('slider')._mousemove(mouse); 45 | setTimeout(function() { 46 | expect(spy).toHaveBeenCalled(); 47 | done(); 48 | }); 49 | }); 50 | 51 | it("'slide' event sets the right value on the input", function(done) { 52 | testSlider.on('slide', function() { 53 | expect(isNaN(testSlider.val())).not.toBeTruthy(); 54 | done(); 55 | }); 56 | testSlider.data('slider')._mousemove(mouse); 57 | }); 58 | 59 | it("'slide' event value and input value properties are synchronous", function() { 60 | testSlider.on('slide', function(e) { 61 | expect(e.value.toString()).toEqual(this.value); 62 | }); 63 | testSlider.slider("setValue", 3, true, false); 64 | }); 65 | 66 | it("'change' event value and input value properties are synchronous", function() { 67 | testSlider.on('change', function(e) { 68 | expect(e.value.newValue.toString()).toEqual(testSlider.val()); 69 | }); 70 | testSlider.slider("setValue", 3, false, true); 71 | }); 72 | 73 | it("'slideStop' event is triggered properly and can be binded to", function(done) { 74 | testSlider.on('slideStop', spy); 75 | testSlider.data('slider')._mouseup(mouse); 76 | setTimeout(function() { 77 | expect(spy).toHaveBeenCalled(); 78 | done(); 79 | }); 80 | }); 81 | 82 | it("slider should not have duplicate events after calling 'refresh'", function(done) { 83 | var numTimesFired = 0; 84 | var obj = { 85 | addOne: function() { 86 | numTimesFired++; 87 | } 88 | }; 89 | spyOn(obj, 'addOne').and.callThrough(); 90 | 91 | testSlider.on('slideStop', obj.addOne); 92 | testSlider.slider('refresh'); 93 | testSlider.data('slider')._mouseup(mouse); 94 | 95 | setTimeout(function() { 96 | expect(numTimesFired).toBe(1); 97 | expect(obj.addOne.calls.count()).toBe(1); 98 | done(); 99 | }); 100 | }); 101 | 102 | describe("Disabled Slider Event Tests", function() { 103 | var spy; 104 | 105 | beforeEach(function() { 106 | testSlider.slider('disable'); 107 | spy = jasmine.createSpy('spy'); 108 | }); 109 | 110 | it("should not trigger 'slideStart' event when disabled", function(done) { 111 | testSlider.on('slideStart', spy); 112 | testSlider.data('slider')._mousedown(mouse); 113 | window.setTimeout(function() { 114 | expect(spy).not.toHaveBeenCalled(); 115 | done(); 116 | }); 117 | }); 118 | 119 | it("should not trigger 'slide' event when disabled", function(done) { 120 | testSlider.on('slide', spy); 121 | testSlider.data('slider')._mousemove(mouse); 122 | window.setTimeout(function() { 123 | expect(spy).not.toHaveBeenCalled(); 124 | done(); 125 | }); 126 | }); 127 | 128 | it("should not trigger 'slideStop' event when disabled", function(done) { 129 | testSlider.on('slideStop', spy); 130 | testSlider.data('slider')._mouseup(mouse); 131 | window.setTimeout(function() { 132 | expect(spy).not.toHaveBeenCalled(); 133 | done(); 134 | }); 135 | }); 136 | }); 137 | 138 | }); 139 | 140 | describe("Touch Events", function() { 141 | var touch; 142 | var spy; 143 | var coords; 144 | var touchStart; 145 | var touchMove; 146 | var touchEnd; 147 | 148 | /* 149 | list can be either [[x, y], [x, y]] or [x, y] 150 | */ 151 | function createTouchList(target, list) { 152 | if (Array.isArray(list) && list[0] && !Array.isArray(list[0])) { 153 | list = [list]; 154 | } 155 | list = list.map(function (entry, index) { 156 | var x = entry[0], y = entry[1], id = entry[2] ? entry[2] : index + 1; 157 | return createTouch(x, y, target, id); 158 | }); 159 | return document.createTouchList.apply(document, list); 160 | } 161 | 162 | function createTouch(x, y, target, id) { 163 | return document.createTouch(window, target, 164 | id || 1, //identifier 165 | x, //pageX / clientX 166 | y, //pageY / clientY 167 | x, //screenX 168 | y //screenY 169 | ); 170 | } 171 | 172 | function initTouchEvent(touchEvent, type, touches) { 173 | var touch1 = touches[0]; 174 | return touchEvent.initTouchEvent( 175 | touches, //touches 176 | touches, //targetTouches 177 | touches, //changedTouches 178 | type, //type 179 | window, //view 180 | touch1.screenX, //screenX 181 | touch1.screenY, //screenY 182 | touch1.clientX, //clientX 183 | touch1.clientY, //clientY 184 | false, //ctrlKey 185 | false, //altKey 186 | false, //shiftKey 187 | false //metaKey 188 | ); 189 | } 190 | 191 | function createTouchEvent(elem, type, touches) { 192 | var touchEvent = document.createEvent('TouchEvent'); 193 | if (Array.isArray(touches)) { 194 | touches = createTouchList(elem, touches); 195 | } 196 | 197 | initTouchEvent(touchEvent, type, touches); 198 | return touchEvent; 199 | } 200 | 201 | function calcTouchEventCoords(element) { 202 | var elementBB = element.getBoundingClientRect(); 203 | 204 | return { 205 | clientX: elementBB.left, 206 | clientY: elementBB.top 207 | }; 208 | } 209 | 210 | beforeEach(function() { 211 | touch = document.createEvent('Event'); 212 | var dummyTouchEvent = document.createEvent('MouseEvents'); 213 | touch.touches = [dummyTouchEvent]; 214 | window.ontouchstart = true; 215 | spy = jasmine.createSpy('spy'); 216 | 217 | coords = calcTouchEventCoords(sliderElem); 218 | touchStart = createTouchEvent(sliderElem, 'touchstart', [coords.clientX, coords.clientY]); 219 | touchMove = createTouchEvent(sliderElem, 'touchmove', [coords.clientX, coords.clientY]); 220 | touchEnd = createTouchEvent(sliderElem, 'touchend', [[0, 0]]); 221 | }); 222 | 223 | afterEach(function() { 224 | window.ontouchstart = null; 225 | }); 226 | 227 | it("'slideStart' event is triggered properly and can be binded to", function(done) { 228 | testSlider.on('slideStart', spy); 229 | 230 | window.setTimeout(function() { 231 | expect(spy).toHaveBeenCalled(); 232 | done(); 233 | }); 234 | 235 | sliderElem.dispatchEvent(touchStart); 236 | sliderElem.dispatchEvent(touchEnd); 237 | }); 238 | 239 | it("'slide' event is triggered properly and can be binded to", function(done) { 240 | testSlider.on('slide', spy); 241 | 242 | window.setTimeout(function() { 243 | expect(spy).toHaveBeenCalled(); 244 | done(); 245 | }); 246 | 247 | // Expect to fail if ONLY dispatching 'touchmove' because `preventDefault()` will prevent 248 | // the browser from sending the corresponding 'mousemove'. 249 | // The 'mousedown' event must happen first via 'touchstart'. 250 | sliderElem.dispatchEvent(touchStart); 251 | sliderElem.dispatchEvent(touchMove); 252 | // Always call 'touchend' to remove any touch event listeners on the document. 253 | sliderElem.dispatchEvent(touchEnd); 254 | }); 255 | 256 | it("'slide' event sets the right value on the input", function(done) { 257 | testSlider.on('slide', function() { 258 | expect(isNaN(testSlider.val())).not.toBeTruthy(); 259 | done(); 260 | }); 261 | 262 | sliderElem.dispatchEvent(touchStart); 263 | sliderElem.dispatchEvent(touchMove); 264 | sliderElem.dispatchEvent(touchEnd); 265 | }); 266 | 267 | it("'slide' event value and input value properties are synchronous", function() { 268 | testSlider.on('slide', function(e) { 269 | expect(e.value.toString()).toEqual(testSlider.val()); 270 | }); 271 | testSlider.slider("setValue", 3, true, false); 272 | }); 273 | 274 | it("'change' event value and input value properties are synchronous", function() { 275 | testSlider.on('change', function(e) { 276 | expect(e.value.newValue.toString()).toEqual(testSlider.val()); 277 | }); 278 | testSlider.slider("setValue", 3, false, true); 279 | }); 280 | 281 | it("'slideStop' event is triggered properly and can be binded to", function(done) { 282 | testSlider.on('slideStop', spy); 283 | 284 | window.setTimeout(function() { 285 | expect(spy).toHaveBeenCalled(); 286 | done(); 287 | }); 288 | 289 | sliderElem.dispatchEvent(touchStart); 290 | sliderElem.dispatchEvent(touchMove); 291 | sliderElem.dispatchEvent(touchEnd); 292 | }); 293 | 294 | it("slider should not have duplicate events after calling 'refresh'", function(done) { 295 | // FIXME: Should set `flag` to 0 and make sure spy is called only once 296 | testSlider.on('slideStop', spy); 297 | 298 | window.setTimeout(function() { 299 | expect(spy).toHaveBeenCalled(); 300 | done(); 301 | }); 302 | 303 | sliderElem.dispatchEvent(touchStart); 304 | sliderElem.dispatchEvent(touchMove); 305 | sliderElem.dispatchEvent(touchEnd); 306 | testSlider.slider('refresh'); 307 | }); 308 | 309 | it("slider should not bind multiple touchstart events after calling 'refresh'", function(done) { 310 | flag = 0; 311 | var obj = { 312 | addOne: function() { 313 | flag++; 314 | } 315 | }; 316 | spyOn(obj, 'addOne').and.callThrough(); 317 | 318 | touch.initEvent("touchstart", true, true); 319 | 320 | testSlider.on('slideStart', obj.addOne); 321 | 322 | var handleElem = $('#testSlider2').prev('div.slider').find('.slider-handle:first').get(0); 323 | handleElem.dispatchEvent(touchStart); 324 | handleElem.dispatchEvent(touchMove); 325 | handleElem.dispatchEvent(touchEnd); 326 | testSlider.slider('refresh'); 327 | 328 | window.setTimeout(function() { 329 | expect(flag).toBe(1); 330 | expect(obj.addOne.calls.count()).toBe(1); 331 | done(); 332 | }); 333 | }); 334 | 335 | describe("Disabled Slider Event Tests", function() { 336 | var spy; 337 | 338 | beforeEach(function() { 339 | testSlider.slider('disable'); 340 | spy = jasmine.createSpy('spy'); 341 | }); 342 | 343 | it("should not trigger 'slideStart' event when disabled", function(done) { 344 | touch.initEvent("touchstart"); 345 | 346 | testSlider.on('slideStart', spy); 347 | testSlider.data('slider')._mousedown(touch); 348 | 349 | window.setTimeout(function() { 350 | expect(spy).not.toHaveBeenCalled(); 351 | done(); 352 | }); 353 | }); 354 | 355 | it("should not trigger 'slide' event when disabled", function(done) { 356 | touch.initEvent("touchmove"); 357 | 358 | testSlider.on('slide', spy); 359 | testSlider.data('slider')._mousemove(touch); 360 | 361 | window.setTimeout(function() { 362 | expect(spy).not.toHaveBeenCalled(); 363 | done(); 364 | }); 365 | }); 366 | 367 | it("should not trigger 'slideStop' event when disabled", function(done) { 368 | touch.initEvent("touchend"); 369 | 370 | testSlider.on('slideStop', spy); 371 | testSlider.data('slider')._mouseup(mouse); 372 | 373 | window.setTimeout(function() { 374 | expect(spy).not.toHaveBeenCalled(); 375 | done(); 376 | }); 377 | }); 378 | }); 379 | 380 | }); 381 | 382 | describe("Enabled/Disabled tests", function() { 383 | var spy; 384 | 385 | beforeEach(function() { 386 | spy = jasmine.createSpy('spy'); 387 | }); 388 | 389 | it("'slideDisabled' event is triggered properly and can be binded to", function(done) { 390 | testSlider.on('slideDisabled', spy); 391 | testSlider.slider('disable'); 392 | window.setTimeout(function() { 393 | expect(spy).toHaveBeenCalled(); 394 | done(); 395 | }); 396 | }); 397 | 398 | it("'slideDisabled' event is triggered properly and can be binded to", function(done) { 399 | testSlider.on('slideEnabled', spy); 400 | testSlider.slider('disable'); 401 | testSlider.slider('enable'); 402 | window.setTimeout(function() { 403 | expect(spy).toHaveBeenCalled(); 404 | done(); 405 | }); 406 | }); 407 | 408 | it("'change' event is triggered properly and can be binded to", function(done) { 409 | testSlider.on('change', spy); 410 | testSlider.slider("setValue", 3, false, true); 411 | window.setTimeout(function() { 412 | expect(spy).toHaveBeenCalled(); 413 | done(); 414 | }); 415 | }); 416 | }); 417 | 418 | }); // End of JQuery version tests 419 | 420 | describe("CommonJS version", function() { 421 | describe("Event repetition tests", function() { 422 | var testSlider, numTimesFired; 423 | var testObj; 424 | 425 | beforeEach(function() { 426 | testSlider = new Slider("#testSlider2"); 427 | numTimesFired = 0; 428 | testObj = { 429 | addOne: function() { 430 | numTimesFired++; 431 | } 432 | }; 433 | }); 434 | 435 | afterEach(function() { 436 | testSlider.destroy(); 437 | }); 438 | 439 | it("'slide' event is triggered only once per slide action", function(done) { 440 | spyOn(testObj, 'addOne').and.callThrough(); 441 | 442 | testSlider.on('slide', testObj.addOne); 443 | testSlider._mousemove(mouse); 444 | 445 | setTimeout(function() { 446 | expect(numTimesFired).toBe(1); 447 | expect(testObj.addOne.calls.count()).toBe(1); 448 | done(); 449 | }); 450 | }); 451 | 452 | it("'slideStart' event is triggered only once per slide action", function(done) { 453 | spyOn(testObj, 'addOne').and.callThrough(); 454 | 455 | testSlider.on('slideStart', testObj.addOne); 456 | testSlider._mousedown(mouse); 457 | 458 | setTimeout(function() { 459 | expect(numTimesFired).toBe(1); 460 | expect(testObj.addOne.calls.count()).toBe(1); 461 | done(); 462 | }); 463 | }); 464 | 465 | it("'slideStop' event is triggered only once per slide action", function(done) { 466 | spyOn(testObj, 'addOne').and.callThrough(); 467 | 468 | testSlider.on('slideStop', testObj.addOne); 469 | testSlider._mouseup(mouse); 470 | 471 | setTimeout(function() { 472 | expect(numTimesFired).toBe(1); 473 | expect(testObj.addOne.calls.count()).toBe(1); 474 | done(); 475 | }); 476 | }); 477 | 478 | it("'change' event is triggered only once per value change action", function(done) { 479 | spyOn(testObj, 'addOne').and.callThrough(); 480 | 481 | testSlider.on('change', testObj.addOne); 482 | testSlider.setValue(3, false, true); 483 | 484 | setTimeout(function() { 485 | expect(numTimesFired).toBe(1); 486 | expect(testObj.addOne.calls.count()).toBe(1); 487 | done(); 488 | }); 489 | }); 490 | }); 491 | }); // End of common JS tests 492 | 493 | }); // End of spec 494 | -------------------------------------------------------------------------------- /test/specs/FocusOptionSpec.js: -------------------------------------------------------------------------------- 1 | /* 2 | ****************** 3 | 4 | Focus Option Tests 5 | 6 | ****************** 7 | 8 | This spec has tests for checking proper behavior of the focus option. 9 | */ 10 | 11 | describe("Focus Option Tests", function() { 12 | 13 | var testSlider; 14 | 15 | var simulateMousedown = function(target, pos) { 16 | var myEvent = document.createEvent("MouseEvents"); 17 | myEvent.initEvent("mousedown", true, true); 18 | myEvent.pageX = pos; 19 | myEvent.pageY = pos; 20 | target.dispatchEvent(myEvent); 21 | }; 22 | 23 | it("handle should not be focused after value change when 'focus' is false", function() { 24 | testSlider = $("#testSlider1").slider({ 25 | min : 0, 26 | max : 10, 27 | value: 0, 28 | focus: false, 29 | id : "testSlider" 30 | }); 31 | 32 | var hasFocus; 33 | $("#testSlider").find(".min-slider-handle").focus(function() { 34 | hasFocus = true; 35 | }); 36 | 37 | simulateMousedown($("#testSlider").find(".slider-track-high").get(0), 1000); 38 | 39 | expect(hasFocus).toBe(undefined); 40 | }); 41 | 42 | it("handle should be focused after value change when 'focus' is true", function() { 43 | testSlider = $("#testSlider1").slider({ 44 | min : 0, 45 | max : 10, 46 | value: 0, 47 | focus: true, 48 | id : "testSlider" 49 | }); 50 | 51 | var hasFocus; 52 | $("#testSlider").find(".min-slider-handle").focus(function() { 53 | hasFocus = true; 54 | }); 55 | 56 | simulateMousedown($("#testSlider").find(".slider-track-high").get(0), 1000); 57 | 58 | expect(hasFocus).toBe(true); 59 | }); 60 | 61 | afterEach(function() { 62 | if (testSlider) { 63 | testSlider.slider("destroy"); 64 | testSlider = null; 65 | } 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/specs/LogarithmicScaleSpec.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | ************************* 4 | 5 | Logarithmic Scale Tests 6 | 7 | ************************* 8 | 9 | */ 10 | describe("Slider with logarithmic scale tests", function() { 11 | 12 | var testSlider; 13 | 14 | describe("Should properly position the slider", function() { 15 | 16 | function testSliderPosition(min, max, value){ 17 | testSlider = $("#testSlider1").slider({ 18 | min: min, 19 | max: max, 20 | scale: 'logarithmic', 21 | value: value // This should be at 50% 22 | }); 23 | var expectedPostition = 210 / 2 + 'px'; 24 | var handle = $("#testSlider1").prev('div.slider').find('.min-slider-handle'); 25 | expect(handle.css('left')).toBe(expectedPostition); 26 | } 27 | 28 | it("with positive values", function() { 29 | testSliderPosition(1, 10000, 100); 30 | }); 31 | 32 | it("with zero", function() { 33 | testSliderPosition(0, 63, 7); 34 | }); 35 | 36 | it("with a negative value", function() { 37 | testSliderPosition(-7, 56, 0); 38 | }); 39 | }); 40 | 41 | it("Should properly position the tick marks", function() { 42 | testSlider = $("#testSlider1").slider({ 43 | min: 1, 44 | max: 100, 45 | scale: 'logarithmic', 46 | ticks: [1,10,20,50,100] 47 | }); 48 | 49 | // Position expected for the '10' tick 50 | var expectedTickOnePosition = 210 / 2 + 'px'; //should be at 50% 51 | 52 | var handle = $("#testSlider1").prev('div.slider').find(".slider-tick").eq(1); 53 | expect(handle.css('left')).toBe(expectedTickOnePosition); 54 | }); 55 | 56 | it("Should use step size when navigating the keyboard", function() { 57 | testSlider = $("#testSlider1").slider({ 58 | min: 1, 59 | max: 10000, 60 | scale: 'logarithmic', 61 | value: 100, 62 | step: 5 63 | }); 64 | 65 | // Focus on handle1 66 | var handle1 = $("#testSlider1").prev('div.slider').find('.slider-handle'); 67 | handle1.focus(); 68 | 69 | // Create keyboard event 70 | var keyboardEvent = document.createEvent("Events"); 71 | keyboardEvent.initEvent("keydown", true, true); 72 | 73 | var keyPresses = 0; 74 | handle1.on("keydown", function() { 75 | keyPresses++; 76 | var value = $("#testSlider1").slider('getValue'); 77 | expect(value).toBe(100 + keyPresses*5); 78 | }); 79 | 80 | keyboardEvent.keyCode = keyboardEvent.which = 39; // RIGHT 81 | for (var i = 0; i < 5; i++) { 82 | handle1[0].dispatchEvent(keyboardEvent); 83 | } 84 | }); 85 | 86 | afterEach(function() { 87 | if(testSlider) { 88 | testSlider.slider('destroy'); 89 | testSlider = null; 90 | } 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /test/specs/LowAndHighTrackSpec.js: -------------------------------------------------------------------------------- 1 | /* 2 | ********************** 3 | 4 | Left/Right Track Tests 5 | 6 | ********************** 7 | 8 | This spec has tests for checking that the widths of the left and right 9 | segments are the correct widths and colors, based on their CSS. 10 | */ 11 | describe("Low/High Track Tests", function() { 12 | 13 | var unstyledID = "low-high-slider"; 14 | var styledID = "low-high-slider-styled"; 15 | 16 | var testSlider; 17 | 18 | describe("Single-value sliders, no styling", function() { 19 | 20 | var id = unstyledID; 21 | 22 | beforeEach(function() { 23 | testSlider = $("#testSlider1").slider({ 24 | id: id, 25 | min: 0, 26 | max: 10, 27 | value: 5 28 | }); 29 | }); 30 | 31 | it("low track width is zero", function() 32 | { 33 | var leftTrack = $("#" + id + " .slider-track-low"); 34 | expect($(leftTrack).css("width")).toBe("0px"); 35 | }); 36 | 37 | it("high track width is 50%", function() 38 | { 39 | var rightTrack = $("#" + id + " .slider-track-high"); 40 | var trackWidth = rightTrack.parent().width(); 41 | expect($(rightTrack).css("width")).toBe((trackWidth / 2) + "px"); 42 | }); 43 | 44 | it("high track is transparent", function() 45 | { 46 | var rightTrack = $("#" + id + " .slider-track-high"); 47 | var rightColor = rightTrack.css("background-color"); 48 | var isTransparent = rightColor.match(/rgba\([0-9]{1,3}, [0-9]{1,3}, [0-9]{1,3}, 0\)/); 49 | expect(isTransparent).toBeTruthy(); 50 | }); 51 | 52 | afterEach(function() { 53 | if(testSlider) { 54 | testSlider.slider('destroy'); 55 | testSlider = null; 56 | } 57 | }); 58 | }); 59 | 60 | describe("Single-value sliders, with styling", function() { 61 | 62 | var id = styledID; 63 | 64 | beforeEach(function() { 65 | testSlider = $("#testSlider1").slider({ 66 | id: id, 67 | min: 0, 68 | max: 10, 69 | value: 5 70 | }); 71 | }); 72 | 73 | it("low track width is zero", function() 74 | { 75 | var leftTrack = $("#" + id + " .slider-track-low"); 76 | expect($(leftTrack).css("width")).toBe("0px"); 77 | }); 78 | 79 | it("high track width is 50%", function() 80 | { 81 | var rightTrack = $("#" + id + " .slider-track-high"); 82 | var trackWidth = rightTrack.parent().width(); 83 | expect($(rightTrack).css("width")).toBe((trackWidth / 2) + "px"); 84 | }); 85 | 86 | it("high track is red", function() 87 | { 88 | var rightTrack = $("#" + id + " .slider-track-high"); 89 | var rightColor = rightTrack.css("background-color"); 90 | expect(rightColor).toBe("rgb(255, 0, 0)"); 91 | }); 92 | 93 | afterEach(function() { 94 | if(testSlider) { 95 | testSlider.slider('destroy'); 96 | testSlider = null; 97 | } 98 | }); 99 | }); 100 | 101 | describe("Range sliders, no styling", function() { 102 | 103 | var id = unstyledID; 104 | var values = { 105 | min: 0, 106 | max: 10, 107 | values: [ 4, 6 ] 108 | }; 109 | 110 | beforeEach(function() { 111 | testSlider = $("#testSlider1").slider({ 112 | id: id, 113 | min: values.min, 114 | max: values.max, 115 | range: true, 116 | value: values.values 117 | }); 118 | }); 119 | 120 | it("low track width is correct", function() 121 | { 122 | var leftTrack = $("#" + id + " .slider-track-low"); 123 | 124 | var trackWidth = leftTrack.parent().width(); 125 | var expectedWidth = ((values.values[0] - values.min) / (values.max - values.min)) * trackWidth; 126 | 127 | expect($(leftTrack).css("width")).toBe(expectedWidth + "px"); 128 | }); 129 | 130 | it("high track width is correct", function() 131 | { 132 | var rightTrack = $("#" + id + " .slider-track-high"); 133 | var trackWidth = rightTrack.parent().width(); 134 | 135 | var expectedWidth = ((values.max - values.values[1]) / (values.max - values.min)) * trackWidth; 136 | 137 | expect($(rightTrack).css("width")).toBe(expectedWidth + "px"); 138 | }); 139 | 140 | it("low track is transparent", function() 141 | { 142 | var leftTrack = $("#" + id + " .slider-track-low"); 143 | var leftColor = leftTrack.css("background-color"); 144 | var isTransparent = leftColor.match(/rgba\([0-9]{1,3}, [0-9]{1,3}, [0-9]{1,3}, 0\)/); 145 | expect(isTransparent).toBeTruthy(); 146 | }); 147 | 148 | it("high track is transparent", function() 149 | { 150 | var rightTrack = $("#" + id + " .slider-track-high"); 151 | var rightColor = rightTrack.css("background-color"); 152 | var isTransparent = rightColor.match(/rgba\([0-9]{1,3}, [0-9]{1,3}, [0-9]{1,3}, 0\)/); 153 | expect(isTransparent).toBeTruthy(); 154 | }); 155 | 156 | afterEach(function() { 157 | if(testSlider) { 158 | testSlider.slider('destroy'); 159 | testSlider = null; 160 | } 161 | }); 162 | }); 163 | 164 | describe("Range sliders, with styling", function() { 165 | 166 | var id = styledID; 167 | var values = { 168 | min: 0, 169 | max: 10, 170 | values: [ 4, 6 ] 171 | }; 172 | 173 | beforeEach(function() { 174 | testSlider = $("#testSlider1").slider({ 175 | id: id, 176 | min: values.min, 177 | max: values.max, 178 | range: true, 179 | value: values.values 180 | }); 181 | }); 182 | 183 | it("low track width is correct", function() 184 | { 185 | var leftTrack = $("#" + id + " .slider-track-low"); 186 | 187 | var trackWidth = leftTrack.parent().width(); 188 | var expectedWidth = ((values.values[0] - values.min) / (values.max - values.min)) * trackWidth; 189 | 190 | expect($(leftTrack).css("width")).toBe(expectedWidth + "px"); 191 | }); 192 | 193 | it("high track width is correct", function() 194 | { 195 | var rightTrack = $("#" + id + " .slider-track-high"); 196 | var trackWidth = rightTrack.parent().width(); 197 | 198 | var expectedWidth = ((values.max - values.values[1]) / (values.max - values.min)) * trackWidth; 199 | 200 | expect($(rightTrack).css("width")).toBe(expectedWidth + "px"); 201 | }); 202 | 203 | it("low track is green", function() 204 | { 205 | var leftTrack = $("#" + id + " .slider-track-low"); 206 | var leftColor = leftTrack.css("background-color"); 207 | expect(leftColor).toBe("rgb(0, 255, 0)"); 208 | }); 209 | 210 | it("high track is red", function() 211 | { 212 | var rightTrack = $("#" + id + " .slider-track-high"); 213 | var rightColor = rightTrack.css("background-color"); 214 | expect(rightColor).toBe("rgb(255, 0, 0)"); 215 | }); 216 | 217 | afterEach(function() { 218 | if(testSlider) { 219 | testSlider.slider('destroy'); 220 | testSlider = null; 221 | } 222 | }); 223 | }); 224 | }); -------------------------------------------------------------------------------- /test/specs/NamespaceSpec.js: -------------------------------------------------------------------------------- 1 | describe("Namespace Tests", function() { 2 | var sourceJS = "temp/bootstrap-slider.js"; 3 | var defaultNamespace = 'slider'; 4 | var alternateNamespace = 'bootstrapSlider'; 5 | 6 | it("should always set the plugin namespace to 'bootstrapSlider'", function(done) { 7 | $.when($.getScript(sourceJS)).then(function() { 8 | expect($.fn.bootstrapSlider).toBeDefined(); 9 | done(); 10 | }); 11 | }); 12 | 13 | it("should set the plugin namespace to 'slider' if the namespace is available", function(done) { 14 | $.when($.getScript(sourceJS)).then(function() { 15 | expect($.fn.slider).toBeDefined(); 16 | done(); 17 | }); 18 | }); 19 | 20 | it("should print a console warning if the 'slider' namespace is already bound", function(done) { 21 | $.fn.slider = function() {}; 22 | spyOn(window.console, "warn"); 23 | 24 | $.when($.getScript(sourceJS)).then(function() { 25 | var expectedWarningMessage = "bootstrap-slider.js - WARNING: $.fn.slider namespace is already bound. Use the $.fn.bootstrapSlider namespace instead."; 26 | expect(window.console.warn).toHaveBeenCalledWith(expectedWarningMessage); 27 | done(); 28 | }); 29 | }); 30 | 31 | it("Should not create instance when 'slider' namespace is in use", function(done) { 32 | $.fn.slider = function() {}; // Overwrite temporarily 33 | 34 | $.when($.getScript(sourceJS)).then(function() { 35 | var $testSlider = $('#testSlider1').bootstrapSlider(); 36 | 37 | var sliderInst = $testSlider.data(defaultNamespace); 38 | expect(sliderInst).toBeUndefined(); 39 | 40 | $testSlider.bootstrapSlider('destroy'); 41 | 42 | done(); 43 | }); 44 | }); 45 | 46 | it("Should create instance associated with the alternate 'bootstrapSlider' namespace", function(done) { 47 | $.fn.slider = function() {}; 48 | 49 | $.when($.getScript(sourceJS)).then(function() { 50 | var $testSlider = $('#testSlider1').bootstrapSlider(); 51 | 52 | var sliderInst = $testSlider.data(alternateNamespace); 53 | expect(sliderInst).toBeTruthy(); 54 | 55 | $testSlider.bootstrapSlider('destroy'); 56 | 57 | done(); 58 | }); 59 | }); 60 | 61 | afterEach(function(done) { 62 | /* 63 | Set the namespaces back to undefined and reload slider 64 | So that namespace is returned to $.fn.slider 65 | */ 66 | $.fn.bootstrapSlider = undefined; 67 | $.fn.slider = undefined; 68 | 69 | $.when($.getScript(sourceJS)).then(function() { 70 | done(); 71 | }); 72 | }); 73 | 74 | }); -------------------------------------------------------------------------------- /test/specs/OrientationSpec.js: -------------------------------------------------------------------------------- 1 | describe("Orientation Tests", function() { 2 | var testSlider; 3 | var sliderHandleTopPos; 4 | var sliderHandleLeftPos; 5 | 6 | describe("Vertical", function() { 7 | beforeEach(function() { 8 | testSlider = new Slider("#orientationSlider", { 9 | id: "orientationSliderId", 10 | orientation: "vertical", 11 | min: 0, 12 | max: 10, 13 | value: 5 14 | }); 15 | 16 | var sliderHandleEl = document.querySelector("#orientationSliderId .slider-handle"); 17 | var sliderHandleBoundingBoxInfo = sliderHandleEl.getBoundingClientRect(); 18 | sliderHandleTopPos = sliderHandleBoundingBoxInfo.top; 19 | sliderHandleLeftPos = sliderHandleBoundingBoxInfo.left; 20 | }); 21 | 22 | afterEach(function() { 23 | if(testSlider) { 24 | testSlider.destroy(); 25 | } 26 | }); 27 | 28 | it("slides up when handle moves upwards", function() { 29 | var mousemove = document.createEvent('MouseEvents'); 30 | var mousemoveX = sliderHandleLeftPos; 31 | var mousemoveY = sliderHandleTopPos - 100; 32 | var newSliderValue; 33 | 34 | mousemove.initMouseEvent( 35 | "mousedown", 36 | true /* bubble */, 37 | true /* cancelable */, 38 | window, 39 | null, 40 | 0, 0, mousemoveX, mousemoveY, /* coordinates */ 41 | false, false, false, false, /* modifier keys */ 42 | 0 /*left*/, 43 | null 44 | ); 45 | testSlider.sliderElem.dispatchEvent(mousemove); 46 | newSliderValue = testSlider.getValue(); 47 | 48 | expect(newSliderValue).toBeLessThan(5); 49 | }); 50 | 51 | it("slides down when handle moves downwards", function() { 52 | var mousemove = document.createEvent('MouseEvents'); 53 | var mousemoveX = sliderHandleLeftPos; 54 | var mousemoveY = sliderHandleTopPos + 100; 55 | var newSliderValue; 56 | 57 | mousemove.initMouseEvent( 58 | "mousedown", 59 | true /* bubble */, 60 | true /* cancelable */, 61 | window, 62 | null, 63 | 0, 0, mousemoveX, mousemoveY, /* coordinates */ 64 | false, false, false, false, /* modifier keys */ 65 | 0 /*left*/, 66 | null 67 | ); 68 | testSlider.sliderElem.dispatchEvent(mousemove); 69 | newSliderValue = testSlider.getValue(); 70 | 71 | expect(newSliderValue).toBeGreaterThan(5); 72 | }); 73 | }); 74 | 75 | }); // End of spec -------------------------------------------------------------------------------- /test/specs/RangeHighlightsSpec.js: -------------------------------------------------------------------------------- 1 | /* 2 | RangeHighlights Render Tests 3 | */ 4 | 5 | describe("RangeHighlights Render Tests", function() { 6 | var testSlider1; 7 | var testSlider2; 8 | var testSlider3; 9 | var testSlider4; 10 | 11 | //setup 12 | beforeEach(function() { 13 | var rangeHighlightsOpts1 = [ 14 | { "start": 2, "end": 5, "class": "category1" }, // left: 10%; width: 15% 15 | { "start": 7, "end": 8, "class": "category2" }, // left: 35%; width: 5% 16 | { "start": 17, "end": 19 }, // left: 85%; width: 10% 17 | { "start": 17, "end": 24 }, //out of range - not visible 18 | { "start": -3, "end": 19 } //out of range - not visible 19 | ]; 20 | 21 | var rangeHighlightsOpts2 = [ 22 | { "start": 2, "end": 5, "class": "category1" }, // top: 10%; height: 15% 23 | { "start": 7, "end": 8, "class": "category2" }, // top: 35%; height: 5% 24 | { "start": 17, "end": 19 }, // top: 85%; height: 10% 25 | { "start": 7, "end": -4 }, //out of range - not visible 26 | { "start": 23, "end": 15 } //out of range - not visible 27 | ]; 28 | 29 | testSlider1 = $('#testSlider1').slider({ 30 | id: 'slider1', 31 | min: 0, 32 | max: 20, 33 | step: 1, 34 | value: 14, 35 | rangeHighlights: rangeHighlightsOpts1 36 | }); 37 | 38 | testSlider2 = $('#testSlider2').slider({ 39 | id: 'slider2', 40 | min: 0, 41 | max: 20, 42 | step: 1, 43 | value: 14, 44 | orientation: 'vertical', 45 | rangeHighlights: rangeHighlightsOpts2 46 | }); 47 | 48 | testSlider3 = $('#testSlider3').slider({ 49 | id: 'slider3', 50 | min: 0, 51 | max: 20, 52 | step: 1, 53 | value: 14, 54 | reversed: true, 55 | rangeHighlights: rangeHighlightsOpts1 56 | }); 57 | 58 | testSlider4 = $('#testSlider4').slider({ 59 | id: 'slider4', 60 | min: 0, 61 | max: 20, 62 | step: 1, 63 | value: 14, 64 | reversed: true, 65 | orientation: 'vertical', 66 | rangeHighlights: rangeHighlightsOpts2 67 | }); 68 | }); 69 | 70 | //cleanup 71 | afterEach(function() { 72 | testSlider1.slider('destroy'); 73 | testSlider1 = null; 74 | 75 | testSlider2.slider('destroy'); 76 | testSlider2 = null; 77 | 78 | testSlider3.slider('destroy'); 79 | testSlider3 = null; 80 | 81 | testSlider4.slider('destroy'); 82 | testSlider4 = null; 83 | }); 84 | 85 | //test the visibility of ranges e.g. : { "start": 23, "end": 15 } - out of range - not visible 86 | function testHighlightedElements(sliderId, isHorizontal, expections) { 87 | 88 | //check elements exist 89 | it("Highlighted ranges are rendered - " + sliderId, function() { 90 | expect($(sliderId).length).toBe(1); 91 | expect($(sliderId + ' .slider-rangeHighlight').length).toBe(5); 92 | expect($(sliderId + ' .slider-rangeHighlight.category1').length).toBe(1); 93 | expect($(sliderId + ' .slider-rangeHighlight.category2').length).toBe(1); 94 | }); 95 | 96 | //check elements exist within proper display value 97 | it("Highlighted ranges render inside the slider's bounds " + sliderId, function() { 98 | expect($(sliderId).length).toBe(1); 99 | 100 | var ranges = $(sliderId + ' .slider-rangeHighlight'); 101 | expect(ranges.length).toBe(5); 102 | 103 | for (var i = 0; i < ranges.length; i++) { 104 | expect($(ranges[i]).is(":visible")).toBe(expections[i].isVisible); 105 | if (expections[i].isVisible) { 106 | if(isHorizontal) { 107 | expect(_getLeftPercent($(ranges[i]))).toBe(expections[i].start); 108 | expect(_getWidthPercent($(ranges[i]))).toBe(expections[i].size); 109 | } else { 110 | expect(_getTopPercent($(ranges[i]))).toBe(expections[i].start); 111 | expect(_getHeightPercent($(ranges[i]))).toBe(expections[i].size); 112 | } 113 | } 114 | } 115 | }); 116 | 117 | } 118 | 119 | function _getLeftPercent(element) { 120 | return Math.round(100 * element.position().left / element.parent().width()) + '%'; 121 | } 122 | 123 | function _getWidthPercent(element) { 124 | var width = element.width(); 125 | var parentWidth = element.offsetParent().width(); 126 | return Math.round(100 * width / parentWidth) + '%'; 127 | } 128 | 129 | function _getTopPercent(element) { 130 | return Math.round(100 * element.position().top / element.parent().height()) + '%'; 131 | } 132 | 133 | function _getHeightPercent(element) { 134 | var height = element.height(); 135 | var parentHeight = element.offsetParent().height(); 136 | return Math.round(100 * height / parentHeight) + '%'; 137 | } 138 | 139 | //test both testSlider 140 | testHighlightedElements('#slider1', true, [{ 141 | isVisible: true, 142 | start: '10%', 143 | size: '15%' 144 | }, { 145 | isVisible: true, 146 | start: '35%', 147 | size: '5%' 148 | }, { 149 | isVisible: true, 150 | start: '85%', 151 | size: '10%' 152 | }, { 153 | isVisible: false, 154 | start: '85%', 155 | size: '10%' 156 | }, { 157 | isVisible: false, 158 | start: '85%', 159 | size: '10%' 160 | }]); 161 | testHighlightedElements('#slider2', false, [{ 162 | isVisible: true, 163 | start: '10%', 164 | size: '15%' 165 | }, { 166 | isVisible: true, 167 | start: '35%', 168 | size: '5%' 169 | }, { 170 | isVisible: true, 171 | start: '85%', 172 | size: '10%' 173 | }, { 174 | isVisible: false, 175 | start: '85%', 176 | size: '10%' 177 | }, { 178 | isVisible: false, 179 | start: '85%', 180 | size: '10%' 181 | }]); 182 | testHighlightedElements('#slider3', true, [{ 183 | isVisible: true, 184 | start: '75%', 185 | size: '15%' 186 | }, { 187 | isVisible: true, 188 | start: '60%', 189 | size: '5%' 190 | }, { 191 | isVisible: true, 192 | start: '5%', 193 | size: '10%' 194 | }, { 195 | isVisible: false, 196 | start: '5%', 197 | size: '10%' 198 | }, { 199 | isVisible: false, 200 | start: '5%', 201 | size: '10%' 202 | }]); 203 | testHighlightedElements('#slider4', false, [{ 204 | isVisible: true, 205 | start: '75%', 206 | size: '15%' 207 | }, { 208 | isVisible: true, 209 | start: '60%', 210 | size: '5%' 211 | }, { 212 | isVisible: true, 213 | start: '5%', 214 | size: '10%' 215 | }, { 216 | isVisible: false, 217 | start: '5%', 218 | size: '10%' 219 | }, { 220 | isVisible: false, 221 | start: '5%', 222 | size: '10%' 223 | }]); 224 | }); 225 | -------------------------------------------------------------------------------- /test/specs/RefreshMethodSpec.js: -------------------------------------------------------------------------------- 1 | describe("refresh() Method Tests", function() { 2 | var testSlider; 3 | var $testSlider; 4 | var options; 5 | var initialValue, initialRangeValue; 6 | var newValue, newRangeValue; 7 | 8 | beforeEach(function() { 9 | initialValue = 5; 10 | initialRangeValue = [4, 5]; 11 | newValue = 7; 12 | newRangeValue = [7, 10]; 13 | 14 | options = { 15 | id: 'mySlider', 16 | min: 0, 17 | max: 10, 18 | step: 1, 19 | value: initialValue 20 | }; 21 | }); 22 | 23 | afterEach(function() { 24 | if(testSlider) { 25 | testSlider.destroy(); 26 | testSlider = null; 27 | } 28 | if ($testSlider) { 29 | $testSlider.slider('destroy'); 30 | $testSlider = null; 31 | } 32 | }); 33 | 34 | it("does not convert a non-range slider into a range slider when invoked", function() { 35 | // Initialize non-range slider 36 | testSlider = new Slider("#testSlider1", { 37 | min: 0, 38 | max: 10, 39 | value: 5 40 | }); 41 | 42 | // Assert that slider is non-range slider 43 | var initialValue = testSlider.getValue(); 44 | var sliderIsRangeValue = initialValue instanceof Array; 45 | 46 | expect(sliderIsRangeValue).toBeFalsy(); 47 | 48 | // Invoke refresh() method 49 | testSlider.refresh(); 50 | 51 | // Assert that slider remains a non-range slider 52 | var afterRefreshValue = testSlider.getValue(); 53 | sliderIsRangeValue = afterRefreshValue instanceof Array; 54 | 55 | expect(sliderIsRangeValue).toBeFalsy(); 56 | }); 57 | 58 | it("should reset slider to its default value on refresh", function() { 59 | // Initialize non-range slider 60 | testSlider = new Slider('#testSlider1', options); 61 | 62 | testSlider.setValue(newValue, true, true); 63 | testSlider.refresh(); 64 | 65 | expect(testSlider.getValue()).toBe(initialValue); 66 | }); 67 | 68 | it("should maintain its current value on refresh", function() { 69 | // Initialize non-range slider 70 | testSlider = new Slider('#testSlider1', options); 71 | 72 | testSlider.setValue(newValue, true, true); 73 | testSlider.refresh({ useCurrentValue: true }); 74 | 75 | expect(testSlider.getValue()).toBe(newValue); 76 | }); 77 | 78 | it("should reset slider to its default value on refresh (jQuery)", function() { 79 | // Initialize non-range slider 80 | $testSlider = $('#testSlider1').slider(options); 81 | 82 | $testSlider.slider('setValue', newValue, true, true); 83 | $testSlider.slider('refresh'); 84 | 85 | expect($testSlider.slider('getValue')).toBe(initialValue); 86 | }); 87 | 88 | it("should maintain its current value on refresh (jQuery)", function() { 89 | // Initialize non-range slider 90 | $testSlider = $('#testSlider1').slider(options); 91 | 92 | $testSlider.slider('setValue', newValue, true, true); 93 | $testSlider.slider('refresh', { useCurrentValue: true }); 94 | 95 | expect($testSlider.slider('getValue')).toBe(newValue); 96 | }); 97 | 98 | it("should reset slider to its default value on refresh (range)", function() { 99 | // Initialize range slider 100 | options.value = initialRangeValue; 101 | options.range = true; 102 | testSlider = new Slider('#testSlider1', options); 103 | 104 | testSlider.setValue(newRangeValue, true, true); 105 | testSlider.refresh(); 106 | 107 | expect(testSlider.getValue()).toBe(initialRangeValue); 108 | }); 109 | 110 | it("should maintain its current value on refresh (range)", function() { 111 | // Initialize range slider 112 | options.value = initialRangeValue; 113 | options.range = true; 114 | testSlider = new Slider('#testSlider1', options); 115 | 116 | testSlider.setValue(newRangeValue, true, true); 117 | testSlider.refresh({ useCurrentValue: true }); 118 | 119 | expect(testSlider.getValue()).toBe(newRangeValue); 120 | }); 121 | 122 | }); // End of spec -------------------------------------------------------------------------------- /test/specs/ResizeSpec.js: -------------------------------------------------------------------------------- 1 | describe("Resize Tests", function() { 2 | var testSlider, dataSlider; 3 | 4 | afterEach(function() { 5 | if(testSlider) { 6 | testSlider.slider('destroy'); 7 | testSlider = null; 8 | dataSlider = null; 9 | } 10 | }); 11 | 12 | describe("Tick Labels", function() { 13 | 14 | var $el, options; 15 | 16 | beforeEach(function() { 17 | var tick = [0, 100, 200, 300, 400]; 18 | options = { 19 | ticks: tick, 20 | ticks_labels: ['$0', '$100', '$200', '$300', '$400'] 21 | }; 22 | }); 23 | 24 | it("should resize the tick labels when horizontal", function() { 25 | 26 | $el = $("#resizeSlider"); 27 | testSlider = $el.slider(options); 28 | dataSlider = testSlider.data('slider'); 29 | 30 | $('.slider').width(210); 31 | dataSlider._resize(); 32 | expect($el.siblings('div.slider').find('.slider-tick-label:eq(0)').width()).toBe(52.5); 33 | 34 | $('.slider').width(120); 35 | dataSlider._resize(); 36 | expect($el.siblings('div.slider').find('.slider-tick-label:eq(0)').width()).toBe(30); 37 | 38 | $('.slider').width(900); 39 | dataSlider._resize(); 40 | expect($el.siblings('div.slider').find('.slider-tick-label:eq(1)').width()).toBe(225); 41 | 42 | $('.slider').width(210); 43 | dataSlider._resize(); 44 | expect($el.siblings('div.slider').find('.slider-tick-label:eq(0)').width()).toBe(52.5); 45 | }); 46 | 47 | it('should resize the tick labels when vertical', function() { 48 | 49 | var $el = $("#resizeSliderVertical"); 50 | testSlider = $el.slider(options); 51 | dataSlider = testSlider.data('slider'); 52 | 53 | $('.slider').height(210); 54 | dataSlider._resize(); 55 | expect($el.siblings('div.slider').find('.slider-tick-label:eq(0)').height()).toBe(52.5); 56 | 57 | $('.slider').height(120); 58 | dataSlider._resize(); 59 | expect($el.siblings('div.slider').find('.slider-tick-label:eq(0)').height()).toBe(30); 60 | 61 | $('.slider').height(900); 62 | dataSlider._resize(); 63 | expect($el.siblings('div.slider').find('.slider-tick-label:eq(1)').height()).toBe(225); 64 | 65 | $('.slider').height(210); 66 | dataSlider._resize(); 67 | expect($el.siblings('div.slider').find('.slider-tick-label:eq(0)').height()).toBe(52.5); 68 | }); 69 | }); 70 | }); // End of spec 71 | -------------------------------------------------------------------------------- /test/specs/RtlOptionsSpec.js: -------------------------------------------------------------------------------- 1 | describe("RTL Tests", function() { 2 | var testSlider; 3 | 4 | afterEach(function() { 5 | if(testSlider) { 6 | testSlider.destroy(); 7 | testSlider = null; 8 | } 9 | }); 10 | 11 | describe("rtl slider tests", function() { 12 | it("should be rtl by default inside an rtl wrapper", function() { 13 | testSlider = new Slider("#rtlSlider"); 14 | 15 | var dirIsRtl = $("#rtlSlider").siblings().is(".slider-rtl"); 16 | 17 | expect(dirIsRtl).toBeTruthy(); 18 | }); 19 | 20 | it("rtl to false inside an rtl wrapper", function() { 21 | testSlider = new Slider("#rtlSlider", { 22 | rtl: false 23 | }); 24 | 25 | var dirIsRtl = $("#rtlSlider").siblings().is(".slider-rtl"); 26 | 27 | expect(dirIsRtl).not.toBeTruthy(); 28 | }); 29 | 30 | it("rtl to true inside an ltr wrapper", function() { 31 | testSlider = new Slider("#testSlider1", { 32 | rtl: true 33 | }); 34 | 35 | var dirIsRtl = $("#testSlider1").siblings().is(".slider-rtl"); 36 | 37 | expect(dirIsRtl).toBeTruthy(); 38 | }); 39 | 40 | it("slider use inversed left and right inline style", function() { 41 | testSlider = new Slider("#rtlSlider", { 42 | min: 0, 43 | max: 10, 44 | value: 5 45 | }); 46 | 47 | var sliderTrackLowRight=$("#rtlSlider").siblings(".slider-rtl").children("div.slider-track").children("div.slider-track-low").css("right"); 48 | var sliderSelectionRight=$("#rtlSlider").siblings(".slider-rtl").children("div.slider-track").children("div.slider-selection").css("right"); 49 | var sliderTrackHighLeft=$("#rtlSlider").siblings(".slider-rtl").children("div.slider-track").children("div.slider-track-high").css("left"); 50 | 51 | expect(sliderTrackLowRight).toBe("0px"); 52 | expect(sliderSelectionRight).toBe("0px"); 53 | expect(sliderTrackHighLeft).toBe("0px"); 54 | }); 55 | 56 | it("tooltip position must be inversed in vertical", function() { 57 | testSlider = new Slider("#rtlSlider", { 58 | orientation: "vertical", 59 | }); 60 | 61 | var mainTooltipHasClassLeft = testSlider.tooltip.classList.contains("bs-tooltip-left"); 62 | 63 | expect(mainTooltipHasClassLeft).toBeTruthy(); 64 | expect(testSlider.tooltip.style.right).toBe("100%"); 65 | }); 66 | 67 | it("tooltip position can be forced in vertical", function() { 68 | testSlider = new Slider("#rtlSlider", { 69 | orientation: "vertical", 70 | tooltip_position: "right", 71 | }); 72 | 73 | var mainTooltipHasClassRight = testSlider.tooltip.classList.contains("bs-tooltip-right"); 74 | 75 | expect(mainTooltipHasClassRight).toBeTruthy(); 76 | expect(testSlider.tooltip.style.left).toBe("100%"); 77 | }); 78 | 79 | }); 80 | 81 | }); // End of spec 82 | -------------------------------------------------------------------------------- /test/specs/ScrollableBodySpec.js: -------------------------------------------------------------------------------- 1 | describe("Scrollable body test", function() { 2 | var testSlider; 3 | var sliderHandleTopPos; 4 | var sliderHandleLeftPos; 5 | 6 | describe("Vertical scrolled body", function() { 7 | beforeEach(function() { 8 | testSlider = new Slider("#veryLowPositionedSlider", { 9 | id: "scrollTestSliderId", 10 | orientation: "vertical", 11 | min: 0, 12 | max: 20, 13 | value: 10, 14 | step: 1 15 | }); 16 | 17 | document.body.scrollTop = 2000; 18 | 19 | var sliderHandleEl = document.querySelector("#scrollTestSliderId .slider-handle"); 20 | var sliderHandleBoundingBoxInfo = sliderHandleEl.getBoundingClientRect(); 21 | sliderHandleTopPos = sliderHandleBoundingBoxInfo.top; 22 | sliderHandleLeftPos = sliderHandleBoundingBoxInfo.left; 23 | }); 24 | 25 | afterEach(function() { 26 | if(testSlider) { 27 | testSlider.destroy(); 28 | } 29 | document.body.scrollTop = 0; 30 | }); 31 | 32 | // The difference between sliderHandleTopPos and mousemoveY is equal to 50 in both cases, 33 | // but difference between initial and final slider value is not equal (6 and 4). 34 | // It happens because we don't 'hit' the center of handle but the top left corner. 35 | 36 | it("slides up when handle moves upwards after scroll page down", function() { 37 | var mousemove = document.createEvent('MouseEvents'); 38 | var mousemoveX = sliderHandleLeftPos; 39 | var mousemoveY = sliderHandleTopPos - 50; 40 | var newSliderValue; 41 | 42 | mousemove.initMouseEvent( 43 | "mousedown", 44 | true /* bubble */, 45 | true /* cancelable */, 46 | window, 47 | null, 48 | 0, 0, mousemoveX, mousemoveY, /* coordinates */ 49 | false, false, false, false, /* modifier keys */ 50 | 0 /*left*/, 51 | null 52 | ); 53 | testSlider.sliderElem.dispatchEvent(mousemove); 54 | newSliderValue = testSlider.getValue(); 55 | 56 | expect(newSliderValue).toEqual(4); 57 | }); 58 | 59 | it("slides down when handle moves downwards after scroll page down", function() { 60 | var mousemove = document.createEvent('MouseEvents'); 61 | var mousemoveX = sliderHandleLeftPos; 62 | var mousemoveY = sliderHandleTopPos + 50; 63 | var newSliderValue; 64 | 65 | mousemove.initMouseEvent( 66 | "mousedown", 67 | true /* bubble */, 68 | true /* cancelable */, 69 | window, 70 | null, 71 | 0, 0, mousemoveX, mousemoveY, /* coordinates */ 72 | false, false, false, false, /* modifier keys */ 73 | 0 /*left*/, 74 | null 75 | ); 76 | testSlider.sliderElem.dispatchEvent(mousemove); 77 | newSliderValue = testSlider.getValue(); 78 | 79 | expect(newSliderValue).toEqual(14); 80 | }); 81 | }); 82 | 83 | 84 | describe('Horizontal scrolled body', function() { 85 | beforeEach(function() { 86 | testSlider = new Slider('#offRightEdgeSliderInput', { 87 | id: 'offRightEdgeSlider', 88 | orientation: 'horizontal', 89 | min: 0, 90 | max: 20, 91 | value: 10, 92 | step: 1, 93 | }); 94 | 95 | testSlider.sliderElem.scrollIntoView(); 96 | 97 | var handle = document.querySelector('#offRightEdgeSlider .slider-handle'); 98 | var handleRect = handle.getBoundingClientRect(); 99 | sliderHandleTopPos = handleRect.top; 100 | sliderHandleLeftPos = handleRect.left; 101 | }); 102 | 103 | afterEach(function() { 104 | if (testSlider) { 105 | testSlider.destroy(); 106 | } 107 | window.scrollTo(0, 0); 108 | }); 109 | 110 | it('slides left when clicked on the left of the handle', function() { 111 | var x = sliderHandleLeftPos - 50; 112 | var y = sliderHandleTopPos; 113 | var mousedown, newSliderValue; 114 | 115 | mousedown = createMouseDownEvent(x, y); 116 | testSlider.sliderElem.dispatchEvent(mousedown); 117 | newSliderValue = testSlider.getValue(); 118 | 119 | expect(newSliderValue).toEqual(4); 120 | }); 121 | 122 | it('slides right when clicked on the left of the handle', function() { 123 | var x = sliderHandleLeftPos + 50; 124 | var y = sliderHandleTopPos; 125 | var mousedown, newSliderValue; 126 | 127 | mousedown = createMouseDownEvent(x, y); 128 | testSlider.sliderElem.dispatchEvent(mousedown); 129 | newSliderValue = testSlider.getValue(); 130 | 131 | expect(newSliderValue).toEqual(14); 132 | }); 133 | 134 | function createMouseDownEvent(x, y) { 135 | var mousedown = document.createEvent('MouseEvents'); 136 | mousedown.initMouseEvent( 137 | 'mousedown', 138 | false /* bubble */, 139 | true /* cancelable */, 140 | window, /* view */ 141 | null, /* detail */ 142 | 0, 0, x, y, /* coordinates */ 143 | false, false, false, false, /* modifier keys */ 144 | 0, /* button: left */ 145 | null /* relatedTarget */ 146 | ); 147 | return mousedown; 148 | } 149 | }); 150 | }); 151 | -------------------------------------------------------------------------------- /test/specs/ScrollableContainerSpec.js: -------------------------------------------------------------------------------- 1 | describe("Scrollable test", function() { 2 | var testSlider; 3 | var sliderHandleTopPos; 4 | var sliderHandleLeftPos; 5 | var scrollableContainer; 6 | 7 | describe("Vertical inside scrollable container", function() { 8 | beforeEach(function() { 9 | testSlider = new Slider("#ex1", { 10 | id: "ex1Slider", 11 | orientation: "vertical", 12 | min: 0, 13 | max: 20, 14 | value: 10, 15 | step: 1 16 | }); 17 | 18 | scrollableContainer = document.querySelector('#scrollable-div'); 19 | scrollableContainer.scrollTop = 145; 20 | 21 | var sliderHandleEl = document.querySelector("#ex1Slider .slider-handle"); 22 | var sliderHandleBoundingBoxInfo = sliderHandleEl.getBoundingClientRect(); 23 | sliderHandleTopPos = sliderHandleBoundingBoxInfo.top; 24 | sliderHandleLeftPos = sliderHandleBoundingBoxInfo.left; 25 | 26 | }); 27 | 28 | afterEach(function() { 29 | if(testSlider) { 30 | testSlider.destroy(); 31 | } 32 | }); 33 | 34 | // The difference between sliderHandleTopPos and mousemoveY is equal to 50 in both cases, 35 | // but difference between initial and final slider value is not equal (6 and 4). 36 | // It happens because we don't 'hit' the center of handle but the top left corner. 37 | 38 | it("slides up when handle moves upwards inside scrollable element after scrolling", function() { 39 | var mousemove = document.createEvent('MouseEvents'); 40 | var mousemoveX = sliderHandleLeftPos; 41 | var mousemoveY = sliderHandleTopPos - 50; 42 | var newSliderValue; 43 | 44 | mousemove.initMouseEvent( 45 | "mousedown", 46 | true /* bubble */, 47 | true /* cancelable */, 48 | window, 49 | null, 50 | 0, 0, mousemoveX, mousemoveY, /* coordinates */ 51 | false, false, false, false, /* modifier keys */ 52 | 0 /*left*/, 53 | null 54 | ); 55 | testSlider.sliderElem.dispatchEvent(mousemove); 56 | newSliderValue = testSlider.getValue(); 57 | 58 | expect(newSliderValue).toEqual(4); 59 | }); 60 | 61 | it("slides down when handle moves downwards inside scrollable element after scrolling", function() { 62 | var mousemove = document.createEvent('MouseEvents'); 63 | var mousemoveX = sliderHandleLeftPos; 64 | var mousemoveY = sliderHandleTopPos + 50; 65 | var newSliderValue; 66 | 67 | mousemove.initMouseEvent( 68 | "mousedown", 69 | true /* bubble */, 70 | true /* cancelable */, 71 | window, 72 | null, 73 | 0, 0, mousemoveX, mousemoveY, /* coordinates */ 74 | false, false, false, false, /* modifier keys */ 75 | 0 /*left*/, 76 | null 77 | ); 78 | testSlider.sliderElem.dispatchEvent(mousemove); 79 | newSliderValue = testSlider.getValue(); 80 | 81 | expect(newSliderValue).toEqual(14); 82 | }); 83 | }); 84 | 85 | }); // End of spec 86 | -------------------------------------------------------------------------------- /test/specs/StepReachMaxValueSpec.js: -------------------------------------------------------------------------------- 1 | describe("TickMaxValueNotATickBehavior", function() { 2 | var SLIDER_ID = "testSlider1"; 3 | var slider; 4 | var options; 5 | 6 | describe('max value should be reached', function() { 7 | beforeEach(function() { 8 | options = { 9 | min: 40, 10 | max: 1310, 11 | step: 5, 12 | scale: "logarithmic", 13 | value: 44 14 | }; 15 | slider = new Slider(document.getElementById(SLIDER_ID), options); 16 | }); 17 | 18 | it("Value should contain max value when slider is moved to outer right position", function() { 19 | var sliderLeft = slider.sliderElem.offsetLeft; 20 | var offsetY = slider.sliderElem.offsetTop; 21 | // I think the + 10 work because it is half of the handle size; 22 | var offsetX = sliderLeft + slider.sliderElem.clientWidth + 10; 23 | var expectedValue = slider.options.max; 24 | var mouseEvent = getMouseDownEvent(offsetX, offsetY); 25 | slider.mousedown(mouseEvent); 26 | // FIXME: Use 'mouseup' event type 27 | slider.mouseup(mouseEvent); 28 | expect(slider.getValue()).toBe(expectedValue); 29 | }); 30 | }); 31 | 32 | afterEach(function() { 33 | slider.destroy(); 34 | }); 35 | 36 | // helper functions 37 | function getMouseDownEvent(offsetXToClick, offsetYToClick) { 38 | var args = [ 39 | 'mousedown', // type 40 | true, // canBubble 41 | true, // cancelable 42 | document, // view, 43 | 0, // detail 44 | 0, // screenX 45 | 0, // screenY 46 | offsetXToClick, // clientX 47 | offsetYToClick, // clientY, 48 | false, // ctrlKey 49 | false, // altKey 50 | false, // shiftKey 51 | false, // metaKey, 52 | 0, // button 53 | null // relatedTarget 54 | ]; 55 | 56 | var event = document.createEvent('MouseEvents'); 57 | event.initMouseEvent.apply(event, args); 58 | return event; 59 | } 60 | 61 | }); 62 | -------------------------------------------------------------------------------- /test/specs/TickClickingBehaviorSpec.js: -------------------------------------------------------------------------------- 1 | describe("TickClickingBehavior", function() { 2 | var SLIDER_ID = "testSlider1"; 3 | var slider; 4 | var options; 5 | 6 | describe('ticks start with 0', function() { 7 | beforeEach(function() { 8 | options = { 9 | ticks: [0, 1, 2, 3, 4], 10 | ticks_positions: [0, 25, 50, 75, 100], 11 | step: 1, 12 | value: 4 13 | }; 14 | 15 | slider = new Slider(document.getElementById(SLIDER_ID), options); 16 | }); 17 | 18 | it("Should set slider to corresponding value when ticks are clicked", function() { 19 | for (var i = 0; i < options.ticks.length; i++) { 20 | clickTickAtIndexAndVerify(slider, i); 21 | } 22 | }); 23 | }); 24 | 25 | describe('ticks start with positive value', function() { 26 | beforeEach(function() { 27 | options = { 28 | ticks: [1, 2, 3, 4, 5], 29 | ticks_positions: [0, 25, 50, 75, 100], 30 | step: 1, 31 | value: 5 32 | }; 33 | 34 | slider = new Slider(document.getElementById(SLIDER_ID), options); 35 | }); 36 | 37 | it("Should set slider to corresponding value when ticks are clicked", function() { 38 | for (var i = 0; i < options.ticks.length; i++) { 39 | clickTickAtIndexAndVerify(slider, i); 40 | } 41 | }); 42 | }); 43 | 44 | describe('ticks start with negative value', function() { 45 | beforeEach(function() { 46 | options = { 47 | ticks: [-5, -4, -3, -2, -1], 48 | ticks_positions: [0, 25, 50, 75, 100], 49 | step: 1, 50 | value: -1 51 | }; 52 | 53 | slider = new Slider(document.getElementById(SLIDER_ID), options); 54 | }); 55 | 56 | it("Should set slider to corresponding value when ticks are clicked", function() { 57 | for (var i = 0; i < options.ticks.length; i++) { 58 | clickTickAtIndexAndVerify(slider, i); 59 | } 60 | }); 61 | }); 62 | 63 | afterEach(function() { slider.destroy(); }); 64 | 65 | // helper functions 66 | function clickTickAtIndexAndVerify(slider, tickIndex) { 67 | var sliderLeft = slider.sliderElem.offsetLeft; 68 | var tickLeft = slider.ticks[tickIndex].offsetLeft; 69 | var handleHalfWidth = $('.slider-handle.round').width() / 2; 70 | 71 | var offsetX = sliderLeft + tickLeft + handleHalfWidth; 72 | var offsetY = slider.sliderElem.offsetTop; 73 | 74 | var mouseEvent = getMouseDownEvent(offsetX, offsetY); 75 | 76 | slider.mousedown(mouseEvent); 77 | // FIXME: Use 'mouseup' event type 78 | slider.mouseup(mouseEvent); 79 | 80 | var expectedValue = slider.options.ticks[tickIndex]; 81 | expect(slider.getValue()).toBe(expectedValue); 82 | } 83 | 84 | function getMouseDownEvent(offsetXToClick, offsetYToClick) { 85 | var args = [ 86 | 'mousedown', // type 87 | true, // canBubble 88 | true, // cancelable 89 | document, // view, 90 | 0, // detail 91 | 0, // screenX 92 | 0, // screenY 93 | offsetXToClick, // clientX 94 | offsetYToClick, // clientY, 95 | false, // ctrlKey 96 | false, // altKey 97 | false, // shiftKey 98 | false, // metaKey, 99 | 0, // button 100 | null // relatedTarget 101 | ]; 102 | 103 | var event = document.createEvent('MouseEvents'); 104 | event.initMouseEvent.apply(event, args); 105 | 106 | return event; 107 | } 108 | }); 109 | -------------------------------------------------------------------------------- /test/specs/TickLabelSpec.js: -------------------------------------------------------------------------------- 1 | /* 2 | Tick label Render Tests - Tests that labels render in correct positions in both horizontal and vertical orientation 3 | */ 4 | 5 | describe("Tick Label Render Tests", function() { 6 | var testSliderH; 7 | var testSliderV; 8 | 9 | //setup 10 | beforeEach(function() { 11 | testSliderH = $('#testSlider1').slider({ 12 | id: 'slider1', 13 | ticks: [0, 1, 2], 14 | ticks_labels:['x', 'y', 'z'], 15 | orientation:'horizontal' 16 | }); 17 | 18 | testSliderV = $('#testSlider2').slider({ 19 | id: 'slider2', 20 | ticks: [0, 1, 2], 21 | ticks_labels:['x', 'y', 'z'], 22 | orientation:'vertical' 23 | }); 24 | }); 25 | 26 | //cleanup 27 | afterEach(function() { 28 | testSliderH.slider('destroy'); 29 | testSliderH = null; 30 | 31 | testSliderV.slider('destroy'); 32 | testSliderV = null; 33 | }); 34 | 35 | //e.g. testOrientation('horizontal', 2) will test the horizontal 36 | //code path using control with the id testSlider2 37 | function testOrientation(orientation) { 38 | var sliderIndex = orientation.toLowerCase() === 'horizontal' ? 1 : 2; 39 | var isVertical = orientation.toLowerCase() === 'horizontal' ? false : true; 40 | var sliderId = '#slider' + sliderIndex; 41 | 42 | //check elements exist 43 | it("Tick labels are rendered - " + orientation, function() { 44 | expect($(sliderId).length).toBe(1); 45 | 46 | var length = $(sliderId + ' .slider-tick-label').length; 47 | expect(length).toBe(3); 48 | }); 49 | 50 | //check elements exist within the bounds of the slider 51 | it("Tick labels render inside the slider's bounds" + orientation, function() { 52 | expect($(sliderId).length).toBe(1); 53 | 54 | var sliderRect = $(sliderId)[0].getBoundingClientRect(); 55 | var tickLabels = $(sliderId + ' .slider-tick-label'); 56 | 57 | for (var i = 0; i < tickLabels.length; i++) { 58 | var labelRect = tickLabels[i].getBoundingClientRect(); 59 | 60 | if (isVertical) { 61 | expect(labelRect.left).toBeGreaterThan(sliderRect.left); 62 | expect(labelRect.top + 10 >= sliderRect.top).toBeTruthy(); 63 | } else { 64 | expect(labelRect.top + 10 >= sliderRect.top).toBeTruthy(); 65 | expect(labelRect.width / 2 + labelRect.left >= sliderRect.left).toBeTruthy(); 66 | } 67 | } 68 | }); 69 | } 70 | 71 | //test both horizontal and vertical orientations 72 | testOrientation('horizontal'); 73 | testOrientation('vertical'); 74 | }); 75 | 76 | describe("Tick Labels 'is-selection' and 'in-selection' Tests", function() { 77 | var $inputSlider; 78 | var options; 79 | var keyboardEvent; 80 | var $slider; 81 | var $handle1; 82 | var $handle2; 83 | var $tickLabels; 84 | var tickLabelCount; 85 | 86 | // Setup 87 | beforeEach(function() { 88 | options = { 89 | id: 'slider1', 90 | ticks: [0, 1, 2, 3, 4], 91 | value: 2, 92 | ticks_labels:['$0', '$1', '$2', '$3', '$4'], 93 | }; 94 | 95 | tickLabelCount = options.ticks_labels.length; 96 | 97 | // Create keyboard event 98 | keyboardEvent = document.createEvent('Event'); 99 | keyboardEvent.initEvent('keydown', true, true); 100 | }); 101 | 102 | // Cleanup 103 | afterEach(function() { 104 | $inputSlider.slider('destroy'); 105 | $inputSlider = null; 106 | }); 107 | 108 | describe("Tick Labels 'is-selection' Tests", function() { 109 | 110 | describe("'options.selection = 'before'", function() { 111 | 112 | beforeEach(function() { 113 | options.selection = 'before'; 114 | $inputSlider = $('#testSlider1').slider(options); 115 | $slider = $('#slider1'); 116 | $tickLabels = $slider.find('.slider-tick-label-container div.slider-tick-label'); 117 | }); 118 | 119 | it("Should show the correct tick labels as 'is-selection'", function() { 120 | // There should only be one tick label with the 'label-is-selection' class 121 | expect($slider.find('.label-is-selection').length).toBe(1); 122 | // Only the third tick label should have the 'label-is-selection' class 123 | expect($tickLabels.eq(2).hasClass('label-is-selection')).toBe(true); 124 | }); 125 | 126 | it("Should show the correct tick labels as 'is-selection' when keying to the left", function(done) { 127 | $handle1 = $('#slider1').find('.slider-handle:first'); 128 | 129 | expect($slider.find('.label-is-selection').length).toBe(1); 130 | expect($tickLabels.eq(2).hasClass('label-is-selection')).toBe(true); 131 | 132 | $handle1.on('keydown', function() { 133 | expect($slider.find('.label-is-selection').length).toBe(1); 134 | expect($tickLabels.eq(1).hasClass('label-is-selection')).toBe(true); 135 | done(); 136 | }); 137 | 138 | // Move handle1 to the left with keyboard 139 | $handle1.focus(); 140 | keyboardEvent.keyCode = keyboardEvent.which = 37; 141 | $handle1[0].dispatchEvent(keyboardEvent); 142 | }); 143 | }); 144 | 145 | describe("'options.selection = 'after'", function() { 146 | 147 | beforeEach(function() { 148 | options.selection = 'after'; 149 | $inputSlider = $('#testSlider1').slider(options); 150 | $slider = $('#slider1'); 151 | $tickLabels = $slider.find('.slider-tick-label-container div.slider-tick-label'); 152 | }); 153 | 154 | it("Should show the correct tick labels as 'is-selection'" , function() { 155 | expect($slider.find('.label-is-selection').length).toBe(1); 156 | expect($tickLabels.eq(2).hasClass('label-is-selection')).toBe(true); 157 | }); 158 | 159 | it("Should show the correct tick labels as 'is-selection' when keying to the right" , function(done) { 160 | $handle1 = $('#slider1').find('.slider-handle:first'); 161 | 162 | expect($slider.find('.label-is-selection').length).toBe(1); 163 | expect($tickLabels.eq(2).hasClass('label-is-selection')).toBe(true); 164 | 165 | $handle1.on('keydown', function() { 166 | expect($slider.find('.label-is-selection').length).toBe(1); 167 | expect($tickLabels.eq(3).hasClass('label-is-selection')).toBe(true); 168 | done(); 169 | }); 170 | 171 | // Move handle1 to the right with keyboard 172 | $handle1.focus(); 173 | keyboardEvent.keyCode = keyboardEvent.which = 39; 174 | $handle1[0].dispatchEvent(keyboardEvent); 175 | }); 176 | }); 177 | }); 178 | 179 | describe("Tick Labels 'in-selection' Tests", function() { 180 | 181 | function checkTickLabels($labels, expectedLabels) { 182 | var next = 0; 183 | 184 | // There are only 5 tick labels. 185 | expect($labels.length).toBe(tickLabelCount); 186 | 187 | for (var i = 0; i < tickLabelCount; i++) { 188 | if (i === expectedLabels[next]) { 189 | expect($labels.eq(i).hasClass('label-in-selection')).toBe(true); 190 | next++; 191 | } 192 | else { 193 | expect($labels.eq(i).hasClass('label-in-selection')).toBe(false); 194 | } 195 | } 196 | } 197 | 198 | // Setup 199 | beforeEach(function() { 200 | options.value = [1, 3]; 201 | $inputSlider = $('#testSlider1').slider(options); 202 | $slider = $('#slider1'); 203 | $tickLabels = $slider.find('.slider-tick-label-container div.slider-tick-label'); 204 | }); 205 | 206 | it("Should show the correct tick labels as 'in-selection'", function() { 207 | expect($slider.find('.label-is-selection').length).toBe(3); 208 | checkTickLabels($tickLabels, [1, 2, 3]); 209 | }); 210 | 211 | it("Should show the correct tick labels as 'in-selection' when keying to the left", function(done) { 212 | $handle1 = $('#slider1').find('.slider-handle:first'); 213 | 214 | // There should be 3 tick labels with the 'label-in-selection' class 215 | expect($slider.find('.label-in-selection').length).toBe(3); 216 | 217 | // Check that the correct tick labels have the 'label-in-selection' class 218 | checkTickLabels($tickLabels, [1, 2, 3]); 219 | 220 | $handle1.on('keydown', function() { 221 | expect($slider.find('.label-in-selection').length).toBe(4); 222 | 223 | // Check the labels again 224 | checkTickLabels($tickLabels, [0, 1, 2, 3]); 225 | done(); 226 | }); 227 | 228 | // Move handle1 to the left with keyboard 229 | $handle1.focus(); 230 | keyboardEvent.keyCode = keyboardEvent.which = 37; 231 | $handle1[0].dispatchEvent(keyboardEvent); 232 | }); 233 | 234 | it("Should show the correct tick labels as 'in-selection' when keying to the right" , function(done) { 235 | $handle2 = $('#slider1').find('.slider-handle:last'); 236 | 237 | expect($slider.find('.label-in-selection').length).toBe(3); 238 | 239 | checkTickLabels($tickLabels, [1, 2, 3]); 240 | 241 | $handle2.on('keydown', function() { 242 | expect($slider.find('.label-in-selection').length).toBe(4); 243 | checkTickLabels($tickLabels, [1, 2, 3, 4]); 244 | done(); 245 | }); 246 | 247 | // Move handle2 to the right with keyboard 248 | $handle2.focus(); 249 | keyboardEvent.keyCode = keyboardEvent.which = 39; 250 | $handle2[0].dispatchEvent(keyboardEvent); 251 | }); 252 | }); 253 | }); -------------------------------------------------------------------------------- /test/specs/TickMarksSpec.js: -------------------------------------------------------------------------------- 1 | /* 2 | ************************* 3 | 4 | Tick Marks Tests 5 | 6 | ************************* 7 | 8 | Verify that the number of tick marks matches what you set 9 | Verify the tick marks are at the correct intervals 10 | 11 | 12 | */ 13 | describe("Slider with ticks tests", function() { 14 | 15 | var testSlider; 16 | 17 | it("Should have the number of tick marks you specify", function() { 18 | testSlider = $("#testSlider1").slider({ 19 | ticks: [100, 200, 300, 400, 500] 20 | }); 21 | 22 | var numTicks = $("#testSlider1").siblings('div.slider').find('.slider-tick').length; 23 | expect(numTicks).toBe(5); 24 | }); 25 | 26 | it("Should be at the default positions", function() { 27 | testSlider = $("#testSlider1").slider({ 28 | ticks: [100, 200, 300, 400, 500] 29 | }); 30 | 31 | $("#testSlider1").siblings('div.slider').find('.slider-tick').each(function(i) { 32 | expect(this.style.left).toBe(100 * i / 4.0 + '%'); 33 | }); 34 | }); 35 | 36 | it("Should be at the positions you specify", function() { 37 | var tickPositions = [0, 10, 20, 30, 100]; 38 | testSlider = $("#testSlider1").slider({ 39 | ticks: [100, 200, 300, 400, 500], 40 | ticks_positions: tickPositions 41 | }); 42 | 43 | $("#testSlider1").siblings('div.slider').find('.slider-tick').each(function(i) { 44 | expect(this.style.left).toBe(tickPositions[i] + '%'); 45 | }); 46 | }); 47 | 48 | it("Should have the tick labels you specify", function() { 49 | var tickLabels = ['$0', '$100', '$200', '$300', '$400']; 50 | testSlider = $("#testSlider1").slider({ 51 | ticks: [100, 200, 300, 400, 500], 52 | ticks_labels: tickLabels 53 | }); 54 | 55 | var tickLabelElements = $("#testSlider1").siblings('div.slider').find('.slider-tick-label'); 56 | expect(tickLabelElements.length).toBe(tickLabels.length); 57 | tickLabelElements.each(function(i) { 58 | expect(this.innerHTML).toBe(tickLabels[i]); 59 | }); 60 | }); 61 | 62 | it("Should not snap to a tick within tick bounds when using the keyboard navigation", function() { 63 | testSlider = $("#testSlider1").slider({ 64 | ticks: [100, 200, 300, 400, 500], 65 | ticks_snap_bounds: 30 66 | }); 67 | 68 | // Focus on handle1 69 | var handle1 = $("#testSlider1").prev('div.slider').find('.slider-handle'); 70 | handle1.focus(); 71 | 72 | // Create keyboard event 73 | var keyboardEvent = document.createEvent("Events"); 74 | keyboardEvent.initEvent("keydown", true, true); 75 | 76 | var keyPresses = 0; 77 | handle1.on("keydown", function() { 78 | keyPresses++; 79 | var value = $("#testSlider1").slider('getValue'); 80 | expect(value).toBe(100 + keyPresses); 81 | }); 82 | 83 | keyboardEvent.keyCode = keyboardEvent.which = 39; // RIGHT 84 | for (var i = 0; i < 5; i++) { 85 | handle1[0].dispatchEvent(keyboardEvent); 86 | } 87 | }); 88 | 89 | it("Should show the correct tick marks as 'in-selection', according to the `selection` property", function() { 90 | var options = { 91 | ticks: [100, 200, 300, 400, 500], 92 | value: 250, 93 | selection: 'after' 94 | }, 95 | $el = $("#testSlider1"); 96 | 97 | testSlider = $el.slider(options); 98 | expect($el.siblings('div.slider').find('.in-selection').length).toBe(3); 99 | 100 | testSlider.slider('destroy'); 101 | 102 | options.selection = 'before'; 103 | testSlider = $el.slider(options); 104 | expect($el.siblings('div.slider').find('.in-selection').length).toBe(2); 105 | }); 106 | 107 | it("Should reverse the tick labels if `reversed` option is set to true", function() { 108 | var ticks = [100, 200, 300, 400, 500]; 109 | var ticksLabels = ["$100", "$200", "$300", "$400", "$500"]; 110 | 111 | // Create reversed slider 112 | testSlider = $("#testSlider1").slider({ 113 | id: "testSlider1Ref", 114 | ticks: ticks, 115 | ticks_labels: ticksLabels, 116 | ticks_snap_bounds: 30, 117 | reversed: true 118 | }); 119 | 120 | // Assert that tick marks are reversed 121 | var tickLabelsFromDOM = $("#testSlider1Ref .slider-tick-label-container") 122 | .children(".slider-tick-label") 123 | .map(function() { return $(this).text(); }) 124 | .toArray(); 125 | 126 | var reversedTickLabels = ticksLabels.reverse(); 127 | expect(tickLabelsFromDOM).toEqual(reversedTickLabels); 128 | }); 129 | 130 | it("Should reverse the tick labels if `reversed` option is set to true and `ticks_positions` is specified", function() { 131 | var ticks = [0, 100, 200, 300, 400]; 132 | var ticksLabels = ["$0", "$100", "$200", "$300", "$400"]; 133 | 134 | // Create reversed slider 135 | testSlider = $("#testSlider1").slider({ 136 | id: "testSlider1Ref", 137 | ticks: ticks, 138 | ticks_labels: ticksLabels, 139 | ticks_positions: [0, 30, 70, 90, 100], 140 | ticks_snap_bounds: 20, 141 | value: 200, 142 | reversed: true 143 | }); 144 | 145 | // Assert that tick marks are reversed 146 | var tickLabelsFromDOM = $("#testSlider1Ref .slider-tick-label-container .slider-tick-label") 147 | .sort(function(tickLabelElemA, tickLabelElemB) { 148 | var leftOffsetA = $(tickLabelElemA).position().left; 149 | var leftOffsetB = $(tickLabelElemB).position().left; 150 | 151 | return leftOffsetA - leftOffsetB; 152 | }) 153 | .map(function() { return $(this).text(); }) 154 | .toArray(); 155 | 156 | var reversedTickLabels = ticksLabels.reverse(); 157 | expect(tickLabelsFromDOM).toEqual(reversedTickLabels); 158 | }); 159 | 160 | it("should wrap all of the ticks within a div with classname '.slider-tick-container'", function() { 161 | // Create the slider with ticks 162 | var ticks = [0, 100, 200, 300, 400, 600]; 163 | var $sliderDOMRef = $("#testSlider1"); 164 | 165 | // Create reversed slider 166 | testSlider = $sliderDOMRef.slider({ 167 | id: "testSlider1Ref", 168 | ticks: ticks, 169 | ticks_positions: [0, 30, 70, 90, 100, 130] 170 | }); 171 | 172 | // Assert that the ticks are children of the container element 173 | var numTicks = $sliderDOMRef.siblings('div.slider').find('.slider-tick-container > .slider-tick').length; 174 | expect(numTicks).toBe(ticks.length); 175 | }); 176 | 177 | afterEach(function() { 178 | if(testSlider) { 179 | testSlider.slider('destroy'); 180 | testSlider = null; 181 | } 182 | }); 183 | }); 184 | 185 | describe("Slider min/max settings", function() { 186 | var $inputSlider; 187 | 188 | afterEach(function() { 189 | if ($inputSlider) { 190 | if ($inputSlider instanceof jQuery) { 191 | $inputSlider.slider('destroy'); 192 | } 193 | $inputSlider = null; 194 | } 195 | }); 196 | 197 | it("Should use min/max tick values for min/max settings", function() { 198 | $inputSlider = $('#testSlider1').slider({ 199 | ticks: [1, 2, 3] 200 | }); 201 | 202 | expect($inputSlider.slider('getAttribute', 'min')).toBe(1); 203 | expect($inputSlider.slider('getAttribute', 'max')).toBe(3); 204 | }); 205 | 206 | it("Should not overwrite 'min' setting", function() { 207 | $inputSlider = $('#testSlider1').slider({ 208 | min: 0, 209 | ticks: [1, 2, 3] 210 | }); 211 | 212 | expect($inputSlider.slider('getAttribute', 'min')).toBe(0); 213 | expect($inputSlider.slider('getAttribute', 'max')).toBe(3); 214 | }); 215 | 216 | it("Should not overwrite 'max' setting", function() { 217 | $inputSlider = $('#testSlider1').slider({ 218 | max: 5, 219 | ticks: [1, 2, 3] 220 | }); 221 | 222 | expect($inputSlider.slider('getAttribute', 'min')).toBe(1); 223 | expect($inputSlider.slider('getAttribute', 'max')).toBe(5); 224 | }); 225 | 226 | it("Should not overwrite 'min' or max' settings", function() { 227 | $inputSlider = $('#testSlider1').slider({ 228 | min: 0, 229 | max: 5, 230 | ticks: [1, 2, 3] 231 | }); 232 | 233 | expect($inputSlider.slider('getAttribute', 'min')).toBe(0); 234 | expect($inputSlider.slider('getAttribute', 'max')).toBe(5); 235 | }); 236 | 237 | it("Should ignore the ticks when outside of min/max range", function() { 238 | $inputSlider = $("#testSlider1").slider({ 239 | ticks: [100, 200, 300, 400, 500], 240 | min: 15000, 241 | max: 25000 242 | }); 243 | 244 | expect($inputSlider.slider('getAttribute', 'min')).toBe(15000); 245 | expect($inputSlider.slider('getAttribute', 'max')).toBe(25000); 246 | }); 247 | }); -------------------------------------------------------------------------------- /test/specs/TooltipMouseOverOptionSpec.js: -------------------------------------------------------------------------------- 1 | describe("'ticks_tooltip' Option tests", function() { 2 | var testSlider; 3 | var mouseEventArguments; 4 | 5 | beforeEach(function() { 6 | // Set up default set of mouse event arguments 7 | mouseEventArguments = [ 8 | 'mousemove', // type 9 | true, // canBubble 10 | true, // cancelable 11 | document, // view, 12 | 0, // detail 13 | 0, // screenX 14 | 0, // screenY 15 | undefined, // clientX 16 | undefined, // clientY, 17 | false, // ctrlKey 18 | false, // altKey 19 | false, // shiftKey 20 | false, // metaKey, 21 | 0, // button 22 | null // relatedTarget 23 | ]; 24 | }); 25 | 26 | describe("ticks_tooltip states", function() { 27 | it("should have the tooltip above the last hovered over element", function() { 28 | testSlider = new Slider(document.getElementById("testSlider1"), { 29 | ticks: [0, 1, 2, 3, 4, 5, 6], 30 | ticks_positions: [0, 19, 29, 39, 49, 95, 100], 31 | step: 1, 32 | value: 4, 33 | ticks_tooltip: true, 34 | orientation: 'horizontal' 35 | }); 36 | mouseEventArguments[8] = testSlider.sliderElem.offsetTop; // clientY 37 | var mouse49 = document.createEvent('MouseEvents'); 38 | mouseEventArguments[7] = testSlider.ticks[4].offsetLeft + testSlider.sliderElem.offsetLeft; // clientX 39 | mouse49.initMouseEvent.apply(mouse49, mouseEventArguments); 40 | var mouse95 = document.createEvent('MouseEvents'); 41 | mouseEventArguments[7] = testSlider.ticks[5].offsetLeft + testSlider.sliderElem.offsetLeft; // clientX 42 | mouse95.initMouseEvent.apply(mouse95, mouseEventArguments); 43 | var mouse100 = document.createEvent('MouseEvents'); 44 | mouseEventArguments[7] = testSlider.ticks[6].offsetLeft + testSlider.sliderElem.offsetLeft; // clientX 45 | mouse100.initMouseEvent.apply(mouse100, mouseEventArguments); 46 | var mouseStart = document.createEvent('MouseEvents'); 47 | mouseEventArguments[7] = testSlider.ticks[0].offsetLeft + testSlider.sliderElem.offsetLeft; // clientX 48 | mouseStart.initMouseEvent.apply(mouseStart, mouseEventArguments); 49 | 50 | //Simulate random movements 51 | testSlider.mousedown(mouse49); 52 | testSlider.mousemove(mouse95); 53 | // FIXME: Use 'mouseup' event type 54 | testSlider.mouseup(mouse95); 55 | testSlider.mousedown(mouse49); 56 | testSlider.mousemove(mouse100); 57 | testSlider.mousemove(mouse95); 58 | testSlider.mousemove(mouse95); 59 | testSlider.mousemove(mouseStart); 60 | expect(testSlider.tooltip.style.left).toBe("0%"); 61 | }); 62 | }); 63 | 64 | describe("Always show the tooltip", function() { 65 | it("Should always display the tooltip after hovering over a tick", function(done) { 66 | testSlider = new Slider(document.getElementById("testSlider1"), { 67 | id: 'mySlider', 68 | min: 0, 69 | max: 10, 70 | step: 1, 71 | value: 1, 72 | ticks: [0, 5, 10], 73 | tooltip: 'always', 74 | ticks_tooltip: true, 75 | orientation: 'horizontal' 76 | }); 77 | var bigOffset = 100000; 78 | 79 | var isTooltipVisible = $('#mySlider').find('.tooltip.tooltip-main').hasClass('show'); 80 | expect(isTooltipVisible).toBe(true); 81 | 82 | var mouseenter = document.createEvent('MouseEvent'); 83 | mouseEventArguments[0] = 'mouseenter'; 84 | mouseEventArguments[7] = 85 | testSlider.ticks[1].offsetLeft + testSlider.sliderElem.offsetLeft; // clientX 86 | mouseenter.initMouseEvent.apply(mouseenter, mouseEventArguments); 87 | 88 | var mouseleave = document.createEvent('MouseEvent'); 89 | mouseEventArguments[0] = 'mouseleave'; 90 | mouseEventArguments[7] = testSlider.sliderElem.offsetLeft + bigOffset; 91 | mouseleave.initMouseEvent.apply(mouseleave, mouseEventArguments); 92 | 93 | testSlider.ticks[1].addEventListener('mouseleave', function() { 94 | isTooltipVisible = $('#mySlider').find('.tooltip.tooltip-main').hasClass('show'); 95 | expect(isTooltipVisible).toBe(true); 96 | done(); 97 | }); 98 | 99 | testSlider.ticks[1].dispatchEvent(mouseenter); 100 | testSlider.ticks[1].dispatchEvent(mouseleave); 101 | }); 102 | }); 103 | 104 | afterEach(function() { 105 | if(testSlider) { 106 | if(testSlider instanceof Slider) { testSlider.destroy(); } 107 | testSlider = null; 108 | } 109 | }); 110 | }); 111 | 112 | /** 113 | * The mouse navigation tests are based on the following slider properties: 114 | * 115 | * initial value: 3 or [3, 7] 116 | * ticks: [0, 3, 5, 7, 10] 117 | * step: 1 118 | * 119 | * When the `ticks_tooltip` option is set to `true`, hovering over the ticks or handles 120 | * should show the tooltip above it with the value of the tick/handle. 121 | * 122 | * The test logic for sliders: 123 | * 1. Hover over the 1st tick 124 | * 2. Check if the tooltip is positioned correctly (left, top, right) 125 | * 3. Check if the tooltip should be showing 126 | * 4. Check if the tooltip contains the correct value 127 | * 5. Check if the slider value(s) haven't changed 128 | * 129 | */ 130 | describe("`ticks_tooltip: true` mouse navigation test cases", function() { 131 | var initialValue = 3; 132 | var initialRangeValues = [3, 7]; 133 | var tickValues = [0, 3, 5, 7, 10]; 134 | var stepValue = 1; 135 | 136 | var orientations = ['horizontal', 'vertical']; 137 | var reversed = [false, true]; 138 | var sliderTypes = ['single', 'range']; 139 | var rtl = [false, true]; 140 | var testCases = []; 141 | var mouseEventArguments; 142 | 143 | function calcMouseEventCoords(element) { 144 | var elementBB = element.getBoundingClientRect(); 145 | 146 | return { 147 | clientX: elementBB.left, 148 | clientY: elementBB.top 149 | }; 150 | } 151 | 152 | function createMouseEvent(type, clientX, clientY) { 153 | var mouseEvent = document.createEvent('MouseEvent'); 154 | mouseEventArguments[0] = type; 155 | mouseEventArguments[7] = clientX; 156 | mouseEventArguments[8] = clientY; 157 | mouseEvent.initMouseEvent.apply(mouseEvent, mouseEventArguments); 158 | return mouseEvent; 159 | } 160 | 161 | beforeEach(function() { 162 | // Set up default set of mouse event arguments 163 | mouseEventArguments = [ 164 | 'mousemove', // type 165 | true, // canBubble 166 | true, // cancelable 167 | document, // view, 168 | 0, // detail 169 | 0, // screenX 170 | 0, // screenY 171 | undefined, // clientX 172 | undefined, // clientY, 173 | false, // ctrlKey 174 | false, // altKey 175 | false, // shiftKey 176 | false, // metaKey, 177 | 0, // button 178 | null // relatedTarget 179 | ]; 180 | }); 181 | 182 | sliderTypes.forEach(function(sliderType) { 183 | orientations.forEach(function(orientation) { 184 | rtl.forEach(function(isRTL) { 185 | reversed.forEach(function(isReversed) { 186 | var isHorizontal = orientation === 'horizontal'; 187 | var isVertical = orientation === 'vertical'; 188 | var isRange = sliderType === 'range'; 189 | var whichStyle; 190 | 191 | if (isHorizontal) { 192 | if (isRTL) { 193 | whichStyle = 'right'; 194 | } 195 | else { 196 | whichStyle = 'left'; 197 | } 198 | } 199 | else if (isVertical) { 200 | whichStyle = 'top'; 201 | } 202 | 203 | testCases.push({ 204 | value: isRange ? initialRangeValues : initialValue, 205 | step: stepValue, 206 | range: isRange, 207 | orientation: orientation, 208 | reversed: isReversed, 209 | rtl: 'auto', 210 | isRTL: isRTL, 211 | inputId: isRTL ? 'rtlSlider' : 'testSlider1', 212 | expectedValue: isRange ? initialRangeValues : initialValue, 213 | stylePos: whichStyle 214 | }); 215 | }); 216 | }); 217 | }); 218 | }); 219 | 220 | testCases.forEach(function(testCase) { 221 | describe("range=" + testCase.range + ", orientation=" + testCase.orientation + 222 | ", rtl=" + testCase.isRTL + ", reversed=" + testCase.reversed, function() { 223 | var $testSlider; 224 | var sliderElem; 225 | var $handle1; 226 | var $handle2; 227 | var $ticks; 228 | var sliderId; 229 | var sliderOptions; 230 | var $tooltip; 231 | var $tooltipInner; 232 | var lastTickIndex; 233 | var mouseEventType = 'mouseenter'; 234 | 235 | beforeEach(function() { 236 | sliderId = testCase.range ? 'myRangeSlider' : 'mySlider'; 237 | 238 | sliderOptions = { 239 | id: sliderId, 240 | step: testCase.step, 241 | orientation: testCase.orientation, 242 | value: testCase.value, 243 | range: testCase.range, 244 | reversed: testCase.reversed, 245 | rtl: 'auto', 246 | ticks: tickValues, 247 | ticks_tooltip: true 248 | }; 249 | 250 | $testSlider = $('#'+testCase.inputId).slider(sliderOptions); 251 | sliderElem = $('#'+sliderId)[0]; 252 | $ticks = $(sliderElem).find('.slider-tick'); 253 | $handle1 = $(sliderElem).find('.slider-handle:first'); 254 | $handle2 = $(sliderElem).find('.slider-handle:last'); 255 | $tooltip = $(sliderElem).find('.tooltip.tooltip-main'); 256 | $tooltipInner = $tooltip.find('.tooltip-inner'); 257 | lastTickIndex = sliderOptions.ticks.length - 1; 258 | }); 259 | 260 | afterEach(function() { 261 | // Clean up any associated event listeners 262 | $ticks = null; 263 | $handle1 = null; 264 | $handle2 = null; 265 | 266 | if ($testSlider) { 267 | $testSlider.slider('destroy'); 268 | $testSlider = null; 269 | } 270 | }); 271 | 272 | if (!testCase.range) { 273 | it("Should position the tooltip correctly when hovering over each tick (single only)", function(done) { 274 | $ticks.each(function(index, tickElem) { 275 | var coords = calcMouseEventCoords(tickElem); 276 | 277 | var tickCallback = function() { 278 | // Check position 279 | var tooltip_pos = $tooltip[0].style[testCase.stylePos]; 280 | var tick_pos = tickElem.style[testCase.stylePos]; 281 | 282 | expect(tooltip_pos).toBe(tick_pos); 283 | 284 | if (index === lastTickIndex) { 285 | done(); 286 | } 287 | }; 288 | 289 | // Set up listener and dispatch event 290 | this.addEventListener(mouseEventType, tickCallback, false); 291 | this.dispatchEvent(createMouseEvent(mouseEventType, coords.clientX, coords.clientY)); 292 | }); 293 | }); 294 | } 295 | 296 | it("Should show the tooltip", function(done) { 297 | $ticks.each(function(index, tickElem) { 298 | var coords = calcMouseEventCoords(tickElem); 299 | 300 | var tickCallback = function() { 301 | // Check that tooltip shows 302 | expect($tooltip.hasClass('show')).toBe(true); 303 | 304 | if (index === lastTickIndex) { 305 | done(); 306 | } 307 | }; 308 | 309 | this.addEventListener(mouseEventType, tickCallback, false); 310 | this.dispatchEvent(createMouseEvent(mouseEventType, coords.clientX, coords.clientY)); 311 | }); 312 | }); 313 | 314 | it("Should not show the tooltip", function(done) { 315 | var bigOffset = 100000; 316 | 317 | $ticks.each(function(index, tickElem) { 318 | var coords = calcMouseEventCoords(tickElem); 319 | 320 | var tickCallback = function() { 321 | // Check that tooltip shows 322 | expect($tooltip.hasClass('show')).toBe(false); 323 | 324 | if (index === lastTickIndex) { 325 | done(); 326 | } 327 | }; 328 | 329 | this.addEventListener('mouseleave', tickCallback, false); 330 | this.dispatchEvent(createMouseEvent('mouseleave', coords.clientX + bigOffset, coords.clientY)); 331 | }); 332 | }); 333 | 334 | it("Should contain the correct value for the tooltip", function(done) { 335 | $ticks.each(function(index, tickElem) { 336 | var coords = calcMouseEventCoords(tickElem); 337 | 338 | var tickCallback = function() { 339 | // Check value of tooltip 340 | expect($tooltipInner.text()).toBe(''+sliderOptions.ticks[index]); 341 | 342 | if (index === lastTickIndex) { 343 | done(); 344 | } 345 | }; 346 | 347 | this.addEventListener(mouseEventType, tickCallback, false); 348 | this.dispatchEvent(createMouseEvent(mouseEventType, coords.clientX, coords.clientY)); 349 | }); 350 | }); 351 | 352 | it("Should not modify the value(s) of the slider when displaying the tooltip", function(done) { 353 | $ticks.each(function(index, tickElem) { 354 | var coords = calcMouseEventCoords(tickElem); 355 | 356 | var tickCallback = function() { 357 | var value = $testSlider.slider('getValue'); 358 | 359 | // Check value of slider 360 | expect(value).toEqual(testCase.expectedValue); 361 | 362 | if (index === lastTickIndex) { 363 | done(); 364 | } 365 | }; 366 | 367 | this.addEventListener(mouseEventType, tickCallback, false); 368 | this.dispatchEvent(createMouseEvent(mouseEventType, coords.clientX, coords.clientY)); 369 | }); 370 | }); 371 | 372 | describe("Test position and values of the tooltip when hovering over the handle(s)", function() { 373 | 374 | if (testCase.range) { 375 | it("Should position for the tooltip correctly (range)", function(done) { 376 | var handleElems = [$handle1[0], $handle2[0]]; 377 | 378 | $.each(handleElems, function(index, handleElem) { 379 | var coords = calcMouseEventCoords(handleElem, testCase.orientation); 380 | 381 | var handleCallback = function() { 382 | // Check position 383 | var tooltip_pos = $tooltip[0].style[testCase.stylePos]; 384 | var handle_pos = handleElem.style[testCase.stylePos]; 385 | 386 | expect(tooltip_pos).toBe(handle_pos); 387 | 388 | if (index === 1) { 389 | done(); 390 | } 391 | }; 392 | 393 | handleElem.addEventListener(mouseEventType, handleCallback, false); 394 | handleElem.dispatchEvent(createMouseEvent(mouseEventType, coords.clientX, coords.clientY)); 395 | }); 396 | }); 397 | 398 | it("Should contain the correct values for the tooltip (range)", function(done) { 399 | var handleElems = [$handle1[0], $handle2[0]]; 400 | 401 | $.each(handleElems, function(index, handleElem) { 402 | var coords = calcMouseEventCoords(handleElem, testCase.orientation); 403 | 404 | var handleCallback = function() { 405 | // Check value of tooltip 406 | expect($tooltipInner.text()).toBe(''+testCase.expectedValue[index]); 407 | 408 | if (index === 1) { 409 | done(); 410 | } 411 | }; 412 | 413 | handleElem.addEventListener(mouseEventType, handleCallback, false); 414 | handleElem.dispatchEvent(createMouseEvent(mouseEventType, coords.clientX, coords.clientY)); 415 | }); 416 | }); 417 | 418 | } 419 | else { 420 | it("Should position for the tooltip correctly (single)", function(done) { 421 | var handleElem = $handle1[0]; 422 | 423 | var coords = calcMouseEventCoords(handleElem, testCase.orientation); 424 | 425 | var handleCallback = function() { 426 | // Check position 427 | var tooltip_pos = $tooltip[0].style[testCase.stylePos]; 428 | var handle_pos = handleElem.style[testCase.stylePos]; 429 | 430 | expect(tooltip_pos).toBe(handle_pos); 431 | 432 | done(); 433 | }; 434 | 435 | handleElem.addEventListener(mouseEventType, handleCallback, false); 436 | handleElem.dispatchEvent(createMouseEvent(mouseEventType, coords.clientX, coords.clientY)); 437 | }); 438 | 439 | it("Should contain the correct value for the tooltip (single)", function(done) { 440 | var handleElem = $handle1[0]; 441 | 442 | var coords = calcMouseEventCoords(handleElem, testCase.orientation); 443 | 444 | var handleCallback = function() { 445 | // Check value of tooltip 446 | expect($tooltipInner.text()).toBe(''+testCase.expectedValue); 447 | done(); 448 | }; 449 | 450 | handleElem.addEventListener(mouseEventType, handleCallback, false); 451 | handleElem.dispatchEvent(createMouseEvent(mouseEventType, coords.clientX, coords.clientY)); 452 | }); 453 | } 454 | }); 455 | }); 456 | }); 457 | }); 458 | -------------------------------------------------------------------------------- /test/specs/TooltipPositionOptionSpec.js: -------------------------------------------------------------------------------- 1 | /* 2 | ************************* 3 | 4 | tooltip_position Option Test 5 | 6 | ************************* 7 | */ 8 | describe("'tooltip_position' Option tests", function() { 9 | 10 | var testSlider; 11 | 12 | afterEach(function() { 13 | if(testSlider) { 14 | testSlider.destroy(); 15 | testSlider = null; 16 | } 17 | }); 18 | 19 | describe("vertical slider tests", function() { 20 | 21 | it("should be aligned to the left of the handle if set to 'left'", function() { 22 | // Create slider 23 | testSlider = new Slider("#testSlider1", { 24 | min: 0, 25 | max: 10, 26 | value: 5, 27 | tooltip_position: "left", 28 | orientation: "vertical" 29 | }); 30 | 31 | // Extract needed references/values 32 | var mainTooltipHasClassLeft = testSlider.tooltip.classList.contains("bs-tooltip-left"); 33 | 34 | // Assert 35 | expect(mainTooltipHasClassLeft).toBeTruthy(); 36 | expect(testSlider.tooltip.style.right).toBe("100%"); 37 | }); 38 | 39 | it("should be aligned to the right of the handle if set to 'right'", function() { 40 | // Create slider 41 | testSlider = new Slider("#testSlider1", { 42 | min: 0, 43 | max: 10, 44 | value: 5, 45 | tooltip_position: "right", 46 | orientation: "vertical" 47 | }); 48 | 49 | // Extract needed references/values 50 | var mainTooltipHasClassRight = testSlider.tooltip.classList.contains("bs-tooltip-right"); 51 | 52 | // Assert 53 | expect(mainTooltipHasClassRight).toBeTruthy(); 54 | expect(testSlider.tooltip.style.left).toBe("100%"); 55 | }); 56 | 57 | it("should default to 'right' if tooltip_position set to 'top'", function() { 58 | // Create slider 59 | testSlider = new Slider("#testSlider1", { 60 | min: 0, 61 | max: 10, 62 | value: 5, 63 | tooltip_position: "top", 64 | orientation: "vertical" 65 | }); 66 | 67 | // Extract needed references/values 68 | var mainTooltipHasClassRight = testSlider.tooltip.classList.contains("bs-tooltip-right"); 69 | 70 | // Assert 71 | expect(mainTooltipHasClassRight).toBeTruthy(); 72 | expect(testSlider.tooltip.style.left).toBe("100%"); 73 | }); 74 | 75 | it("should default to 'right' if tooltip_position set to 'bottom'", function() { 76 | // Create slider 77 | testSlider = new Slider("#testSlider1", { 78 | min: 0, 79 | max: 10, 80 | value: 5, 81 | tooltip_position: "bottom", 82 | orientation: "vertical" 83 | }); 84 | 85 | // Extract needed references/values 86 | var mainTooltipHasClassRight = testSlider.tooltip.classList.contains("bs-tooltip-right"); 87 | 88 | // Assert 89 | expect(mainTooltipHasClassRight).toBeTruthy(); 90 | expect(testSlider.tooltip.style.left).toBe("100%"); 91 | }); 92 | 93 | }); 94 | 95 | 96 | describe("horizontal slider tests", function() { 97 | 98 | it("should be aligned above the handle if set to 'top'", function() { 99 | // Create slider 100 | testSlider = new Slider("#testSlider1", { 101 | min: 0, 102 | max: 10, 103 | value: 5, 104 | tooltip_position: "top", 105 | orientation: "horizontal" 106 | }); 107 | 108 | // Extract needed references/values 109 | var mainTooltipHasClassTop = testSlider.tooltip.classList.contains("bs-tooltip-top"); 110 | 111 | // Assert 112 | expect(mainTooltipHasClassTop).toBeTruthy(); 113 | expect(testSlider.tooltip.style.top).toBe(""); 114 | }); 115 | 116 | it("should be aligned below the handle if set to 'bottom'", function() { 117 | // Create slider 118 | testSlider = new Slider("#testSlider1", { 119 | min: 0, 120 | max: 10, 121 | value: 5, 122 | tooltip_position: "bottom", 123 | orientation: "horizontal" 124 | }); 125 | 126 | // Extract needed references/values 127 | var mainTooltipHasClassTop = testSlider.tooltip.classList.contains("bs-tooltip-bottom"); 128 | 129 | // Assert 130 | expect(mainTooltipHasClassTop).toBeTruthy(); 131 | expect(testSlider.tooltip.style.top).toBe("22px"); 132 | }); 133 | 134 | it("should be aligned below the handle if set to 'bottom' for range", function() { 135 | // Create slider 136 | testSlider = new Slider("#testSlider1", { 137 | min: 0, 138 | max: 20, 139 | value: [0, 10], 140 | range: true, 141 | tooltip_position: "bottom", 142 | orientation: "horizontal" 143 | }); 144 | 145 | // Extract needed references/values 146 | var mainTooltipHasClassTopMin = testSlider.tooltip_min.classList.contains("bs-tooltip-bottom"); 147 | var mainTooltipHasClassTopMax = testSlider.tooltip_max.classList.contains("bs-tooltip-bottom"); 148 | 149 | // Assert 150 | expect(mainTooltipHasClassTopMin).toBeTruthy(); 151 | expect(mainTooltipHasClassTopMax).toBeTruthy(); 152 | expect(testSlider.tooltip_min.style.top).toBe("22px"); 153 | expect(testSlider.tooltip_max.style.top).toBe("22px"); 154 | }); 155 | 156 | it("should default to 'top' if tooltip_position set to 'left'", function() { 157 | // Create slider 158 | testSlider = new Slider("#testSlider1", { 159 | min: 0, 160 | max: 10, 161 | value: 5, 162 | tooltip_position: "left", 163 | orientation: "horizontal" 164 | }); 165 | 166 | // Extract needed references/values 167 | var mainTooltipHasClassTop = testSlider.tooltip.classList.contains("bs-tooltip-top"); 168 | 169 | // Assert 170 | expect(mainTooltipHasClassTop).toBeTruthy(); 171 | expect(testSlider.tooltip.style.top).toBe(""); 172 | }); 173 | 174 | it("should default to 'top' if tooltip_position set to 'right'", function() { 175 | // Create slider 176 | testSlider = new Slider("#testSlider1", { 177 | min: 0, 178 | max: 10, 179 | value: 5, 180 | tooltip_position: "right", 181 | orientation: "horizontal" 182 | }); 183 | 184 | // Extract needed references/values 185 | var mainTooltipHasClassTop = testSlider.tooltip.classList.contains("bs-tooltip-top"); 186 | 187 | // Assert 188 | expect(mainTooltipHasClassTop).toBeTruthy(); 189 | expect(testSlider.tooltip.style.top).toBe(""); 190 | }); 191 | 192 | }); 193 | 194 | }); 195 | -------------------------------------------------------------------------------- /test/specs/TooltipSplitOptionSpec.js: -------------------------------------------------------------------------------- 1 | /* 2 | ************************* 3 | 4 | tooltip_split Option Test 5 | 6 | ************************* 7 | 8 | This spec tests if tooltip_main, tooltip_min and tooltip_max 9 | behave correctly when tooltip_split option is set to true or false. 10 | */ 11 | describe("'tooltip_split' Option tests", function() { 12 | var testSlider, sliderId = "tooltipedSlider", 13 | $slider, $tooltipMain, $tooltipMin, $tooltipMax, 14 | sliderOptions = {id: sliderId, value: [0, 10], tooltip: "always"}; // for the sake of testing, always display the tooltip 15 | 16 | describe("When 'tooltip_split' is false", function() { 17 | beforeEach(function() { 18 | testSlider = $("#testSlider1").slider($.extend(sliderOptions, {tooltip_split: false})); 19 | $slider = $("#"+sliderId); 20 | $tooltipMain = $slider.find(".tooltip-main"); 21 | $tooltipMin = $slider.find(".tooltip-min"); 22 | $tooltipMax = $slider.find(".tooltip-max"); 23 | }); 24 | 25 | it("should have `tooltip-main` displayed with `show` class", function() { 26 | expect($tooltipMain.css("display")).not.toBe("none"); 27 | expect($tooltipMain.hasClass("show")).toBeTruthy(); 28 | }); 29 | 30 | it("should have `tooltip-min, tooltip-max` not displayed", function() { 31 | expect($tooltipMin.css("display")).toBe("none"); 32 | expect($tooltipMin.hasClass("show")).toBeFalsy(); 33 | expect($tooltipMax.css("display")).toBe("none"); 34 | expect($tooltipMax.hasClass("show")).toBeFalsy(); 35 | }); 36 | }); 37 | 38 | describe("When 'tooltip_split' is true", function() { 39 | beforeEach(function() { 40 | testSlider = $("#testSlider1").slider($.extend(sliderOptions, {tooltip_split: true})); 41 | $slider = $("#"+sliderId); 42 | $tooltipMain = $slider.find(".tooltip-main"); 43 | $tooltipMin = $slider.find(".tooltip-min"); 44 | $tooltipMax = $slider.find(".tooltip-max"); 45 | }); 46 | 47 | it("should have `tooltip-min, tooltip-max` displayed with `show` class", function() { 48 | expect($tooltipMin.css("display")).not.toBe("none"); 49 | expect($tooltipMin.hasClass("show")).toBeTruthy(); 50 | expect($tooltipMax.css("display")).not.toBe("none"); 51 | expect($tooltipMax.hasClass("show")).toBeTruthy(); 52 | }); 53 | 54 | it("should have `tooltip-main` not displayed", function() { 55 | expect($tooltipMain.css("display")).toBe("none"); 56 | expect($tooltipMain.hasClass("show")).toBeFalsy(); 57 | }); 58 | 59 | it("should be aligned above the handle on init if set to 'top'", function() { 60 | expect($tooltipMin.hasClass("bs-tooltip-top")).toBeTruthy(); 61 | expect($tooltipMax.hasClass("bs-tooltip-top")).toBeTruthy(); 62 | }); 63 | }); 64 | 65 | afterEach(function() { 66 | if(testSlider) { 67 | testSlider.slider('destroy'); 68 | testSlider = null; 69 | } 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /test/specs/offMethodSpec.js: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------- 2 | //-------------------------------------------------- 3 | //-- Removes attached function from slider event -- 4 | //-------------------------------------------------- 5 | //-------------------------------------------------- 6 | 7 | 8 | 9 | describe("'off()' test", function() { 10 | var testSlider, eventHandlerTriggered, mouse; 11 | 12 | var onStart = function(){ 13 | eventHandlerTriggered = true; 14 | }; 15 | 16 | 17 | beforeEach(function() { 18 | eventHandlerTriggered = false; 19 | mouse = document.createEvent('MouseEvents'); 20 | }); 21 | 22 | 23 | it("should properly unbind an event listener", function() { 24 | testSlider = $("#testSlider1").slider(); 25 | 26 | testSlider.on('slideStart', onStart); 27 | testSlider.off('slideStart', onStart); 28 | 29 | testSlider.data('slider')._mousedown(mouse); 30 | 31 | expect(eventHandlerTriggered).not.toBeTruthy(); 32 | }); 33 | }); -------------------------------------------------------------------------------- /tpl/SpecRunner.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Jasmine Spec Runner 6 | <% css.forEach(function(style){ %> 7 | 8 | <% }) %> 9 | 40 | 41 | 42 |
45 | 46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
92 | 93 |
94 | 95 | 98 | 99 | 102 | 103 |
104 |

just a row

105 |

just a row

106 | 107 |
108 | 109 |
110 | 111 |
Text
112 |
113 | 114 |
115 | 116 |
More text
117 |
118 | 119 |
120 | 121 |
122 | 123 | 124 | 125 | 126 | 127 | 128 |
129 | Label A 130 | Label B 131 | 132 | 133 | 134 | 135 |
136 | 137 |
138 | 139 |
140 | 141 | <% with (scripts) { %> 142 | <% [].concat(polyfills, jasmine, boot, vendor, helpers, src, specs,reporters).forEach(function(script){ %> 143 | 144 | <% }) %> 145 | <% }; %> 146 | 147 | 148 | --------------------------------------------------------------------------------