├── .gitattributes ├── .gitignore ├── .jscsrc ├── .jshintrc ├── README.md ├── bower.json ├── dist ├── jquery-ui-slider-pips.css ├── jquery-ui-slider-pips.js ├── jquery-ui-slider-pips.min.css └── jquery-ui-slider-pips.min.js ├── gulpfile.js ├── package.json └── src ├── css └── jquery-ui-slider-pips.scss └── js └── jquery-ui-slider-pips.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | 33 | 34 | 35 | ################# 36 | ## Visual Studio 37 | ################# 38 | 39 | ## Ignore Visual Studio temporary files, build results, and 40 | ## files generated by popular Visual Studio add-ons. 41 | 42 | # User-specific files 43 | *.suo 44 | *.user 45 | *.sln.docstates 46 | 47 | # Build results 48 | [Dd]ebug/ 49 | [Rr]elease/ 50 | *_i.c 51 | *_p.c 52 | *.ilk 53 | *.meta 54 | *.obj 55 | *.pch 56 | *.pdb 57 | *.pgc 58 | *.pgd 59 | *.rsp 60 | *.sbr 61 | *.tlb 62 | *.tli 63 | *.tlh 64 | *.tmp 65 | *.vspscc 66 | .builds 67 | *.dotCover 68 | 69 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 70 | #packages/ 71 | 72 | # Visual C++ cache files 73 | ipch/ 74 | *.aps 75 | *.ncb 76 | *.opensdf 77 | *.sdf 78 | 79 | # Visual Studio profiler 80 | *.psess 81 | *.vsp 82 | 83 | # ReSharper is a .NET coding add-in 84 | _ReSharper* 85 | 86 | # Installshield output folder 87 | [Ee]xpress 88 | 89 | # DocProject is a documentation generator add-in 90 | DocProject/buildhelp/ 91 | DocProject/Help/*.HxT 92 | DocProject/Help/*.HxC 93 | DocProject/Help/*.hhc 94 | DocProject/Help/*.hhk 95 | DocProject/Help/*.hhp 96 | DocProject/Help/Html2 97 | DocProject/Help/html 98 | 99 | # Click-Once directory 100 | publish 101 | 102 | # Others 103 | [Bb]in 104 | [Oo]bj 105 | sql 106 | TestResults 107 | *.Cache 108 | ClientBin 109 | stylecop.* 110 | ~$* 111 | *.dbmdl 112 | Generated_Code #added for RIA/Silverlight projects 113 | 114 | # Backup & report files from converting an old project file to a newer 115 | # Visual Studio version. Backup files are not needed, because we have git ;-) 116 | _UpgradeReport_Files/ 117 | Backup*/ 118 | UpgradeLog*.XML 119 | 120 | 121 | 122 | 123 | ############ 124 | ## Windows / OSX 125 | ############ 126 | 127 | # Image file caches 128 | Thumbs.db 129 | .DS_Store 130 | 131 | # Folder config file 132 | Desktop.ini 133 | 134 | 135 | ############# 136 | ## Python 137 | ############# 138 | 139 | *.py[co] 140 | 141 | # Packages 142 | *.egg 143 | *.egg-info 144 | build 145 | eggs 146 | parts 147 | bin 148 | var 149 | sdist 150 | develop-eggs 151 | .installed.cfg 152 | 153 | # Installer logs 154 | pip-log.txt 155 | 156 | # Unit test / coverage reports 157 | .coverage 158 | .tox 159 | 160 | #Translations 161 | *.mo 162 | 163 | #Mr Developer 164 | .mr.developer.cfg 165 | 166 | 167 | 168 | ############ 169 | ## Node 170 | ############ 171 | node_modules/ 172 | 173 | 174 | ############ 175 | ## Bower 176 | ############ 177 | bower_components 178 | 179 | 180 | ############ 181 | ## Sass 182 | ############ 183 | .sass-cache 184 | 185 | 186 | 187 | ######################################### 188 | 189 | demo.html -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "maximumLineLength": 120, 4 | 5 | "disallowCapitalizedComments": true, 6 | "disallowDanglingUnderscores": { "allExcept": [ 7 | "_this", 8 | "_data", 9 | "_valueMin", 10 | "_valueMax", 11 | "_value", 12 | "_values", 13 | "_lastChangedValue", 14 | "_change", 15 | "_trimAlignValue", 16 | "_refreshValue"] }, 17 | "disallowEmptyBlocks": true, 18 | "disallowImplicitTypeConversion": [ "string", "number" ], 19 | "disallowKeywordsOnNewLine": [ "else", "catch", "while" ], 20 | "disallowKeywords": [ "with" ], 21 | "disallowMixedSpacesAndTabs": true, 22 | "disallowMultipleLineStrings": true, 23 | "disallowMultipleSpaces": true, 24 | "disallowNamedUnassignedFunctions": true, 25 | "disallowNewlineBeforeBlockStatements": true, 26 | "disallowOperatorBeforeLineBreak": ["."], 27 | "disallowQuotedKeysInObjects": "allButReserved", 28 | "disallowSpaceAfterKeywords": ["function"], 29 | "disallowSpaceAfterObjectKeys": true, 30 | "disallowSpaceBeforePostfixUnaryOperators": ["++", "--"], 31 | "disallowSpacesInCallExpression": true, 32 | "disallowTrailingComma": true, 33 | "disallowTrailingWhitespace": true, 34 | "disallowYodaConditions": true, 35 | 36 | "requireAlignedObjectValues": false, 37 | "requireAnonymousFunctions": true, 38 | "requireBlocksOnNewline": 1, 39 | "requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties", 40 | "requireCapitalizedConstructors": true, 41 | "requireCommaBeforeLineBreak": true, 42 | "requireCurlyBraces": true, 43 | "requireDollarBeforejQueryAssignment": true, 44 | "requireDotNotation": true, 45 | "requireLineBreakAfterVariableAssignment": true, 46 | "requireLineFeedAtFileEnd": true, 47 | "requireMultipleVarDecl": true, 48 | "requireOperatorBeforeLineBreak": true, 49 | "requirePaddingNewLinesAfterUseStrict": true, 50 | "requirePaddingNewLinesBeforeExport": true, 51 | "requirePaddingNewlinesBeforeKeywords": ["do", "for", "if", "switch", "try", "void", "while", "return"], 52 | "requirePaddingNewLinesBeforeLineComments": { "allExcept": "firstAfterCurly" }, 53 | "requirePaddingNewlinesInBlocks": 1, 54 | "requireParenthesesAroundIIFE": true, 55 | "requireSpaceAfterBinaryOperators": true, 56 | "requireSpaceAfterKeywords": ["do", "for", "if", "else", "switch", "try", "catch", "void", "while", "return", "typeof"], 57 | "requireSpaceAfterLineComment": true, 58 | "requireSpaceBeforeBinaryOperators": true, 59 | "requireSpaceBeforeBlockStatements": true, 60 | "requireSpaceBetweenArguments": true, 61 | "requireSpacesInAnonymousFunctionExpression": { 62 | "beforeOpeningCurlyBrace": true 63 | }, 64 | "requireSpacesInConditionalExpression": true, 65 | "requireSpacesInForStatement": true, 66 | "requireSpacesInFunction": { 67 | "beforeOpeningCurlyBrace": true 68 | }, 69 | "requireSpacesInFunctionDeclaration": { 70 | "beforeOpeningCurlyBrace": true 71 | }, 72 | "requireSpacesInFunctionExpression": { 73 | "beforeOpeningCurlyBrace": true 74 | }, 75 | "requireSpacesInNamedFunctionExpression": { 76 | "beforeOpeningCurlyBrace": true 77 | }, 78 | //"requireSpacesInsideArrayBrackets": "all", 79 | //"requireSpacesInsideObjectBrackets": "allButNested", 80 | //"requireSpacesInsideParentheses": "allButNested", 81 | "safeContextKeyword": ["_this", "$this", "slider"], 82 | "validateIndentation": 4, 83 | "validateParameterSeparator": ", ", 84 | "validateQuoteMarks": true 85 | } -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | // JSHint Default Configuration File (as on JSHint website) 3 | // See http://jshint.com/docs/ for more details 4 | 5 | "maxerr" : 50, // {int} Maximum error before stopping 6 | 7 | // Enforcing 8 | "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) 9 | "camelcase" : true, // true: Identifiers must be in camelCase 10 | "curly" : true, // true: Require {} for every new block or scope 11 | "eqeqeq" : true, // true: Require triple equals (===) for comparison 12 | "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() 13 | "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc. 14 | "immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` 15 | "indent" : 4, // {int} Number of spaces to use for indentation 16 | "latedef" : true, // true: Require variables/functions to be defined before being used 17 | "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()` 18 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` 19 | "noempty" : true, // true: Prohibit use of empty blocks 20 | "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters. 21 | "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) 22 | "plusplus" : false, // true: Prohibit use of `++` & `--` 23 | "quotmark" : true, // Quotation mark consistency: 24 | // false : do nothing (default) 25 | // true : ensure whatever is used is consistent 26 | // "single" : require single quotes 27 | // "double" : require double quotes 28 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) 29 | "unused" : true, // Unused variables: 30 | // true : all variables, last function parameter 31 | // "vars" : all variables only 32 | // "strict" : all variables, all function parameters 33 | "strict" : true, // true: Requires all functions run in ES5 Strict Mode 34 | "maxparams" : 3, // {int} Max number of formal params allowed per function 35 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions) 36 | "maxstatements" : false, // {int} Max number statements per function 37 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function 38 | "maxlen" : 120, // {int} Max number of characters per line 39 | "varstmt" : false, // true: Disallow any var statements. Only `let` and `const` are allowed. 40 | 41 | // Relaxing 42 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) 43 | "boss" : false, // true: Tolerate assignments where comparisons would be expected 44 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. 45 | "eqnull" : false, // true: Tolerate use of `== null` 46 | "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) 47 | "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) 48 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) 49 | // (ex: `for each`, multiple try/catch, function expression…) 50 | "evil" : false, // true: Tolerate use of `eval` and `new Function()` 51 | "expr" : false, // true: Tolerate `ExpressionStatement` as Programs 52 | "funcscope" : false, // true: Tolerate defining variables inside control statements 53 | "globalstrict" : true, // true: Allow global "use strict" (also enables 'strict') 54 | "iterator" : false, // true: Tolerate using the `__iterator__` property 55 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block 56 | "laxbreak" : false, // true: Tolerate possibly unsafe line breakings 57 | "laxcomma" : false, // true: Tolerate comma-first style coding 58 | "loopfunc" : false, // true: Tolerate functions being defined in loops 59 | "multistr" : false, // true: Tolerate multi-line strings 60 | "noyield" : false, // true: Tolerate generator functions with no yield statement in them. 61 | "notypeof" : false, // true: Tolerate invalid typeof operator values 62 | "proto" : false, // true: Tolerate using the `__proto__` property 63 | "scripturl" : false, // true: Tolerate script-targeted URLs 64 | "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` 65 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation 66 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` 67 | "validthis" : false, // true: Tolerate using this in a non-constructor function 68 | 69 | // Environments 70 | "browser" : true, // Web Browser (window, document, etc) 71 | "browserify" : false, // Browserify (node.js code in the browser) 72 | "couch" : false, // CouchDB 73 | "devel" : true, // Development/debugging (alert, confirm, etc) 74 | "dojo" : false, // Dojo Toolkit 75 | "jasmine" : false, // Jasmine 76 | "jquery" : true, // jQuery 77 | "mocha" : false, // Mocha 78 | "mootools" : false, // MooTools 79 | "node" : true, // Node.js 80 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) 81 | "phantom" : false, // PhantomJS 82 | "prototypejs" : false, // Prototype and Scriptaculous 83 | "qunit" : false, // QUnit 84 | "rhino" : false, // Rhino 85 | "shelljs" : false, // ShellJS 86 | "typed" : false, // Globals for typed array constructions 87 | "worker" : false, // Web Workers 88 | "wsh" : false, // Windows Scripting Host 89 | "yui" : false, // Yahoo User Interface 90 | 91 | // Custom Globals 92 | "globals" : {} // additional predefined global variables 93 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > ## ⚠ **Unmaintained / Deprecated** 2 | > [Use `svelte-range-slider-pips` instead! 🔗](https://github.com/simeydotme/svelte-range-slider-pips) 3 | > 4 | > _While this plugin should still function (if you're using an older version of jQueryUI) I don't think it's good enough for modern use and goes against some newer ideals (low dependency, low kb, less opinions on style) ... therefore I'd suggest moving away from this, and jQueryUI, and perhaps [look at using the newer **svelte-range-slider-pips**](https://github.com/simeydotme/svelte-range-slider-pips) module which should work in all environments!_ 5 | > 6 | 7 | # jQuery UI Slider Pips 8 | #### Plugin to add "pips" or "floats" to a JQUI Slider. 9 | 10 | [![Join the chat at https://gitter.im/simeydotme/jQuery-ui-Slider-Pips](https://badges.gitter.im/simeydotme/jQuery-ui-Slider-Pips.svg)](https://gitter.im/simeydotme/jQuery-ui-Slider-Pips?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 11 | 12 | 13 | This plugin **extends** the [jQuery UI Slider widget](http://jqueryui.com/slider/). 14 | Use it for creating a nicely-styled slider like shown below 15 | [Documentation, Demos and Examples here](http://simeydotme.github.io/jQuery-ui-Slider-Pips/) 16 | 17 | --- 18 | 19 | #### Want to contribute?: 20 | Please make sure to create a JSFiddle to demonstrate any problems, or pull requests, with this as a base: http://jsfiddle.net/simeydotme/Lh6pygef/ (press **fork** on the toolbar) 21 | 22 | --- 23 | 24 | ![Default settings for the plugin](http://files.simey.me/pips.jpg "Example of Pips plugin with default options") 25 | ![Example of the slider in use](https://cloud.githubusercontent.com/assets/2817396/3999716/d887ebf2-2952-11e4-9044-0c1b6baba99a.gif "Slider being used by a person with a mouse") 26 | 27 | ### Install 28 | If you're using [Bower](http://bower.io) you can install this plugin quickly from the command-line! :) 29 | ```bash 30 | bower install jquery-ui-slider-pips --save 31 | ``` 32 | 33 | Otherwise, you may download the files in the `/dist/` folder. 34 | 35 | ------------------------------------ 36 | 37 | ### Requirements: 38 | - jQuery (1.9+) 39 | - jQuery UI (1.10+) 40 | 41 | ------------------------------------ 42 | 43 | ### Usage: 44 | Include the plugin javascript file __after__ jQuery & jQuery-ui. 45 | Include the CSS file; edit as you please. 46 | _Below methods are chainable, I've shown them separate for clarity_ 47 | 48 | #### Default usage: 49 | 50 | ```html 51 | 54 |
55 | ``` 56 | 57 | ```javascript 58 | // if you just want the defaults, copy & paste this code. 59 | $('.element').slider().slider('pips').slider('float'); 60 | ``` 61 | 62 | #### Advanced usage with options: 63 | ```javascript 64 | 65 | // First of all attach a slider to an element. 66 | // If you want to set values, you do it in the initialization. 67 | $('.element').slider({ 68 | min: 20, 69 | max: 65, 70 | values: [30, 40, 50] 71 | }); 72 | 73 | // Then you can give it pips and labels! 74 | $('.element').slider('pips', { 75 | first: 'label', 76 | last: 'label', 77 | rest: 'pip', 78 | labels: ['label1', 'label2', ...], 79 | prefix: "", 80 | suffix: "" 81 | }); 82 | 83 | // And finally can add floaty numbers (if desired) 84 | $('.element').slider('float', { 85 | handle: true, 86 | pips: true, 87 | labels: ['label1', 'label2', ...], 88 | prefix: "", 89 | suffix: "" 90 | }); 91 | ``` 92 | 93 | #### Options for pips: 94 | **first:** `"pip"` or `"label"` or `false` 95 | **last:** `"pip"` or `"label"` or `false` 96 | **rest:** `"pip"` or `"label"` or `false` 97 | **labels:** `[]` or `{first: "", last: "", rest: [] }` or `false` 98 | **prefix:** `"string"` 99 | **suffix:** `"string"` 100 | **formatLabel:** `function(val){ return this.prefix + val + this.suffix }` 101 | 102 | ####Options for float: 103 | **handle:** `true` or `false` 104 | **pips:** `true` or `false` 105 | **labels:** `[]` or `{first: "", last: "", rest: [] }` or `false` 106 | **prefix:** `"string"` 107 | **suffix:** `"string"` 108 | **formatLabel:** `function(val){ return this.prefix + val + this.suffix }` 109 | 110 | 111 | 112 | 113 | ------------------------------------ 114 | 115 | ### Style Customisation: 116 | All customisation should be done to the CSS file, or in your own CSS. 117 | The base styles I've provided do a decent job in the Demo, 118 | but they may need tweaking to suit your needs and UI theme. 119 | For some inspiration and help with styling, [go to the styling section of the documentation.](http://simeydotme.github.io/jQuery-ui-Slider-Pips/#styling) 120 | 121 | ------------------------------------ 122 | 123 | ### Compatibility: 124 | Modern Browsers, IE7+ 125 | _(To really support IE7 you will need to do some CSS changes.)_ 126 | 127 | ------------------------------------ 128 | 129 | ### License: 130 | Open Source MIT. 131 | http://opensource.org/licenses/MIT 132 | 133 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jQuery-ui-Slider-Pips", 3 | "version": "1.11.4", 4 | "description": "A plugin to add little \"pips\" to the jQuery UI Slider widget", 5 | "main": [ 6 | "dist/jquery-ui-slider-pips.css", 7 | "dist/jquery-ui-slider-pips.js" 8 | ], 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/simeydotme/jQuery-ui-Slider-Pips.git" 12 | }, 13 | "license": "MIT", 14 | "keywords": [ 15 | "jquery", 16 | "ui", 17 | "slider", 18 | "widget", 19 | "pips", 20 | "points", 21 | "labels", 22 | "floats", 23 | "markers", 24 | "waypoints" 25 | ], 26 | "authors": [ 27 | "Simon Goellner " 28 | ], 29 | "ignore": [ 30 | ".gitattributes", 31 | ".gitignore", 32 | "gulpfile.js", 33 | "*.json", 34 | "*.md", 35 | "*.txt", 36 | "*.html", 37 | "src", 38 | "node_modules" 39 | ], 40 | "dependencies": { 41 | "jquery": ">=1.10.2", 42 | "jquery-ui": ">=1.9.2" 43 | }, 44 | "devDependencies": {} 45 | } 46 | -------------------------------------------------------------------------------- /dist/jquery-ui-slider-pips.css: -------------------------------------------------------------------------------- 1 | /*! jQuery-ui-Slider-Pips - v1.11.4 - 2016-09-04 2 | * Copyright (c) 2016 Simon Goellner ; Licensed MIT */ 3 | 4 | /* HORIZONTAL */ 5 | /* increase bottom margin to fit the pips */ 6 | .ui-slider-horizontal.ui-slider-pips { 7 | margin-bottom: 1.4em; 8 | } 9 | 10 | /* default hide the labels and pips that arnt visible */ 11 | /* we just use css to hide incase we want to show certain */ 12 | /* labels/pips individually later */ 13 | .ui-slider-pips .ui-slider-label, 14 | .ui-slider-pips .ui-slider-pip-hide { 15 | display: none; 16 | } 17 | 18 | /* now we show any labels that we've set to show in the options */ 19 | .ui-slider-pips .ui-slider-pip-label .ui-slider-label { 20 | display: block; 21 | } 22 | 23 | /* PIP/LABEL WRAPPER */ 24 | /* position each pip absolutely just below the default slider */ 25 | /* and also prevent accidental selection */ 26 | .ui-slider-pips .ui-slider-pip { 27 | width: 2em; 28 | height: 1em; 29 | line-height: 1em; 30 | position: absolute; 31 | font-size: 0.8em; 32 | color: #999; 33 | overflow: visible; 34 | text-align: center; 35 | top: 20px; 36 | left: 20px; 37 | margin-left: -1em; 38 | cursor: pointer; 39 | -webkit-touch-callout: none; 40 | -webkit-user-select: none; 41 | -moz-user-select: none; 42 | -ms-user-select: none; 43 | user-select: none; 44 | } 45 | 46 | .ui-state-disabled.ui-slider-pips .ui-slider-pip { 47 | cursor: default; 48 | } 49 | 50 | /* little pip/line position & size */ 51 | .ui-slider-pips .ui-slider-line { 52 | background: #999; 53 | width: 1px; 54 | height: 3px; 55 | position: absolute; 56 | left: 50%; 57 | } 58 | 59 | /* the text label postion & size */ 60 | /* it overflows so no need for width to be accurate */ 61 | .ui-slider-pips .ui-slider-label { 62 | position: absolute; 63 | top: 5px; 64 | left: 50%; 65 | margin-left: -1em; 66 | width: 2em; 67 | } 68 | 69 | /* make it easy to see when we hover a label */ 70 | .ui-slider-pips:not(.ui-slider-disabled) .ui-slider-pip:hover .ui-slider-label { 71 | color: black; 72 | font-weight: bold; 73 | } 74 | 75 | /* VERTICAL */ 76 | /* vertical slider needs right-margin, not bottom */ 77 | .ui-slider-vertical.ui-slider-pips { 78 | margin-bottom: 1em; 79 | margin-right: 2em; 80 | } 81 | 82 | /* align vertical pips left and to right of the slider */ 83 | .ui-slider-vertical.ui-slider-pips .ui-slider-pip { 84 | text-align: left; 85 | top: auto; 86 | left: 20px; 87 | margin-left: 0; 88 | margin-bottom: -0.5em; 89 | } 90 | 91 | /* vertical line/pip should be horizontal instead */ 92 | .ui-slider-vertical.ui-slider-pips .ui-slider-line { 93 | width: 3px; 94 | height: 1px; 95 | position: absolute; 96 | top: 50%; 97 | left: 0; 98 | } 99 | 100 | .ui-slider-vertical.ui-slider-pips .ui-slider-label { 101 | top: 50%; 102 | left: 0.5em; 103 | margin-left: 0; 104 | margin-top: -0.5em; 105 | width: 2em; 106 | } 107 | 108 | /* FLOATING HORIZTONAL TOOLTIPS */ 109 | /* remove the godawful looking focus outline on handle and float */ 110 | .ui-slider-float .ui-slider-handle:focus, 111 | .ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip-label, 112 | .ui-slider-float .ui-slider-handle:focus .ui-slider-tip, 113 | .ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip-label, 114 | .ui-slider-float .ui-slider-handle:focus .ui-slider-tip-label 115 | .ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip-label { 116 | outline: none; 117 | } 118 | 119 | /* style tooltips on handles and on labels */ 120 | /* also has a nice transition */ 121 | .ui-slider-float .ui-slider-tip, 122 | .ui-slider-float .ui-slider-tip-label { 123 | position: absolute; 124 | visibility: hidden; 125 | top: -40px; 126 | display: block; 127 | width: 34px; 128 | margin-left: -18px; 129 | left: 50%; 130 | height: 20px; 131 | line-height: 20px; 132 | background: white; 133 | border-radius: 3px; 134 | border: 1px solid #888; 135 | text-align: center; 136 | font-size: 12px; 137 | opacity: 0; 138 | color: #333; 139 | -webkit-transition-property: opacity, top, visibility; 140 | transition-property: opacity, top, visibility; 141 | -webkit-transition-timing-function: ease-in; 142 | transition-timing-function: ease-in; 143 | -webkit-transition-duration: 200ms, 200ms, 0ms; 144 | transition-duration: 200ms, 200ms, 0ms; 145 | -webkit-transition-delay: 0ms, 0ms, 200ms; 146 | transition-delay: 0ms, 0ms, 200ms; 147 | } 148 | 149 | /* show the tooltip on hover or focus */ 150 | /* also switch transition delay around */ 151 | .ui-slider-float .ui-slider-handle:hover .ui-slider-tip, 152 | .ui-slider-float .ui-slider-handle.ui-state-hover .ui-slider-tip, 153 | .ui-slider-float .ui-slider-handle:focus .ui-slider-tip, 154 | .ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip, 155 | .ui-slider-float .ui-slider-handle.ui-state-active .ui-slider-tip, 156 | .ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label { 157 | opacity: 1; 158 | top: -30px; 159 | visibility: visible; 160 | -webkit-transition-timing-function: ease-out; 161 | transition-timing-function: ease-out; 162 | -webkit-transition-delay: 200ms, 200ms, 0ms; 163 | transition-delay: 200ms, 200ms, 0ms; 164 | } 165 | 166 | /* put label tooltips below slider */ 167 | .ui-slider-float .ui-slider-pip .ui-slider-tip-label { 168 | top: 42px; 169 | } 170 | 171 | .ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label { 172 | top: 32px; 173 | font-weight: normal; 174 | } 175 | 176 | /* give the tooltip a css triangle arrow */ 177 | .ui-slider-float .ui-slider-tip:after, 178 | .ui-slider-float .ui-slider-pip .ui-slider-tip-label:after { 179 | content: " "; 180 | width: 0; 181 | height: 0; 182 | border: 5px solid rgba(255, 255, 255, 0); 183 | border-top-color: white; 184 | position: absolute; 185 | bottom: -10px; 186 | left: 50%; 187 | margin-left: -5px; 188 | } 189 | 190 | /* put a 1px border on the tooltip arrow to match tooltip border */ 191 | .ui-slider-float .ui-slider-tip:before, 192 | .ui-slider-float .ui-slider-pip .ui-slider-tip-label:before { 193 | content: " "; 194 | width: 0; 195 | height: 0; 196 | border: 5px solid rgba(255, 255, 255, 0); 197 | border-top-color: #888; 198 | position: absolute; 199 | bottom: -11px; 200 | left: 50%; 201 | margin-left: -5px; 202 | } 203 | 204 | /* switch the arrow to top on labels */ 205 | .ui-slider-float .ui-slider-pip .ui-slider-tip-label:after { 206 | border: 5px solid rgba(255, 255, 255, 0); 207 | border-bottom-color: white; 208 | top: -10px; 209 | } 210 | 211 | .ui-slider-float .ui-slider-pip .ui-slider-tip-label:before { 212 | border: 5px solid rgba(255, 255, 255, 0); 213 | border-bottom-color: #888; 214 | top: -11px; 215 | } 216 | 217 | /* FLOATING VERTICAL TOOLTIPS */ 218 | /* tooltip floats to left of handle */ 219 | .ui-slider-vertical.ui-slider-float .ui-slider-tip, 220 | .ui-slider-vertical.ui-slider-float .ui-slider-tip-label { 221 | top: 50%; 222 | margin-top: -11px; 223 | width: 34px; 224 | margin-left: 0px; 225 | left: -60px; 226 | color: #333; 227 | -webkit-transition-duration: 200ms, 200ms, 0; 228 | transition-duration: 200ms, 200ms, 0; 229 | -webkit-transition-property: opacity, left, visibility; 230 | transition-property: opacity, left, visibility; 231 | -webkit-transition-delay: 0, 0, 200ms; 232 | transition-delay: 0, 0, 200ms; 233 | } 234 | 235 | .ui-slider-vertical.ui-slider-float .ui-slider-handle:hover .ui-slider-tip, 236 | .ui-slider-vertical.ui-slider-float .ui-slider-handle.ui-state-hover .ui-slider-tip, 237 | .ui-slider-vertical.ui-slider-float .ui-slider-handle:focus .ui-slider-tip, 238 | .ui-slider-vertical.ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip, 239 | .ui-slider-vertical.ui-slider-float .ui-slider-handle.ui-state-active .ui-slider-tip, 240 | .ui-slider-vertical.ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label { 241 | top: 50%; 242 | margin-top: -11px; 243 | left: -50px; 244 | } 245 | 246 | /* put label tooltips to right of slider */ 247 | .ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label { 248 | left: 47px; 249 | } 250 | 251 | .ui-slider-vertical.ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label { 252 | left: 37px; 253 | } 254 | 255 | /* give the tooltip a css triangle arrow */ 256 | .ui-slider-vertical.ui-slider-float .ui-slider-tip:after, 257 | .ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:after { 258 | border: 5px solid rgba(255, 255, 255, 0); 259 | border-left-color: white; 260 | border-top-color: transparent; 261 | position: absolute; 262 | bottom: 50%; 263 | margin-bottom: -5px; 264 | right: -10px; 265 | margin-left: 0; 266 | top: auto; 267 | left: auto; 268 | } 269 | 270 | .ui-slider-vertical.ui-slider-float .ui-slider-tip:before, 271 | .ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:before { 272 | border: 5px solid rgba(255, 255, 255, 0); 273 | border-left-color: #888; 274 | border-top-color: transparent; 275 | position: absolute; 276 | bottom: 50%; 277 | margin-bottom: -5px; 278 | right: -11px; 279 | margin-left: 0; 280 | top: auto; 281 | left: auto; 282 | } 283 | 284 | .ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:after { 285 | border: 5px solid rgba(255, 255, 255, 0); 286 | border-right-color: white; 287 | right: auto; 288 | left: -10px; 289 | } 290 | 291 | .ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:before { 292 | border: 5px solid rgba(255, 255, 255, 0); 293 | border-right-color: #888; 294 | right: auto; 295 | left: -11px; 296 | } 297 | 298 | /* SELECTED STATES */ 299 | /* Comment out this chuck of code if you don't want to have 300 | the new label colours shown */ 301 | .ui-slider-pips [class*=ui-slider-pip-initial] { 302 | font-weight: bold; 303 | color: #14CA82; 304 | } 305 | 306 | .ui-slider-pips .ui-slider-pip-initial-2 { 307 | color: #1897C9; 308 | } 309 | 310 | .ui-slider-pips [class*=ui-slider-pip-selected] { 311 | font-weight: bold; 312 | color: #FF7A00; 313 | } 314 | 315 | .ui-slider-pips .ui-slider-pip-inrange { 316 | color: black; 317 | } 318 | 319 | .ui-slider-pips .ui-slider-pip-selected-2 { 320 | color: #E70081; 321 | } 322 | 323 | .ui-slider-pips [class*=ui-slider-pip-selected] .ui-slider-line, 324 | .ui-slider-pips .ui-slider-pip-inrange .ui-slider-line { 325 | background: black; 326 | } 327 | -------------------------------------------------------------------------------- /dist/jquery-ui-slider-pips.js: -------------------------------------------------------------------------------- 1 | /*! jQuery-ui-Slider-Pips - v1.11.4 - 2016-09-04 2 | * Copyright (c) 2016 Simon Goellner ; Licensed MIT */ 3 | 4 | (function($) { 5 | 6 | "use strict"; 7 | 8 | var extensionMethods = { 9 | 10 | 11 | 12 | 13 | 14 | // pips 15 | 16 | pips: function( settings ) { 17 | 18 | var slider = this, 19 | i, j, p, 20 | collection = "", 21 | mousedownHandlers, 22 | min = slider._valueMin(), 23 | max = slider._valueMax(), 24 | pips = ( max - min ) / slider.options.step, 25 | $handles = slider.element.find(".ui-slider-handle"), 26 | $pips; 27 | 28 | var options = { 29 | 30 | first: "label", 31 | /* "label", "pip", false */ 32 | 33 | last: "label", 34 | /* "label", "pip", false */ 35 | 36 | rest: "pip", 37 | /* "label", "pip", false */ 38 | 39 | labels: false, 40 | /* [array], { first: "string", rest: [array], last: "string" }, false */ 41 | 42 | prefix: "", 43 | /* "", string */ 44 | 45 | suffix: "", 46 | /* "", string */ 47 | 48 | step: ( pips > 100 ) ? Math.floor( pips * 0.05 ) : 1, 49 | /* number */ 50 | 51 | formatLabel: function(value) { 52 | return this.prefix + value + this.suffix; 53 | } 54 | /* function 55 | must return a value to display in the pip labels */ 56 | 57 | }; 58 | 59 | if ( $.type( settings ) === "object" || $.type( settings ) === "undefined" ) { 60 | 61 | $.extend( options, settings ); 62 | slider.element.data("pips-options", options ); 63 | 64 | } else { 65 | 66 | if ( settings === "destroy" ) { 67 | 68 | destroy(); 69 | 70 | } else if ( settings === "refresh" ) { 71 | 72 | slider.element.slider( "pips", slider.element.data("pips-options") ); 73 | 74 | } 75 | 76 | return; 77 | 78 | } 79 | 80 | 81 | // we don't want the step ever to be a floating point or negative 82 | // (or 0 actually, so we'll set it to 1 in that case). 83 | slider.options.pipStep = Math.abs( Math.round( options.step ) ) || 1; 84 | 85 | // get rid of all pips that might already exist. 86 | slider.element 87 | .off( ".selectPip" ) 88 | .addClass("ui-slider-pips") 89 | .find(".ui-slider-pip") 90 | .remove(); 91 | 92 | // small object with functions for marking pips as selected. 93 | 94 | var selectPip = { 95 | 96 | single: function(value) { 97 | 98 | this.resetClasses(); 99 | 100 | $pips 101 | .filter(".ui-slider-pip-" + this.classLabel(value) ) 102 | .addClass("ui-slider-pip-selected"); 103 | 104 | if ( slider.options.range ) { 105 | 106 | $pips.each(function(k, v) { 107 | 108 | var pipVal = $(v).children(".ui-slider-label").data("value"); 109 | 110 | if (( slider.options.range === "min" && pipVal < value ) || 111 | ( slider.options.range === "max" && pipVal > value )) { 112 | 113 | $(v).addClass("ui-slider-pip-inrange"); 114 | 115 | } 116 | 117 | }); 118 | 119 | } 120 | 121 | }, 122 | 123 | range: function(values) { 124 | 125 | this.resetClasses(); 126 | 127 | for ( i = 0; i < values.length; i++ ) { 128 | 129 | $pips 130 | .filter(".ui-slider-pip-" + this.classLabel(values[i]) ) 131 | .addClass("ui-slider-pip-selected-" + ( i + 1 ) ); 132 | 133 | } 134 | 135 | if ( slider.options.range ) { 136 | 137 | $pips.each(function(k, v) { 138 | 139 | var pipVal = $(v).children(".ui-slider-label").data("value"); 140 | 141 | if ( pipVal > values[0] && pipVal < values[1] ) { 142 | 143 | $(v).addClass("ui-slider-pip-inrange"); 144 | 145 | } 146 | 147 | }); 148 | 149 | } 150 | 151 | }, 152 | 153 | classLabel: function(value) { 154 | 155 | return value.toString().replace(".", "-"); 156 | 157 | }, 158 | 159 | resetClasses: function() { 160 | 161 | var regex = /(^|\s*)(ui-slider-pip-selected|ui-slider-pip-inrange)(-{1,2}\d+|\s|$)/gi; 162 | 163 | $pips.removeClass( function(index, css) { 164 | return ( css.match(regex) || [] ).join(" "); 165 | }); 166 | 167 | } 168 | 169 | }; 170 | 171 | function getClosestHandle( val ) { 172 | 173 | var h, k, 174 | sliderVals, 175 | comparedVals, 176 | closestVal, 177 | tempHandles = [], 178 | closestHandle = 0; 179 | 180 | if ( slider.values() && slider.values().length ) { 181 | 182 | // get the current values of the slider handles 183 | sliderVals = slider.values(); 184 | 185 | // find the offset value from the `val` for each 186 | // handle, and store it in a new array 187 | comparedVals = $.map( sliderVals, function(v) { 188 | return Math.abs( v - val ); 189 | }); 190 | 191 | // figure out the closest handles to the value 192 | closestVal = Math.min.apply( Math, comparedVals ); 193 | 194 | // if a comparedVal is the closestVal, then 195 | // set the value accordingly, and set the closest handle. 196 | for ( h = 0; h < comparedVals.length; h++ ) { 197 | if ( comparedVals[h] === closestVal ) { 198 | tempHandles.push(h); 199 | } 200 | } 201 | 202 | // set the closest handle to the first handle in array, 203 | // just incase we have no _lastChangedValue to compare to. 204 | closestHandle = tempHandles[0]; 205 | 206 | // now we want to find out if any of the closest handles were 207 | // the last changed handle, if so we specify that handle to change 208 | for ( k = 0; k < tempHandles.length; k++ ) { 209 | if ( slider._lastChangedValue === tempHandles[k] ) { 210 | closestHandle = tempHandles[k]; 211 | } 212 | } 213 | 214 | if ( slider.options.range && tempHandles.length === 2 ) { 215 | 216 | if ( val > sliderVals[1] ) { 217 | 218 | closestHandle = tempHandles[1]; 219 | 220 | } else if ( val < sliderVals[0] ) { 221 | 222 | closestHandle = tempHandles[0]; 223 | 224 | } 225 | 226 | } 227 | 228 | } 229 | 230 | return closestHandle; 231 | 232 | } 233 | 234 | function destroy() { 235 | 236 | slider.element 237 | .off(".selectPip") 238 | .on("mousedown.slider", slider.element.data("mousedown-original") ) 239 | .removeClass("ui-slider-pips") 240 | .find(".ui-slider-pip") 241 | .remove(); 242 | 243 | } 244 | 245 | // when we click on a label, we want to make sure the 246 | // slider's handle actually goes to that label! 247 | // so we check all the handles and see which one is closest 248 | // to the label we clicked. If 2 handles are equidistant then 249 | // we move both of them. We also want to trigger focus on the 250 | // handle. 251 | 252 | // without this method the label is just treated like a part 253 | // of the slider and there's no accuracy in the selected value 254 | 255 | function labelClick( label, e ) { 256 | 257 | if (slider.option("disabled")) { 258 | return; 259 | } 260 | 261 | var val = $(label).data("value"), 262 | indexToChange = getClosestHandle( val ); 263 | 264 | if ( slider.values() && slider.values().length ) { 265 | 266 | slider.options.values[ indexToChange ] = slider._trimAlignValue( val ); 267 | 268 | } else { 269 | 270 | slider.options.value = slider._trimAlignValue( val ); 271 | 272 | } 273 | 274 | slider._refreshValue(); 275 | slider._change( e, indexToChange ); 276 | 277 | } 278 | 279 | // method for creating a pip. We loop this for creating all 280 | // the pips. 281 | 282 | function createPip( which ) { 283 | 284 | var label, 285 | percent, 286 | number = which, 287 | classes = "ui-slider-pip", 288 | css = "", 289 | value = slider.value(), 290 | values = slider.values(), 291 | labelValue, 292 | classLabel, 293 | labelIndex; 294 | 295 | if ( which === "first" ) { 296 | 297 | number = 0; 298 | 299 | } else if ( which === "last" ) { 300 | 301 | number = pips; 302 | 303 | } 304 | 305 | // labelValue is the actual value of the pip based on the min/step 306 | labelValue = min + ( slider.options.step * number ); 307 | 308 | // classLabel replaces any decimals with hyphens 309 | classLabel = labelValue.toString().replace(".", "-"); 310 | 311 | // get the index needed for selecting labels out of the array 312 | labelIndex = ( number + min ) - min; 313 | 314 | // we need to set the human-readable label to either the 315 | // corresponding element in the array, or the appropriate 316 | // item in the object... or an empty string. 317 | 318 | if ( $.type(options.labels) === "array" ) { 319 | 320 | label = options.labels[ labelIndex ] || ""; 321 | 322 | } else if ( $.type( options.labels ) === "object" ) { 323 | 324 | if ( which === "first" ) { 325 | 326 | // set first label 327 | label = options.labels.first || ""; 328 | 329 | } else if ( which === "last" ) { 330 | 331 | // set last label 332 | label = options.labels.last || ""; 333 | 334 | } else if ( $.type( options.labels.rest ) === "array" ) { 335 | 336 | // set other labels, but our index should start at -1 337 | // because of the first pip. 338 | label = options.labels.rest[ labelIndex - 1 ] || ""; 339 | 340 | } else { 341 | 342 | // urrggh, the options must be f**ked, just show nothing. 343 | label = labelValue; 344 | 345 | } 346 | 347 | } else { 348 | 349 | label = labelValue; 350 | 351 | } 352 | 353 | 354 | 355 | 356 | if ( which === "first" ) { 357 | 358 | // first Pip on the Slider 359 | percent = "0%"; 360 | 361 | classes += " ui-slider-pip-first"; 362 | classes += ( options.first === "label" ) ? " ui-slider-pip-label" : ""; 363 | classes += ( options.first === false ) ? " ui-slider-pip-hide" : ""; 364 | 365 | } else if ( which === "last" ) { 366 | 367 | // last Pip on the Slider 368 | percent = "100%"; 369 | 370 | classes += " ui-slider-pip-last"; 371 | classes += ( options.last === "label" ) ? " ui-slider-pip-label" : ""; 372 | classes += ( options.last === false ) ? " ui-slider-pip-hide" : ""; 373 | 374 | } else { 375 | 376 | // all other Pips 377 | percent = (( 100 / pips ) * which ).toFixed(4) + "%"; 378 | 379 | classes += ( options.rest === "label" ) ? " ui-slider-pip-label" : ""; 380 | classes += ( options.rest === false ) ? " ui-slider-pip-hide" : ""; 381 | 382 | } 383 | 384 | classes += " ui-slider-pip-" + classLabel; 385 | 386 | 387 | // add classes for the initial-selected values. 388 | if ( values && values.length ) { 389 | 390 | for ( i = 0; i < values.length; i++ ) { 391 | 392 | if ( labelValue === values[i] ) { 393 | 394 | classes += " ui-slider-pip-initial-" + ( i + 1 ); 395 | classes += " ui-slider-pip-selected-" + ( i + 1 ); 396 | 397 | } 398 | 399 | } 400 | 401 | if ( slider.options.range ) { 402 | 403 | if ( labelValue > values[0] && 404 | labelValue < values[1] ) { 405 | 406 | classes += " ui-slider-pip-inrange"; 407 | 408 | } 409 | 410 | } 411 | 412 | } else { 413 | 414 | if ( labelValue === value ) { 415 | 416 | classes += " ui-slider-pip-initial"; 417 | classes += " ui-slider-pip-selected"; 418 | 419 | } 420 | 421 | if ( slider.options.range ) { 422 | 423 | if (( slider.options.range === "min" && labelValue < value ) || 424 | ( slider.options.range === "max" && labelValue > value )) { 425 | 426 | classes += " ui-slider-pip-inrange"; 427 | 428 | } 429 | 430 | } 431 | 432 | } 433 | 434 | 435 | 436 | css = ( slider.options.orientation === "horizontal" ) ? 437 | "left: " + percent : 438 | "bottom: " + percent; 439 | 440 | 441 | // add this current pip to the collection 442 | return "" + 443 | "" + 444 | "" + options.formatLabel(label) + "" + 446 | ""; 447 | 448 | } 449 | 450 | // create our first pip 451 | collection += createPip("first"); 452 | 453 | // for every stop in the slider where we need a pip; create one. 454 | for ( p = slider.options.pipStep; p < pips; p += slider.options.pipStep ) { 455 | collection += createPip( p ); 456 | } 457 | 458 | // create our last pip 459 | collection += createPip("last"); 460 | 461 | // append the collection of pips. 462 | slider.element.append( collection ); 463 | 464 | // store the pips for setting classes later. 465 | $pips = slider.element.find(".ui-slider-pip"); 466 | 467 | 468 | 469 | // store the mousedown handlers for later, just in case we reset 470 | // the slider, the handler would be lost! 471 | 472 | if ( $._data( slider.element.get(0), "events").mousedown && 473 | $._data( slider.element.get(0), "events").mousedown.length ) { 474 | 475 | mousedownHandlers = $._data( slider.element.get(0), "events").mousedown; 476 | 477 | } else { 478 | 479 | mousedownHandlers = slider.element.data("mousedown-handlers"); 480 | 481 | } 482 | 483 | slider.element.data("mousedown-handlers", mousedownHandlers.slice() ); 484 | 485 | // loop through all the mousedown handlers on the slider, 486 | // and store the original namespaced (.slider) event handler so 487 | // we can trigger it later. 488 | for ( j = 0; j < mousedownHandlers.length; j++ ) { 489 | if ( mousedownHandlers[j].namespace === "slider" ) { 490 | slider.element.data("mousedown-original", mousedownHandlers[j].handler ); 491 | } 492 | } 493 | 494 | // unbind the mousedown.slider event, because it interferes with 495 | // the labelClick() method (stops smooth animation), and decide 496 | // if we want to trigger the original event based on which element 497 | // was clicked. 498 | slider.element 499 | .off("mousedown.slider") 500 | .on("mousedown.selectPip", function(e) { 501 | 502 | var $target = $(e.target), 503 | closest = getClosestHandle( $target.data("value") ), 504 | $handle = $handles.eq( closest ); 505 | 506 | $handle.addClass("ui-state-active"); 507 | 508 | if ( $target.is(".ui-slider-label") ) { 509 | 510 | labelClick( $target, e ); 511 | 512 | slider.element 513 | .one("mouseup.selectPip", function() { 514 | 515 | $handle 516 | .removeClass("ui-state-active") 517 | .focus(); 518 | 519 | }); 520 | 521 | } else { 522 | 523 | var originalMousedown = slider.element.data("mousedown-original"); 524 | originalMousedown(e); 525 | 526 | } 527 | 528 | }); 529 | 530 | 531 | 532 | 533 | slider.element.on( "slide.selectPip slidechange.selectPip", function(e, ui) { 534 | 535 | var $slider = $(this), 536 | value = $slider.slider("value"), 537 | values = $slider.slider("values"); 538 | 539 | if ( ui ) { 540 | 541 | value = ui.value; 542 | values = ui.values; 543 | 544 | } 545 | 546 | if ( slider.values() && slider.values().length ) { 547 | 548 | selectPip.range( values ); 549 | 550 | } else { 551 | 552 | selectPip.single( value ); 553 | 554 | } 555 | 556 | }); 557 | 558 | 559 | 560 | 561 | }, 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | // floats 571 | 572 | float: function( settings ) { 573 | 574 | var i, 575 | slider = this, 576 | min = slider._valueMin(), 577 | max = slider._valueMax(), 578 | value = slider._value(), 579 | values = slider._values(), 580 | tipValues = [], 581 | $handles = slider.element.find(".ui-slider-handle"); 582 | 583 | var options = { 584 | 585 | handle: true, 586 | /* false */ 587 | 588 | pips: false, 589 | /* true */ 590 | 591 | labels: false, 592 | /* [array], { first: "string", rest: [array], last: "string" }, false */ 593 | 594 | prefix: "", 595 | /* "", string */ 596 | 597 | suffix: "", 598 | /* "", string */ 599 | 600 | event: "slidechange slide", 601 | /* "slidechange", "slide", "slidechange slide" */ 602 | 603 | formatLabel: function(value) { 604 | return this.prefix + value + this.suffix; 605 | } 606 | /* function 607 | must return a value to display in the floats */ 608 | 609 | }; 610 | 611 | if ( $.type( settings ) === "object" || $.type( settings ) === "undefined" ) { 612 | 613 | $.extend( options, settings ); 614 | slider.element.data("float-options", options ); 615 | 616 | } else { 617 | 618 | if ( settings === "destroy" ) { 619 | 620 | destroy(); 621 | 622 | } else if ( settings === "refresh" ) { 623 | 624 | slider.element.slider( "float", slider.element.data("float-options") ); 625 | 626 | } 627 | 628 | return; 629 | 630 | } 631 | 632 | 633 | 634 | 635 | if ( value < min ) { 636 | value = min; 637 | } 638 | 639 | if ( value > max ) { 640 | value = max; 641 | } 642 | 643 | if ( values && values.length ) { 644 | 645 | for ( i = 0; i < values.length; i++ ) { 646 | 647 | if ( values[i] < min ) { 648 | values[i] = min; 649 | } 650 | 651 | if ( values[i] > max ) { 652 | values[i] = max; 653 | } 654 | 655 | } 656 | 657 | } 658 | 659 | // add a class for the CSS 660 | slider.element 661 | .addClass("ui-slider-float") 662 | .find(".ui-slider-tip, .ui-slider-tip-label") 663 | .remove(); 664 | 665 | 666 | 667 | function destroy() { 668 | 669 | slider.element 670 | .off(".sliderFloat") 671 | .removeClass("ui-slider-float") 672 | .find(".ui-slider-tip, .ui-slider-tip-label") 673 | .remove(); 674 | 675 | } 676 | 677 | 678 | function getPipLabels( values ) { 679 | 680 | // when checking the array we need to divide 681 | // by the step option, so we store those values here. 682 | 683 | var vals = [], 684 | steppedVals = $.map( values, function(v) { 685 | return Math.ceil(( v - min ) / slider.options.step); 686 | }); 687 | 688 | // now we just get the values we need to return 689 | // by looping through the values array and assigning the 690 | // label if it exists. 691 | 692 | if ( $.type( options.labels ) === "array" ) { 693 | 694 | for ( i = 0; i < values.length; i++ ) { 695 | 696 | vals[i] = options.labels[ steppedVals[i] ] || values[i]; 697 | 698 | } 699 | 700 | } else if ( $.type( options.labels ) === "object" ) { 701 | 702 | for ( i = 0; i < values.length; i++ ) { 703 | 704 | if ( values[i] === min ) { 705 | 706 | vals[i] = options.labels.first || min; 707 | 708 | } else if ( values[i] === max ) { 709 | 710 | vals[i] = options.labels.last || max; 711 | 712 | } else if ( $.type( options.labels.rest ) === "array" ) { 713 | 714 | vals[i] = options.labels.rest[ steppedVals[i] - 1 ] || values[i]; 715 | 716 | } else { 717 | 718 | vals[i] = values[i]; 719 | 720 | } 721 | 722 | } 723 | 724 | } else { 725 | 726 | for ( i = 0; i < values.length; i++ ) { 727 | 728 | vals[i] = values[i]; 729 | 730 | } 731 | 732 | } 733 | 734 | return vals; 735 | 736 | } 737 | 738 | // apply handle tip if settings allows. 739 | if ( options.handle ) { 740 | 741 | // we need to set the human-readable label to either the 742 | // corresponding element in the array, or the appropriate 743 | // item in the object... or an empty string. 744 | 745 | tipValues = ( slider.values() && slider.values().length ) ? 746 | getPipLabels( values ) : 747 | getPipLabels( [ value ] ); 748 | 749 | for ( i = 0; i < tipValues.length; i++ ) { 750 | 751 | $handles 752 | .eq( i ) 753 | .append( $(""+ options.formatLabel(tipValues[i]) +"") ); 754 | 755 | } 756 | 757 | } 758 | 759 | if ( options.pips ) { 760 | 761 | // if this slider also has pip-labels, we make those into tips, too. 762 | slider.element.find(".ui-slider-label").each(function(k, v) { 763 | 764 | var $this = $(v), 765 | val = [ $this.data("value") ], 766 | label, 767 | $tip; 768 | 769 | 770 | label = options.formatLabel( getPipLabels( val )[0] ); 771 | 772 | // create a tip element 773 | $tip = 774 | $("" + label + "") 775 | .insertAfter( $this ); 776 | 777 | }); 778 | 779 | } 780 | 781 | // check that the event option is actually valid against our 782 | // own list of the slider's events. 783 | if ( options.event !== "slide" && 784 | options.event !== "slidechange" && 785 | options.event !== "slide slidechange" && 786 | options.event !== "slidechange slide" ) { 787 | 788 | options.event = "slidechange slide"; 789 | 790 | } 791 | 792 | // when slider changes, update handle tip label. 793 | slider.element 794 | .off(".sliderFloat") 795 | .on( options.event + ".sliderFloat", function( e, ui ) { 796 | 797 | var uiValue = ( $.type( ui.value ) === "array" ) ? ui.value : [ ui.value ], 798 | val = options.formatLabel( getPipLabels( uiValue )[0] ); 799 | 800 | $(ui.handle) 801 | .find(".ui-slider-tip") 802 | .html( val ); 803 | 804 | }); 805 | 806 | } 807 | 808 | }; 809 | 810 | $.extend(true, $.ui.slider.prototype, extensionMethods); 811 | 812 | })(jQuery); 813 | -------------------------------------------------------------------------------- /dist/jquery-ui-slider-pips.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery-ui-Slider-Pips - v1.11.4 - 2016-09-04 2 | * Copyright (c) 2016 Simon Goellner ; Licensed MIT */ 3 | 4 | .ui-slider-horizontal.ui-slider-pips{margin-bottom:1.4em}.ui-slider-pips .ui-slider-label,.ui-slider-pips .ui-slider-pip-hide{display:none}.ui-slider-pips .ui-slider-pip-label .ui-slider-label{display:block}.ui-slider-pips .ui-slider-pip{width:2em;height:1em;line-height:1em;position:absolute;font-size:0.8em;color:#999;overflow:visible;text-align:center;top:20px;left:20px;margin-left:-1em;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ui-state-disabled.ui-slider-pips .ui-slider-pip{cursor:default}.ui-slider-pips .ui-slider-line{background:#999;width:1px;height:3px;position:absolute;left:50%}.ui-slider-pips .ui-slider-label{position:absolute;top:5px;left:50%;margin-left:-1em;width:2em}.ui-slider-pips:not(.ui-slider-disabled) .ui-slider-pip:hover .ui-slider-label{color:black;font-weight:bold}.ui-slider-vertical.ui-slider-pips{margin-bottom:1em;margin-right:2em}.ui-slider-vertical.ui-slider-pips .ui-slider-pip{text-align:left;top:auto;left:20px;margin-left:0;margin-bottom:-0.5em}.ui-slider-vertical.ui-slider-pips .ui-slider-line{width:3px;height:1px;position:absolute;top:50%;left:0}.ui-slider-vertical.ui-slider-pips .ui-slider-label{top:50%;left:0.5em;margin-left:0;margin-top:-0.5em;width:2em}.ui-slider-float .ui-slider-handle:focus,.ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip-label,.ui-slider-float .ui-slider-handle:focus .ui-slider-tip,.ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip-label,.ui-slider-float .ui-slider-handle:focus .ui-slider-tip-label .ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip-label{outline:none}.ui-slider-float .ui-slider-tip,.ui-slider-float .ui-slider-tip-label{position:absolute;visibility:hidden;top:-40px;display:block;width:34px;margin-left:-18px;left:50%;height:20px;line-height:20px;background:white;border-radius:3px;border:1px solid #888;text-align:center;font-size:12px;opacity:0;color:#333;-webkit-transition-property:opacity, top, visibility;transition-property:opacity, top, visibility;-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;-webkit-transition-duration:200ms, 200ms, 0ms;transition-duration:200ms, 200ms, 0ms;-webkit-transition-delay:0ms, 0ms, 200ms;transition-delay:0ms, 0ms, 200ms}.ui-slider-float .ui-slider-handle:hover .ui-slider-tip,.ui-slider-float .ui-slider-handle.ui-state-hover .ui-slider-tip,.ui-slider-float .ui-slider-handle:focus .ui-slider-tip,.ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip,.ui-slider-float .ui-slider-handle.ui-state-active .ui-slider-tip,.ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label{opacity:1;top:-30px;visibility:visible;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out;-webkit-transition-delay:200ms, 200ms, 0ms;transition-delay:200ms, 200ms, 0ms}.ui-slider-float .ui-slider-pip .ui-slider-tip-label{top:42px}.ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label{top:32px;font-weight:normal}.ui-slider-float .ui-slider-tip:after,.ui-slider-float .ui-slider-pip .ui-slider-tip-label:after{content:" ";width:0;height:0;border:5px solid rgba(255,255,255,0);border-top-color:#fff;position:absolute;bottom:-10px;left:50%;margin-left:-5px}.ui-slider-float .ui-slider-tip:before,.ui-slider-float .ui-slider-pip .ui-slider-tip-label:before{content:" ";width:0;height:0;border:5px solid rgba(255,255,255,0);border-top-color:#888;position:absolute;bottom:-11px;left:50%;margin-left:-5px}.ui-slider-float .ui-slider-pip .ui-slider-tip-label:after{border:5px solid rgba(255,255,255,0);border-bottom-color:#fff;top:-10px}.ui-slider-float .ui-slider-pip .ui-slider-tip-label:before{border:5px solid rgba(255,255,255,0);border-bottom-color:#888;top:-11px}.ui-slider-vertical.ui-slider-float .ui-slider-tip,.ui-slider-vertical.ui-slider-float .ui-slider-tip-label{top:50%;margin-top:-11px;width:34px;margin-left:0px;left:-60px;color:#333;-webkit-transition-duration:200ms, 200ms, 0;transition-duration:200ms, 200ms, 0;-webkit-transition-property:opacity, left, visibility;transition-property:opacity, left, visibility;-webkit-transition-delay:0, 0, 200ms;transition-delay:0, 0, 200ms}.ui-slider-vertical.ui-slider-float .ui-slider-handle:hover .ui-slider-tip,.ui-slider-vertical.ui-slider-float .ui-slider-handle.ui-state-hover .ui-slider-tip,.ui-slider-vertical.ui-slider-float .ui-slider-handle:focus .ui-slider-tip,.ui-slider-vertical.ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip,.ui-slider-vertical.ui-slider-float .ui-slider-handle.ui-state-active .ui-slider-tip,.ui-slider-vertical.ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label{top:50%;margin-top:-11px;left:-50px}.ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label{left:47px}.ui-slider-vertical.ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label{left:37px}.ui-slider-vertical.ui-slider-float .ui-slider-tip:after,.ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:after{border:5px solid rgba(255,255,255,0);border-left-color:#fff;border-top-color:transparent;position:absolute;bottom:50%;margin-bottom:-5px;right:-10px;margin-left:0;top:auto;left:auto}.ui-slider-vertical.ui-slider-float .ui-slider-tip:before,.ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:before{border:5px solid rgba(255,255,255,0);border-left-color:#888;border-top-color:transparent;position:absolute;bottom:50%;margin-bottom:-5px;right:-11px;margin-left:0;top:auto;left:auto}.ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:after{border:5px solid rgba(255,255,255,0);border-right-color:#fff;right:auto;left:-10px}.ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:before{border:5px solid rgba(255,255,255,0);border-right-color:#888;right:auto;left:-11px}.ui-slider-pips [class*=ui-slider-pip-initial]{font-weight:bold;color:#14CA82}.ui-slider-pips .ui-slider-pip-initial-2{color:#1897C9}.ui-slider-pips [class*=ui-slider-pip-selected]{font-weight:bold;color:#FF7A00}.ui-slider-pips .ui-slider-pip-inrange{color:black}.ui-slider-pips .ui-slider-pip-selected-2{color:#E70081}.ui-slider-pips [class*=ui-slider-pip-selected] .ui-slider-line,.ui-slider-pips .ui-slider-pip-inrange .ui-slider-line{background:black} 5 | -------------------------------------------------------------------------------- /dist/jquery-ui-slider-pips.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery-ui-Slider-Pips - v1.11.4 - 2016-09-04 2 | * Copyright (c) 2016 Simon Goellner ; Licensed MIT */ 3 | 4 | !function(e){"use strict";var i={pips:function(i){function l(i){var l,s,t,a,n,r=[],o=0;if(u.values()&&u.values().length){for(t=u.values(),a=e.map(t,function(e){return Math.abs(e-i)}),n=Math.min.apply(Math,a),l=0;lt[1]?o=r[1]:iv[0]&&tt||"max"===u.options.range&&t>f)&&(p+=" ui-slider-pip-inrange");return d="horizontal"===u.options.orientation?"left: "+s:"bottom: "+s,''+g.formatLabel(l)+""}var n,r,o,p,d,u=this,f="",c=u._valueMin(),v=u._valueMax(),h=(v-c)/u.options.step,m=u.element.find(".ui-slider-handle"),g={first:"label",last:"label",rest:"pip",labels:!1,prefix:"",suffix:"",step:h>100?Math.floor(.05*h):1,formatLabel:function(e){return this.prefix+e+this.suffix}};if("object"!==e.type(i)&&"undefined"!==e.type(i))return void("destroy"===i?s():"refresh"===i&&u.element.slider("pips",u.element.data("pips-options")));e.extend(g,i),u.element.data("pips-options",g),u.options.pipStep=Math.abs(Math.round(g.step))||1,u.element.off(".selectPip").addClass("ui-slider-pips").find(".ui-slider-pip").remove();var b={single:function(i){this.resetClasses(),d.filter(".ui-slider-pip-"+this.classLabel(i)).addClass("ui-slider-pip-selected"),u.options.range&&d.each(function(l,s){var t=e(s).children(".ui-slider-label").data("value");("min"===u.options.range&&i>t||"max"===u.options.range&&t>i)&&e(s).addClass("ui-slider-pip-inrange")})},range:function(i){for(this.resetClasses(),n=0;ni[0]&&to;o+=u.options.pipStep)f+=a(o);for(f+=a("last"),u.element.append(f),d=u.element.find(".ui-slider-pip"),p=e._data(u.element.get(0),"events").mousedown&&e._data(u.element.get(0),"events").mousedown.length?e._data(u.element.get(0),"events").mousedown:u.element.data("mousedown-handlers"),u.element.data("mousedown-handlers",p.slice()),r=0;ro&&(o=n),o>r&&(o=r),p&&p.length)for(t=0;tr&&(p[t]=r);if(a.element.addClass("ui-slider-float").find(".ui-slider-tip, .ui-slider-tip-label").remove(),f.handle)for(d=s(a.values()&&a.values().length?p:[o]),t=0;t'+f.formatLabel(d[t])+""));f.pips&&a.element.find(".ui-slider-label").each(function(i,l){var t,a,n=e(l),r=[n.data("value")];t=f.formatLabel(s(r)[0]),a=e(''+t+"").insertAfter(n)}),"slide"!==f.event&&"slidechange"!==f.event&&"slide slidechange"!==f.event&&"slidechange slide"!==f.event&&(f.event="slidechange slide"),a.element.off(".sliderFloat").on(f.event+".sliderFloat",function(i,l){var t="array"===e.type(l.value)?l.value:[l.value],a=f.formatLabel(s(t)[0]);e(l.handle).find(".ui-slider-tip").html(a)})}};e.extend(!0,e.ui.slider.prototype,i)}(jQuery); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | 4 | var gulp = require("gulp-param")( require("gulp"), process.argv ), 5 | 6 | fs = require("fs"), 7 | semver = require("semver"), 8 | dateformat = require("dateformat"), 9 | 10 | git = require("gulp-git"), 11 | sass = require("gulp-sass"), 12 | bump = require("gulp-bump"), 13 | clean = require("gulp-clean"), 14 | uglify = require("gulp-uglify"), 15 | rename = require("gulp-rename"), 16 | header = require("gulp-header"), 17 | autoprefixer = require("gulp-autoprefixer"), 18 | 19 | pack = function() { 20 | 21 | return JSON.parse(fs.readFileSync("./package.json", "utf8")); 22 | 23 | }, 24 | 25 | pkg = pack(), 26 | 27 | dates = { 28 | 29 | today: dateformat( new Date() , "yyyy-mm-dd" ), 30 | year: dateformat( new Date() , "yyyy" ) 31 | 32 | }, 33 | 34 | banner = "/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - <%= dates.today %>\n" + 35 | "<%= pkg.homepage ? \"* \" + pkg.homepage + \"\\n\" : \"\" %>" + 36 | "* Copyright (c) <%= dates.year %> <%= pkg.author %>;" + 37 | " Licensed <%= pkg.license %> */\n\n", 38 | 39 | out = { 40 | 41 | js: "jquery-ui-slider-pips", 42 | css: "jquery-ui-slider-pips" 43 | 44 | }; 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | /** 56 | * tasks 57 | * 58 | * to release; tasks should be run in the order: 59 | * "gulp bump" -> "gulp assets" -> "gulp release" 60 | * 61 | * for dev; just run 62 | * "gulp" 63 | */ 64 | 65 | gulp.task("default", ["assets"], function() { 66 | 67 | return gulp; 68 | 69 | }); 70 | 71 | gulp.task("assets", ["clean", "js", "sass"], function() { 72 | 73 | console.log("⭐ >> Finished putting assets to /dist/" ); 74 | 75 | return gulp; 76 | 77 | }); 78 | 79 | /** 80 | * clean the dist folder (empty it) 81 | */ 82 | 83 | gulp.task("clean", function() { 84 | 85 | console.log("⭐ >> All clean and shiny! "); 86 | 87 | return gulp 88 | .src("./dist", { read: false }) 89 | .pipe( clean() ); 90 | 91 | }); 92 | 93 | 94 | /** 95 | * js task is used to clean the dist folder and output 96 | * the minified and non-minified files. 97 | */ 98 | 99 | gulp.task("js", ["clean"], function() { 100 | 101 | var pkg = pack(); 102 | 103 | return gulp 104 | .src( "./src/js/**/*.js" ) 105 | 106 | .pipe( header( banner, { pkg: pkg, dates: dates } )) 107 | .pipe( rename( out.js + ".js" ) ) 108 | .pipe( gulp.dest( "./dist" ) ) 109 | 110 | .pipe( uglify("combined.js") ) 111 | .pipe( header( banner, { pkg: pkg, dates: dates } )) 112 | .pipe( rename( out.js + ".min.js" ) ) 113 | .pipe( gulp.dest( "./dist" ) ); 114 | 115 | }); 116 | 117 | 118 | /** 119 | * sass task is used to clean the dist folder and output 120 | * the minified and non-minified files. 121 | */ 122 | 123 | gulp.task("sass", ["clean"], function() { 124 | 125 | var pkg = pack(); 126 | 127 | gulp 128 | .src("./src/**/*.scss") 129 | .pipe( sass({ outputStyle: "expanded" }).on("error", sass.logError ) ) 130 | .pipe( autoprefixer("last 5 versions") ) 131 | .pipe( header( banner, { pkg: pkg, dates: dates } )) 132 | .pipe( rename( out.css + ".css" )) 133 | .pipe( gulp.dest("./dist") ); 134 | 135 | return gulp 136 | .src("./src/**/*.scss") 137 | .pipe( sass({ outputStyle: "compressed" }).on("error", sass.logError ) ) 138 | .pipe( autoprefixer("last 5 versions") ) 139 | .pipe( header( banner, { pkg: pkg, dates: dates } )) 140 | .pipe( rename( out.css + ".min.css" )) 141 | .pipe( gulp.dest("./dist") ); 142 | 143 | }); 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | /** 152 | * bump task can be used like: 153 | * 154 | * gulp bump --patch 155 | * gulp bump --minor 156 | * gulp bump --major 157 | * 158 | * this task will ONLY bump the version, it will not 159 | * release a tag, commit the code or update the assets. 160 | */ 161 | 162 | gulp.task("bump", function( patch, minor, major ) { 163 | 164 | var b = 165 | (patch) ? "patch" : 166 | (minor) ? "minor" : 167 | (major) ? "major" : 168 | null; 169 | 170 | if( b ) { 171 | 172 | var pkg = pack(), 173 | oldv = pkg.version, 174 | newv = semver.inc( oldv , b ); 175 | 176 | console.log("⭐ >> Bumping Version to v" + newv ); 177 | 178 | return gulp 179 | .src("./*.json") 180 | .pipe( bump({ version: newv }) ) 181 | .pipe( gulp.dest("./") ); 182 | 183 | } else { 184 | 185 | throw new Error("\n⚠ >> Not Bumping; didn't supply bump type\n\n"); 186 | 187 | return false; 188 | 189 | } 190 | 191 | }); 192 | 193 | 194 | 195 | 196 | /** 197 | * release task should be used after "bump" and "assets" was run. 198 | * this task will create a commit, and tag it with the version in package.json 199 | */ 200 | 201 | gulp.task("release", ["commit", "tag"], function() { 202 | return gulp; 203 | }); 204 | 205 | 206 | /** 207 | * commit task is used for creating a cute release icon, and committing dist files 208 | * to the GIT repository; all src files should already be committed. 209 | */ 210 | 211 | gulp.task("commit", function() { 212 | 213 | var pkg = pack(), 214 | newv = pkg.version, 215 | 216 | fun = "🐒 🐔 🐧 🐤 🐗 🐝 🐌 🐞 🐜 🕷 🦂 🦀 🐍 🐢 🐟 🐡 🐬 🐋 🐊 🐆 🐅 🐃 🐂 🐄 🐪 🐘 🐐 🐏 🐑 🐎 🐖 🐀 🐁 🐓 🦃 🕊 🐕 🐈 🐇 🐿 🐉 🐲".split(" "); 217 | fun = fun[ Math.floor(Math.random() * fun.length ) ]; 218 | 219 | console.log("⭐ >> Committing release v" + newv ); 220 | 221 | return gulp 222 | .src([ 223 | "./*.json", 224 | "./dist/**/*" 225 | ]) 226 | .pipe( git.add() ) 227 | .pipe( git.commit("Release v" + newv + " ⚡" + fun + "⚡") ); 228 | 229 | }); 230 | 231 | /** 232 | * tag task should just tag the last commit in repository 233 | * with the latest version information from package.json. 234 | */ 235 | 236 | gulp.task("tag", ["commit"], function() { 237 | 238 | var pkg = pack(), 239 | newv = pkg.version; 240 | 241 | console.log("⭐ >> Creating new tag for v" + newv ); 242 | 243 | git.tag("v" + newv, "Version " + newv, function(err) { 244 | if ( err ) { throw err; } 245 | }); 246 | 247 | return gulp; 248 | 249 | }); 250 | 251 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jQuery-ui-Slider-Pips", 3 | "version": "1.11.4", 4 | "description": "A plugin to add little \"pips\" to the jQuery UI Slider widget", 5 | "main": "dist/jquery-ui-slider-pips.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/simeydotme/jQuery-ui-Slider-Pips.git" 9 | }, 10 | "license": "MIT", 11 | "keywords": [ 12 | "jquery", 13 | "ui", 14 | "slider", 15 | "widget", 16 | "pips", 17 | "points", 18 | "labels", 19 | "floats", 20 | "markers", 21 | "waypoints" 22 | ], 23 | "author": "Simon Goellner ", 24 | "bugs": { 25 | "url": "https://github.com/simeydotme/jQuery-ui-Slider-Pips/issues" 26 | }, 27 | "scripts": { 28 | "test": "echo \"Error: no test specified\" && exit 1" 29 | }, 30 | "devDependencies": { 31 | "dateformat": "^1.0.12", 32 | "semver": "^5.1.0", 33 | "fs": "0.0.2", 34 | "gulp": "^3.9.0", 35 | "gulp-autoprefixer": "^3.1.0", 36 | "gulp-clean": "^0.3.1", 37 | "gulp-header": "^1.7.1", 38 | "gulp-rename": "^1.2.2", 39 | "gulp-sass": "^2.1.0", 40 | "gulp-uglify": "^1.5.1", 41 | "gulp-bump": "^1.0.0", 42 | "gulp-git": "^1.6.0", 43 | "gulp-param": "^0.6.4" 44 | }, 45 | "dependencies": { 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/css/jquery-ui-slider-pips.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /* HORIZONTAL */ 5 | 6 | /* increase bottom margin to fit the pips */ 7 | .ui-slider-horizontal.ui-slider-pips { 8 | margin-bottom: 1.4em; 9 | } 10 | 11 | /* default hide the labels and pips that arnt visible */ 12 | /* we just use css to hide incase we want to show certain */ 13 | /* labels/pips individually later */ 14 | .ui-slider-pips .ui-slider-label, 15 | .ui-slider-pips .ui-slider-pip-hide { 16 | display: none; 17 | } 18 | 19 | /* now we show any labels that we've set to show in the options */ 20 | .ui-slider-pips .ui-slider-pip-label .ui-slider-label { 21 | display: block; 22 | } 23 | 24 | /* PIP/LABEL WRAPPER */ 25 | /* position each pip absolutely just below the default slider */ 26 | /* and also prevent accidental selection */ 27 | .ui-slider-pips .ui-slider-pip { 28 | width: 2em; 29 | height: 1em; 30 | line-height: 1em; 31 | position: absolute; 32 | font-size: 0.8em; 33 | color: #999; 34 | overflow: visible; 35 | text-align: center; 36 | top: 20px; 37 | left: 20px; 38 | margin-left: -1em; 39 | cursor: pointer; 40 | 41 | -webkit-touch-callout: none; 42 | -webkit-user-select: none; 43 | -khtml-user-select: none; 44 | -moz-user-select: none; 45 | -ms-user-select: none; 46 | user-select: none; 47 | } 48 | .ui-state-disabled.ui-slider-pips .ui-slider-pip { 49 | cursor: default; 50 | } 51 | 52 | /* little pip/line position & size */ 53 | .ui-slider-pips .ui-slider-line { 54 | background: #999; 55 | width: 1px; 56 | height: 3px; 57 | position: absolute; 58 | left: 50%; 59 | } 60 | 61 | /* the text label postion & size */ 62 | /* it overflows so no need for width to be accurate */ 63 | .ui-slider-pips .ui-slider-label { 64 | position: absolute; 65 | top: 5px; 66 | left: 50%; 67 | margin-left: -1em; 68 | width: 2em; 69 | } 70 | 71 | /* make it easy to see when we hover a label */ 72 | .ui-slider-pips:not(.ui-slider-disabled) .ui-slider-pip:hover .ui-slider-label { 73 | color: black; 74 | font-weight: bold; 75 | } 76 | 77 | 78 | 79 | 80 | /* VERTICAL */ 81 | 82 | /* vertical slider needs right-margin, not bottom */ 83 | .ui-slider-vertical.ui-slider-pips { 84 | margin-bottom: 1em; 85 | margin-right: 2em; 86 | } 87 | 88 | /* align vertical pips left and to right of the slider */ 89 | .ui-slider-vertical.ui-slider-pips .ui-slider-pip { 90 | text-align: left; 91 | top: auto; 92 | left: 20px; 93 | margin-left: 0; 94 | margin-bottom: -0.5em; 95 | } 96 | 97 | /* vertical line/pip should be horizontal instead */ 98 | .ui-slider-vertical.ui-slider-pips .ui-slider-line { 99 | width: 3px; 100 | height: 1px; 101 | position: absolute; 102 | top: 50%; 103 | left: 0; 104 | } 105 | 106 | .ui-slider-vertical.ui-slider-pips .ui-slider-label { 107 | top: 50%; 108 | left: 0.5em; 109 | margin-left: 0; 110 | margin-top: -0.5em; 111 | width: 2em; 112 | } 113 | 114 | 115 | 116 | 117 | /* FLOATING HORIZTONAL TOOLTIPS */ 118 | 119 | /* remove the godawful looking focus outline on handle and float */ 120 | .ui-slider-float .ui-slider-handle:focus, 121 | .ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip-label, 122 | .ui-slider-float .ui-slider-handle:focus .ui-slider-tip, 123 | .ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip-label, 124 | .ui-slider-float .ui-slider-handle:focus .ui-slider-tip-label 125 | .ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip-label { 126 | outline: none; 127 | } 128 | 129 | /* style tooltips on handles and on labels */ 130 | /* also has a nice transition */ 131 | .ui-slider-float .ui-slider-tip, 132 | .ui-slider-float .ui-slider-tip-label { 133 | 134 | position: absolute; 135 | visibility: hidden; 136 | top: -40px; 137 | display: block; 138 | width: 34px; 139 | margin-left: -18px; 140 | left: 50%; 141 | height: 20px; 142 | line-height: 20px; 143 | background: white; 144 | border-radius: 3px; 145 | border: 1px solid #888; 146 | text-align: center; 147 | font-size: 12px; 148 | opacity: 0; 149 | color: #333; 150 | 151 | -webkit-transition-property: opacity, top, visibility; 152 | -moz-transition-property: opacity, top, visibility; 153 | -ms-transition-property: opacity, top, visibility; 154 | transition-property: opacity, top, visibility; 155 | 156 | -webkit-transition-timing-function: ease-in; 157 | -moz-transition-timing-function: ease-in; 158 | -ms-transition-timing-function: ease-in; 159 | transition-timing-function: ease-in; 160 | 161 | -webkit-transition-duration: 200ms, 200ms, 0ms; 162 | -moz-transition-duration: 200ms, 200ms, 0ms; 163 | -ms-transition-duration: 200ms, 200ms, 0ms; 164 | transition-duration: 200ms, 200ms, 0ms; 165 | 166 | -webkit-transition-delay: 0ms, 0ms, 200ms; 167 | -moz-transition-delay: 0ms, 0ms, 200ms; 168 | -ms-transition-delay: 0ms, 0ms, 200ms; 169 | transition-delay: 0ms, 0ms, 200ms; 170 | } 171 | 172 | /* show the tooltip on hover or focus */ 173 | /* also switch transition delay around */ 174 | .ui-slider-float .ui-slider-handle:hover .ui-slider-tip, 175 | .ui-slider-float .ui-slider-handle.ui-state-hover .ui-slider-tip, 176 | .ui-slider-float .ui-slider-handle:focus .ui-slider-tip, 177 | .ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip, 178 | .ui-slider-float .ui-slider-handle.ui-state-active .ui-slider-tip, 179 | .ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label { 180 | 181 | opacity: 1; 182 | top: -30px; 183 | visibility: visible; 184 | 185 | -webkit-transition-timing-function: ease-out; 186 | -moz-transition-timing-function: ease-out; 187 | -ms-transition-timing-function: ease-out; 188 | transition-timing-function: ease-out; 189 | 190 | -webkit-transition-delay:200ms, 200ms, 0ms; 191 | -moz-transition-delay:200ms, 200ms, 0ms; 192 | -ms-transition-delay:200ms, 200ms, 0ms; 193 | transition-delay:200ms, 200ms, 0ms; 194 | 195 | } 196 | 197 | /* put label tooltips below slider */ 198 | .ui-slider-float .ui-slider-pip .ui-slider-tip-label { 199 | top: 42px; 200 | } 201 | 202 | .ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label { 203 | top: 32px; 204 | font-weight: normal; 205 | } 206 | 207 | /* give the tooltip a css triangle arrow */ 208 | .ui-slider-float .ui-slider-tip:after, 209 | .ui-slider-float .ui-slider-pip .ui-slider-tip-label:after { 210 | content: " "; 211 | width: 0; 212 | height: 0; 213 | border: 5px solid rgba(255,255,255,0); 214 | border-top-color: rgba(255,255,255,1); 215 | position: absolute; 216 | bottom: -10px; 217 | left: 50%; 218 | margin-left: -5px; 219 | } 220 | 221 | /* put a 1px border on the tooltip arrow to match tooltip border */ 222 | .ui-slider-float .ui-slider-tip:before, 223 | .ui-slider-float .ui-slider-pip .ui-slider-tip-label:before { 224 | content: " "; 225 | width: 0; 226 | height: 0; 227 | border: 5px solid rgba(255,255,255,0); 228 | border-top-color: #888; 229 | position: absolute; 230 | bottom: -11px; 231 | left: 50%; 232 | margin-left: -5px; 233 | } 234 | 235 | /* switch the arrow to top on labels */ 236 | .ui-slider-float .ui-slider-pip .ui-slider-tip-label:after { 237 | border: 5px solid rgba(255,255,255,0); 238 | border-bottom-color: rgba(255,255,255,1); 239 | top: -10px; 240 | } 241 | 242 | .ui-slider-float .ui-slider-pip .ui-slider-tip-label:before { 243 | border: 5px solid rgba(255,255,255,0); 244 | border-bottom-color: #888; 245 | top: -11px; 246 | } 247 | 248 | 249 | 250 | 251 | /* FLOATING VERTICAL TOOLTIPS */ 252 | 253 | /* tooltip floats to left of handle */ 254 | .ui-slider-vertical.ui-slider-float .ui-slider-tip, 255 | .ui-slider-vertical.ui-slider-float .ui-slider-tip-label { 256 | 257 | top: 50%; 258 | margin-top: -11px; 259 | width: 34px; 260 | margin-left: 0px; 261 | left: -60px; 262 | color: #333; 263 | 264 | -webkit-transition-duration: 200ms, 200ms, 0; 265 | -moz-transition-duration: 200ms, 200ms, 0; 266 | -ms-transition-duration: 200ms, 200ms, 0; 267 | transition-duration: 200ms, 200ms, 0; 268 | 269 | -webkit-transition-property: opacity, left, visibility; 270 | -moz-transition-property: opacity, left, visibility; 271 | -ms-transition-property: opacity, left, visibility; 272 | transition-property: opacity, left, visibility; 273 | 274 | -webkit-transition-delay: 0, 0, 200ms; 275 | -moz-transition-delay: 0, 0, 200ms; 276 | -ms-transition-delay: 0, 0, 200ms; 277 | transition-delay: 0, 0, 200ms; 278 | 279 | } 280 | 281 | 282 | 283 | .ui-slider-vertical.ui-slider-float .ui-slider-handle:hover .ui-slider-tip, 284 | .ui-slider-vertical.ui-slider-float .ui-slider-handle.ui-state-hover .ui-slider-tip, 285 | .ui-slider-vertical.ui-slider-float .ui-slider-handle:focus .ui-slider-tip, 286 | .ui-slider-vertical.ui-slider-float .ui-slider-handle.ui-state-focus .ui-slider-tip, 287 | .ui-slider-vertical.ui-slider-float .ui-slider-handle.ui-state-active .ui-slider-tip, 288 | .ui-slider-vertical.ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label { 289 | top: 50%; 290 | margin-top: -11px; 291 | left: -50px; 292 | } 293 | 294 | /* put label tooltips to right of slider */ 295 | .ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label { 296 | left: 47px; 297 | } 298 | 299 | .ui-slider-vertical.ui-slider-float .ui-slider-pip:hover .ui-slider-tip-label { 300 | left: 37px; 301 | } 302 | 303 | /* give the tooltip a css triangle arrow */ 304 | .ui-slider-vertical.ui-slider-float .ui-slider-tip:after, 305 | .ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:after { 306 | border: 5px solid rgba(255,255,255,0); 307 | border-left-color: rgba(255,255,255,1); 308 | border-top-color: transparent; 309 | position: absolute; 310 | bottom: 50%; 311 | margin-bottom: -5px; 312 | right: -10px; 313 | margin-left: 0; 314 | top: auto; 315 | left: auto; 316 | } 317 | 318 | .ui-slider-vertical.ui-slider-float .ui-slider-tip:before, 319 | .ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:before { 320 | border: 5px solid rgba(255,255,255,0); 321 | border-left-color: #888; 322 | border-top-color: transparent; 323 | position: absolute; 324 | bottom: 50%; 325 | margin-bottom: -5px; 326 | right: -11px; 327 | margin-left: 0; 328 | top: auto; 329 | left: auto; 330 | } 331 | 332 | .ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:after { 333 | border: 5px solid rgba(255,255,255,0); 334 | border-right-color: rgba(255,255,255,1); 335 | right: auto; 336 | left: -10px; 337 | } 338 | 339 | .ui-slider-vertical.ui-slider-float .ui-slider-pip .ui-slider-tip-label:before { 340 | border: 5px solid rgba(255,255,255,0); 341 | border-right-color: #888; 342 | right: auto; 343 | left: -11px; 344 | } 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | /* SELECTED STATES */ 360 | /* Comment out this chuck of code if you don't want to have 361 | the new label colours shown */ 362 | 363 | .ui-slider-pips [class*=ui-slider-pip-initial] { 364 | 365 | font-weight: bold; 366 | color: #14CA82; 367 | 368 | } 369 | 370 | .ui-slider-pips .ui-slider-pip-initial-1 { 371 | 372 | } 373 | 374 | .ui-slider-pips .ui-slider-pip-initial-2 { 375 | color: #1897C9; 376 | } 377 | 378 | 379 | 380 | .ui-slider-pips [class*=ui-slider-pip-selected] { 381 | 382 | font-weight: bold; 383 | color: #FF7A00; 384 | 385 | } 386 | 387 | .ui-slider-pips .ui-slider-pip-inrange { 388 | 389 | color: black; 390 | 391 | } 392 | 393 | .ui-slider-pips .ui-slider-pip-selected-1 { 394 | 395 | } 396 | 397 | .ui-slider-pips .ui-slider-pip-selected-2 { 398 | color: #E70081; 399 | } 400 | 401 | 402 | .ui-slider-pips [class*=ui-slider-pip-selected] .ui-slider-line, 403 | .ui-slider-pips .ui-slider-pip-inrange .ui-slider-line { 404 | 405 | background: black; 406 | 407 | } 408 | 409 | 410 | 411 | -------------------------------------------------------------------------------- /src/js/jquery-ui-slider-pips.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | "use strict"; 4 | 5 | var extensionMethods = { 6 | 7 | 8 | 9 | 10 | 11 | // pips 12 | 13 | pips: function( settings ) { 14 | 15 | var slider = this, 16 | i, j, p, 17 | collection = "", 18 | mousedownHandlers, 19 | min = slider._valueMin(), 20 | max = slider._valueMax(), 21 | pips = ( max - min ) / slider.options.step, 22 | $handles = slider.element.find(".ui-slider-handle"), 23 | $pips; 24 | 25 | var options = { 26 | 27 | first: "label", 28 | /* "label", "pip", false */ 29 | 30 | last: "label", 31 | /* "label", "pip", false */ 32 | 33 | rest: "pip", 34 | /* "label", "pip", false */ 35 | 36 | labels: false, 37 | /* [array], { first: "string", rest: [array], last: "string" }, false */ 38 | 39 | prefix: "", 40 | /* "", string */ 41 | 42 | suffix: "", 43 | /* "", string */ 44 | 45 | step: ( pips > 100 ) ? Math.floor( pips * 0.05 ) : 1, 46 | /* number */ 47 | 48 | formatLabel: function(value) { 49 | return this.prefix + value + this.suffix; 50 | } 51 | /* function 52 | must return a value to display in the pip labels */ 53 | 54 | }; 55 | 56 | if ( $.type( settings ) === "object" || $.type( settings ) === "undefined" ) { 57 | 58 | $.extend( options, settings ); 59 | slider.element.data("pips-options", options ); 60 | 61 | } else { 62 | 63 | if ( settings === "destroy" ) { 64 | 65 | destroy(); 66 | 67 | } else if ( settings === "refresh" ) { 68 | 69 | slider.element.slider( "pips", slider.element.data("pips-options") ); 70 | 71 | } 72 | 73 | return; 74 | 75 | } 76 | 77 | 78 | // we don't want the step ever to be a floating point or negative 79 | // (or 0 actually, so we'll set it to 1 in that case). 80 | slider.options.pipStep = Math.abs( Math.round( options.step ) ) || 1; 81 | 82 | // get rid of all pips that might already exist. 83 | slider.element 84 | .off( ".selectPip" ) 85 | .addClass("ui-slider-pips") 86 | .find(".ui-slider-pip") 87 | .remove(); 88 | 89 | // small object with functions for marking pips as selected. 90 | 91 | var selectPip = { 92 | 93 | single: function(value) { 94 | 95 | this.resetClasses(); 96 | 97 | $pips 98 | .filter(".ui-slider-pip-" + this.classLabel(value) ) 99 | .addClass("ui-slider-pip-selected"); 100 | 101 | if ( slider.options.range ) { 102 | 103 | $pips.each(function(k, v) { 104 | 105 | var pipVal = $(v).children(".ui-slider-label").data("value"); 106 | 107 | if (( slider.options.range === "min" && pipVal < value ) || 108 | ( slider.options.range === "max" && pipVal > value )) { 109 | 110 | $(v).addClass("ui-slider-pip-inrange"); 111 | 112 | } 113 | 114 | }); 115 | 116 | } 117 | 118 | }, 119 | 120 | range: function(values) { 121 | 122 | this.resetClasses(); 123 | 124 | for ( i = 0; i < values.length; i++ ) { 125 | 126 | $pips 127 | .filter(".ui-slider-pip-" + this.classLabel(values[i]) ) 128 | .addClass("ui-slider-pip-selected-" + ( i + 1 ) ); 129 | 130 | } 131 | 132 | if ( slider.options.range ) { 133 | 134 | $pips.each(function(k, v) { 135 | 136 | var pipVal = $(v).children(".ui-slider-label").data("value"); 137 | 138 | if ( pipVal > values[0] && pipVal < values[1] ) { 139 | 140 | $(v).addClass("ui-slider-pip-inrange"); 141 | 142 | } 143 | 144 | }); 145 | 146 | } 147 | 148 | }, 149 | 150 | classLabel: function(value) { 151 | 152 | return value.toString().replace(".", "-"); 153 | 154 | }, 155 | 156 | resetClasses: function() { 157 | 158 | var regex = /(^|\s*)(ui-slider-pip-selected|ui-slider-pip-inrange)(-{1,2}\d+|\s|$)/gi; 159 | 160 | $pips.removeClass( function(index, css) { 161 | return ( css.match(regex) || [] ).join(" "); 162 | }); 163 | 164 | } 165 | 166 | }; 167 | 168 | function getClosestHandle( val ) { 169 | 170 | var h, k, 171 | sliderVals, 172 | comparedVals, 173 | closestVal, 174 | tempHandles = [], 175 | closestHandle = 0; 176 | 177 | if ( slider.values() && slider.values().length ) { 178 | 179 | // get the current values of the slider handles 180 | sliderVals = slider.values(); 181 | 182 | // find the offset value from the `val` for each 183 | // handle, and store it in a new array 184 | comparedVals = $.map( sliderVals, function(v) { 185 | return Math.abs( v - val ); 186 | }); 187 | 188 | // figure out the closest handles to the value 189 | closestVal = Math.min.apply( Math, comparedVals ); 190 | 191 | // if a comparedVal is the closestVal, then 192 | // set the value accordingly, and set the closest handle. 193 | for ( h = 0; h < comparedVals.length; h++ ) { 194 | if ( comparedVals[h] === closestVal ) { 195 | tempHandles.push(h); 196 | } 197 | } 198 | 199 | // set the closest handle to the first handle in array, 200 | // just incase we have no _lastChangedValue to compare to. 201 | closestHandle = tempHandles[0]; 202 | 203 | // now we want to find out if any of the closest handles were 204 | // the last changed handle, if so we specify that handle to change 205 | for ( k = 0; k < tempHandles.length; k++ ) { 206 | if ( slider._lastChangedValue === tempHandles[k] ) { 207 | closestHandle = tempHandles[k]; 208 | } 209 | } 210 | 211 | if ( slider.options.range && tempHandles.length === 2 ) { 212 | 213 | if ( val > sliderVals[1] ) { 214 | 215 | closestHandle = tempHandles[1]; 216 | 217 | } else if ( val < sliderVals[0] ) { 218 | 219 | closestHandle = tempHandles[0]; 220 | 221 | } 222 | 223 | } 224 | 225 | } 226 | 227 | return closestHandle; 228 | 229 | } 230 | 231 | function destroy() { 232 | 233 | slider.element 234 | .off(".selectPip") 235 | .on("mousedown.slider", slider.element.data("mousedown-original") ) 236 | .removeClass("ui-slider-pips") 237 | .find(".ui-slider-pip") 238 | .remove(); 239 | 240 | } 241 | 242 | // when we click on a label, we want to make sure the 243 | // slider's handle actually goes to that label! 244 | // so we check all the handles and see which one is closest 245 | // to the label we clicked. If 2 handles are equidistant then 246 | // we move both of them. We also want to trigger focus on the 247 | // handle. 248 | 249 | // without this method the label is just treated like a part 250 | // of the slider and there's no accuracy in the selected value 251 | 252 | function labelClick( label, e ) { 253 | 254 | if (slider.option("disabled")) { 255 | return; 256 | } 257 | 258 | var val = $(label).data("value"), 259 | indexToChange = getClosestHandle( val ); 260 | 261 | if ( slider.values() && slider.values().length ) { 262 | 263 | slider.options.values[ indexToChange ] = slider._trimAlignValue( val ); 264 | 265 | } else { 266 | 267 | slider.options.value = slider._trimAlignValue( val ); 268 | 269 | } 270 | 271 | slider._refreshValue(); 272 | slider._change( e, indexToChange ); 273 | 274 | } 275 | 276 | // method for creating a pip. We loop this for creating all 277 | // the pips. 278 | 279 | function createPip( which ) { 280 | 281 | var label, 282 | percent, 283 | number = which, 284 | classes = "ui-slider-pip", 285 | css = "", 286 | value = slider.value(), 287 | values = slider.values(), 288 | labelValue, 289 | classLabel, 290 | labelIndex; 291 | 292 | if ( which === "first" ) { 293 | 294 | number = 0; 295 | 296 | } else if ( which === "last" ) { 297 | 298 | number = pips; 299 | 300 | } 301 | 302 | // labelValue is the actual value of the pip based on the min/step 303 | labelValue = min + ( slider.options.step * number ); 304 | 305 | // classLabel replaces any decimals with hyphens 306 | classLabel = labelValue.toString().replace(".", "-"); 307 | 308 | // get the index needed for selecting labels out of the array 309 | labelIndex = ( number + min ) - min; 310 | 311 | // we need to set the human-readable label to either the 312 | // corresponding element in the array, or the appropriate 313 | // item in the object... or an empty string. 314 | 315 | if ( $.type(options.labels) === "array" ) { 316 | 317 | label = options.labels[ labelIndex ] || ""; 318 | 319 | } else if ( $.type( options.labels ) === "object" ) { 320 | 321 | if ( which === "first" ) { 322 | 323 | // set first label 324 | label = options.labels.first || ""; 325 | 326 | } else if ( which === "last" ) { 327 | 328 | // set last label 329 | label = options.labels.last || ""; 330 | 331 | } else if ( $.type( options.labels.rest ) === "array" ) { 332 | 333 | // set other labels, but our index should start at -1 334 | // because of the first pip. 335 | label = options.labels.rest[ labelIndex - 1 ] || ""; 336 | 337 | } else { 338 | 339 | // urrggh, the options must be f**ked, just show nothing. 340 | label = labelValue; 341 | 342 | } 343 | 344 | } else { 345 | 346 | label = labelValue; 347 | 348 | } 349 | 350 | 351 | 352 | 353 | if ( which === "first" ) { 354 | 355 | // first Pip on the Slider 356 | percent = "0%"; 357 | 358 | classes += " ui-slider-pip-first"; 359 | classes += ( options.first === "label" ) ? " ui-slider-pip-label" : ""; 360 | classes += ( options.first === false ) ? " ui-slider-pip-hide" : ""; 361 | 362 | } else if ( which === "last" ) { 363 | 364 | // last Pip on the Slider 365 | percent = "100%"; 366 | 367 | classes += " ui-slider-pip-last"; 368 | classes += ( options.last === "label" ) ? " ui-slider-pip-label" : ""; 369 | classes += ( options.last === false ) ? " ui-slider-pip-hide" : ""; 370 | 371 | } else { 372 | 373 | // all other Pips 374 | percent = (( 100 / pips ) * which ).toFixed(4) + "%"; 375 | 376 | classes += ( options.rest === "label" ) ? " ui-slider-pip-label" : ""; 377 | classes += ( options.rest === false ) ? " ui-slider-pip-hide" : ""; 378 | 379 | } 380 | 381 | classes += " ui-slider-pip-" + classLabel; 382 | 383 | 384 | // add classes for the initial-selected values. 385 | if ( values && values.length ) { 386 | 387 | for ( i = 0; i < values.length; i++ ) { 388 | 389 | if ( labelValue === values[i] ) { 390 | 391 | classes += " ui-slider-pip-initial-" + ( i + 1 ); 392 | classes += " ui-slider-pip-selected-" + ( i + 1 ); 393 | 394 | } 395 | 396 | } 397 | 398 | if ( slider.options.range ) { 399 | 400 | if ( labelValue > values[0] && 401 | labelValue < values[1] ) { 402 | 403 | classes += " ui-slider-pip-inrange"; 404 | 405 | } 406 | 407 | } 408 | 409 | } else { 410 | 411 | if ( labelValue === value ) { 412 | 413 | classes += " ui-slider-pip-initial"; 414 | classes += " ui-slider-pip-selected"; 415 | 416 | } 417 | 418 | if ( slider.options.range ) { 419 | 420 | if (( slider.options.range === "min" && labelValue < value ) || 421 | ( slider.options.range === "max" && labelValue > value )) { 422 | 423 | classes += " ui-slider-pip-inrange"; 424 | 425 | } 426 | 427 | } 428 | 429 | } 430 | 431 | 432 | 433 | css = ( slider.options.orientation === "horizontal" ) ? 434 | "left: " + percent : 435 | "bottom: " + percent; 436 | 437 | 438 | // add this current pip to the collection 439 | return "" + 440 | "" + 441 | "" + options.formatLabel(label) + "" + 443 | ""; 444 | 445 | } 446 | 447 | // create our first pip 448 | collection += createPip("first"); 449 | 450 | // for every stop in the slider where we need a pip; create one. 451 | for ( p = slider.options.pipStep; p < pips; p += slider.options.pipStep ) { 452 | collection += createPip( p ); 453 | } 454 | 455 | // create our last pip 456 | collection += createPip("last"); 457 | 458 | // append the collection of pips. 459 | slider.element.append( collection ); 460 | 461 | // store the pips for setting classes later. 462 | $pips = slider.element.find(".ui-slider-pip"); 463 | 464 | 465 | 466 | // store the mousedown handlers for later, just in case we reset 467 | // the slider, the handler would be lost! 468 | 469 | if ( $._data( slider.element.get(0), "events").mousedown && 470 | $._data( slider.element.get(0), "events").mousedown.length ) { 471 | 472 | mousedownHandlers = $._data( slider.element.get(0), "events").mousedown; 473 | 474 | } else { 475 | 476 | mousedownHandlers = slider.element.data("mousedown-handlers"); 477 | 478 | } 479 | 480 | slider.element.data("mousedown-handlers", mousedownHandlers.slice() ); 481 | 482 | // loop through all the mousedown handlers on the slider, 483 | // and store the original namespaced (.slider) event handler so 484 | // we can trigger it later. 485 | for ( j = 0; j < mousedownHandlers.length; j++ ) { 486 | if ( mousedownHandlers[j].namespace === "slider" ) { 487 | slider.element.data("mousedown-original", mousedownHandlers[j].handler ); 488 | } 489 | } 490 | 491 | // unbind the mousedown.slider event, because it interferes with 492 | // the labelClick() method (stops smooth animation), and decide 493 | // if we want to trigger the original event based on which element 494 | // was clicked. 495 | slider.element 496 | .off("mousedown.slider") 497 | .on("mousedown.selectPip", function(e) { 498 | 499 | var $target = $(e.target), 500 | closest = getClosestHandle( $target.data("value") ), 501 | $handle = $handles.eq( closest ); 502 | 503 | $handle.addClass("ui-state-active"); 504 | 505 | if ( $target.is(".ui-slider-label") ) { 506 | 507 | labelClick( $target, e ); 508 | 509 | slider.element 510 | .one("mouseup.selectPip", function() { 511 | 512 | $handle 513 | .removeClass("ui-state-active") 514 | .focus(); 515 | 516 | }); 517 | 518 | } else { 519 | 520 | var originalMousedown = slider.element.data("mousedown-original"); 521 | originalMousedown(e); 522 | 523 | } 524 | 525 | }); 526 | 527 | 528 | 529 | 530 | slider.element.on( "slide.selectPip slidechange.selectPip", function(e, ui) { 531 | 532 | var $slider = $(this), 533 | value = $slider.slider("value"), 534 | values = $slider.slider("values"); 535 | 536 | if ( ui ) { 537 | 538 | value = ui.value; 539 | values = ui.values; 540 | 541 | } 542 | 543 | if ( slider.values() && slider.values().length ) { 544 | 545 | selectPip.range( values ); 546 | 547 | } else { 548 | 549 | selectPip.single( value ); 550 | 551 | } 552 | 553 | }); 554 | 555 | 556 | 557 | 558 | }, 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | // floats 568 | 569 | float: function( settings ) { 570 | 571 | var i, 572 | slider = this, 573 | min = slider._valueMin(), 574 | max = slider._valueMax(), 575 | value = slider._value(), 576 | values = slider._values(), 577 | tipValues = [], 578 | $handles = slider.element.find(".ui-slider-handle"); 579 | 580 | var options = { 581 | 582 | handle: true, 583 | /* false */ 584 | 585 | pips: false, 586 | /* true */ 587 | 588 | labels: false, 589 | /* [array], { first: "string", rest: [array], last: "string" }, false */ 590 | 591 | prefix: "", 592 | /* "", string */ 593 | 594 | suffix: "", 595 | /* "", string */ 596 | 597 | event: "slidechange slide", 598 | /* "slidechange", "slide", "slidechange slide" */ 599 | 600 | formatLabel: function(value) { 601 | return this.prefix + value + this.suffix; 602 | } 603 | /* function 604 | must return a value to display in the floats */ 605 | 606 | }; 607 | 608 | if ( $.type( settings ) === "object" || $.type( settings ) === "undefined" ) { 609 | 610 | $.extend( options, settings ); 611 | slider.element.data("float-options", options ); 612 | 613 | } else { 614 | 615 | if ( settings === "destroy" ) { 616 | 617 | destroy(); 618 | 619 | } else if ( settings === "refresh" ) { 620 | 621 | slider.element.slider( "float", slider.element.data("float-options") ); 622 | 623 | } 624 | 625 | return; 626 | 627 | } 628 | 629 | 630 | 631 | 632 | if ( value < min ) { 633 | value = min; 634 | } 635 | 636 | if ( value > max ) { 637 | value = max; 638 | } 639 | 640 | if ( values && values.length ) { 641 | 642 | for ( i = 0; i < values.length; i++ ) { 643 | 644 | if ( values[i] < min ) { 645 | values[i] = min; 646 | } 647 | 648 | if ( values[i] > max ) { 649 | values[i] = max; 650 | } 651 | 652 | } 653 | 654 | } 655 | 656 | // add a class for the CSS 657 | slider.element 658 | .addClass("ui-slider-float") 659 | .find(".ui-slider-tip, .ui-slider-tip-label") 660 | .remove(); 661 | 662 | 663 | 664 | function destroy() { 665 | 666 | slider.element 667 | .off(".sliderFloat") 668 | .removeClass("ui-slider-float") 669 | .find(".ui-slider-tip, .ui-slider-tip-label") 670 | .remove(); 671 | 672 | } 673 | 674 | 675 | function getPipLabels( values ) { 676 | 677 | // when checking the array we need to divide 678 | // by the step option, so we store those values here. 679 | 680 | var vals = [], 681 | steppedVals = $.map( values, function(v) { 682 | return Math.ceil(( v - min ) / slider.options.step); 683 | }); 684 | 685 | // now we just get the values we need to return 686 | // by looping through the values array and assigning the 687 | // label if it exists. 688 | 689 | if ( $.type( options.labels ) === "array" ) { 690 | 691 | for ( i = 0; i < values.length; i++ ) { 692 | 693 | vals[i] = options.labels[ steppedVals[i] ] || values[i]; 694 | 695 | } 696 | 697 | } else if ( $.type( options.labels ) === "object" ) { 698 | 699 | for ( i = 0; i < values.length; i++ ) { 700 | 701 | if ( values[i] === min ) { 702 | 703 | vals[i] = options.labels.first || min; 704 | 705 | } else if ( values[i] === max ) { 706 | 707 | vals[i] = options.labels.last || max; 708 | 709 | } else if ( $.type( options.labels.rest ) === "array" ) { 710 | 711 | vals[i] = options.labels.rest[ steppedVals[i] - 1 ] || values[i]; 712 | 713 | } else { 714 | 715 | vals[i] = values[i]; 716 | 717 | } 718 | 719 | } 720 | 721 | } else { 722 | 723 | for ( i = 0; i < values.length; i++ ) { 724 | 725 | vals[i] = values[i]; 726 | 727 | } 728 | 729 | } 730 | 731 | return vals; 732 | 733 | } 734 | 735 | // apply handle tip if settings allows. 736 | if ( options.handle ) { 737 | 738 | // we need to set the human-readable label to either the 739 | // corresponding element in the array, or the appropriate 740 | // item in the object... or an empty string. 741 | 742 | tipValues = ( slider.values() && slider.values().length ) ? 743 | getPipLabels( values ) : 744 | getPipLabels( [ value ] ); 745 | 746 | for ( i = 0; i < tipValues.length; i++ ) { 747 | 748 | $handles 749 | .eq( i ) 750 | .append( $(""+ options.formatLabel(tipValues[i]) +"") ); 751 | 752 | } 753 | 754 | } 755 | 756 | if ( options.pips ) { 757 | 758 | // if this slider also has pip-labels, we make those into tips, too. 759 | slider.element.find(".ui-slider-label").each(function(k, v) { 760 | 761 | var $this = $(v), 762 | val = [ $this.data("value") ], 763 | label, 764 | $tip; 765 | 766 | 767 | label = options.formatLabel( getPipLabels( val )[0] ); 768 | 769 | // create a tip element 770 | $tip = 771 | $("" + label + "") 772 | .insertAfter( $this ); 773 | 774 | }); 775 | 776 | } 777 | 778 | // check that the event option is actually valid against our 779 | // own list of the slider's events. 780 | if ( options.event !== "slide" && 781 | options.event !== "slidechange" && 782 | options.event !== "slide slidechange" && 783 | options.event !== "slidechange slide" ) { 784 | 785 | options.event = "slidechange slide"; 786 | 787 | } 788 | 789 | // when slider changes, update handle tip label. 790 | slider.element 791 | .off(".sliderFloat") 792 | .on( options.event + ".sliderFloat", function( e, ui ) { 793 | 794 | var uiValue = ( $.type( ui.value ) === "array" ) ? ui.value : [ ui.value ], 795 | val = options.formatLabel( getPipLabels( uiValue )[0] ); 796 | 797 | $(ui.handle) 798 | .find(".ui-slider-tip") 799 | .html( val ); 800 | 801 | }); 802 | 803 | } 804 | 805 | }; 806 | 807 | $.extend(true, $.ui.slider.prototype, extensionMethods); 808 | 809 | })(jQuery); 810 | --------------------------------------------------------------------------------