materialize-sass 0.97.8 → 1.0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +5 -5
  2. data/.gitattributes +1 -0
  3. data/.gitignore +1 -0
  4. data/README.md +34 -32
  5. data/Rakefile +38 -21
  6. data/assets/javascripts/materialize/anime.min.js +417 -0
  7. data/assets/javascripts/materialize/autocomplete.js +504 -0
  8. data/assets/javascripts/materialize/buttons.js +409 -0
  9. data/assets/javascripts/materialize/cards.js +34 -0
  10. data/assets/javascripts/materialize/carousel.js +797 -0
  11. data/assets/javascripts/materialize/cash.js +990 -0
  12. data/assets/javascripts/materialize/characterCounter.js +180 -0
  13. data/assets/javascripts/materialize/chips.js +564 -0
  14. data/assets/javascripts/materialize/collapsible.js +337 -0
  15. data/assets/javascripts/materialize/component.js +57 -0
  16. data/assets/javascripts/materialize/datepicker.js +935 -0
  17. data/assets/javascripts/materialize/dropdown.js +659 -0
  18. data/assets/javascripts/materialize/extras/nouislider.js +2147 -0
  19. data/assets/javascripts/materialize/extras/nouislider.min.js +1 -0
  20. data/assets/javascripts/materialize/forms.js +244 -0
  21. data/assets/javascripts/materialize/global.js +408 -0
  22. data/assets/javascripts/materialize/materialbox.js +513 -0
  23. data/assets/javascripts/materialize/modal.js +449 -0
  24. data/assets/javascripts/materialize/parallax.js +173 -0
  25. data/assets/javascripts/materialize/pushpin.js +179 -0
  26. data/assets/javascripts/materialize/range.js +310 -0
  27. data/assets/javascripts/materialize/scrollspy.js +328 -0
  28. data/assets/javascripts/materialize/select.js +497 -0
  29. data/assets/javascripts/materialize/sidenav.js +655 -0
  30. data/assets/javascripts/materialize/slider.js +424 -0
  31. data/assets/javascripts/materialize/tabs.js +476 -0
  32. data/assets/javascripts/materialize/tapTarget.js +364 -0
  33. data/assets/javascripts/materialize/timepicker.js +647 -0
  34. data/assets/javascripts/materialize/toasts.js +355 -0
  35. data/assets/javascripts/materialize/tooltip.js +351 -0
  36. data/{app/assets → assets}/javascripts/materialize/waves.js +42 -47
  37. data/{app/assets → assets}/javascripts/materialize-sprockets.js +12 -13
  38. data/assets/javascripts/materialize.js +12374 -0
  39. data/assets/stylesheets/materialize/components/_badges.scss +55 -0
  40. data/{app/assets → assets}/stylesheets/materialize/components/_buttons.scss +99 -58
  41. data/{app/assets → assets}/stylesheets/materialize/components/_cards.scss +14 -6
  42. data/{app/assets → assets}/stylesheets/materialize/components/_carousel.scss +12 -7
  43. data/{app/assets → assets}/stylesheets/materialize/components/_chips.scss +13 -6
  44. data/{app/assets → assets}/stylesheets/materialize/components/_collapsible.scss +16 -15
  45. data/assets/stylesheets/materialize/components/_color-classes.scss +32 -0
  46. data/{app/assets/stylesheets/materialize/components/_color.scss → assets/stylesheets/materialize/components/_color-variables.scss} +2 -44
  47. data/assets/stylesheets/materialize/components/_datepicker.scss +191 -0
  48. data/{app/assets → assets}/stylesheets/materialize/components/_dropdown.scss +35 -15
  49. data/{app/assets → assets}/stylesheets/materialize/components/_global.scss +96 -125
  50. data/{app/assets → assets}/stylesheets/materialize/components/_grid.scss +45 -36
  51. data/{app/assets → assets}/stylesheets/materialize/components/_icons-material-design.scss +0 -0
  52. data/{app/assets → assets}/stylesheets/materialize/components/_materialbox.scss +13 -12
  53. data/{app/assets → assets}/stylesheets/materialize/components/_modal.scss +7 -3
  54. data/{app/assets → assets}/stylesheets/materialize/components/_navbar.scss +29 -11
  55. data/assets/stylesheets/materialize/components/_normalize.scss +447 -0
  56. data/{app/assets → assets}/stylesheets/materialize/components/_preloader.scss +2 -2
  57. data/assets/stylesheets/materialize/components/_pulse.scss +34 -0
  58. data/{app/assets/stylesheets/materialize/components/_sideNav.scss → assets/stylesheets/materialize/components/_sidenav.scss} +47 -47
  59. data/{app/assets → assets}/stylesheets/materialize/components/_slider.scss +0 -0
  60. data/{app/assets → assets}/stylesheets/materialize/components/_table_of_contents.scss +5 -5
  61. data/{app/assets → assets}/stylesheets/materialize/components/_tabs.scss +10 -10
  62. data/assets/stylesheets/materialize/components/_tapTarget.scss +103 -0
  63. data/assets/stylesheets/materialize/components/_timepicker.scss +183 -0
  64. data/{app/assets → assets}/stylesheets/materialize/components/_toast.scss +7 -14
  65. data/{app/assets → assets}/stylesheets/materialize/components/_tooltip.scss +3 -3
  66. data/assets/stylesheets/materialize/components/_transitions.scss +13 -0
  67. data/{app/assets → assets}/stylesheets/materialize/components/_typography.scss +8 -9
  68. data/{app/assets → assets}/stylesheets/materialize/components/_variables.scss +65 -29
  69. data/assets/stylesheets/materialize/components/_waves.scss +114 -0
  70. data/{app/assets → assets}/stylesheets/materialize/components/forms/_checkboxes.scss +26 -46
  71. data/{app/assets → assets}/stylesheets/materialize/components/forms/_file-input.scss +6 -0
  72. data/{app/assets → assets}/stylesheets/materialize/components/forms/_forms.scss +0 -0
  73. data/{app/assets → assets}/stylesheets/materialize/components/forms/_input-fields.scss +131 -63
  74. data/assets/stylesheets/materialize/components/forms/_radio-buttons.scss +115 -0
  75. data/{app/assets → assets}/stylesheets/materialize/components/forms/_range.scss +35 -33
  76. data/{app/assets → assets}/stylesheets/materialize/components/forms/_select.scss +88 -19
  77. data/{app/assets → assets}/stylesheets/materialize/components/forms/_switches.scss +32 -21
  78. data/assets/stylesheets/materialize/extras/nouislider.css +406 -0
  79. data/{app/assets → assets}/stylesheets/materialize.scss +10 -9
  80. data/lib/materialize-sass/engine.rb +9 -7
  81. data/lib/materialize-sass/helpers.rb +38 -0
  82. data/lib/materialize-sass/version.rb +1 -1
  83. data/lib/materialize-sass.rb +13 -28
  84. data/materialize-sass.gemspec +5 -5
  85. metadata +97 -119
  86. data/app/assets/fonts/roboto/Roboto-Bold.eot +0 -0
  87. data/app/assets/fonts/roboto/Roboto-Bold.ttf +0 -0
  88. data/app/assets/fonts/roboto/Roboto-Bold.woff +0 -0
  89. data/app/assets/fonts/roboto/Roboto-Bold.woff2 +0 -0
  90. data/app/assets/fonts/roboto/Roboto-Light.eot +0 -0
  91. data/app/assets/fonts/roboto/Roboto-Light.ttf +0 -0
  92. data/app/assets/fonts/roboto/Roboto-Light.woff +0 -0
  93. data/app/assets/fonts/roboto/Roboto-Light.woff2 +0 -0
  94. data/app/assets/fonts/roboto/Roboto-Medium.eot +0 -0
  95. data/app/assets/fonts/roboto/Roboto-Medium.ttf +0 -0
  96. data/app/assets/fonts/roboto/Roboto-Medium.woff +0 -0
  97. data/app/assets/fonts/roboto/Roboto-Medium.woff2 +0 -0
  98. data/app/assets/fonts/roboto/Roboto-Regular.eot +0 -0
  99. data/app/assets/fonts/roboto/Roboto-Regular.ttf +0 -0
  100. data/app/assets/fonts/roboto/Roboto-Regular.woff +0 -0
  101. data/app/assets/fonts/roboto/Roboto-Regular.woff2 +0 -0
  102. data/app/assets/fonts/roboto/Roboto-Thin.eot +0 -0
  103. data/app/assets/fonts/roboto/Roboto-Thin.ttf +0 -0
  104. data/app/assets/fonts/roboto/Roboto-Thin.woff +0 -0
  105. data/app/assets/fonts/roboto/Roboto-Thin.woff2 +0 -0
  106. data/app/assets/javascripts/materialize/animation.js +0 -9
  107. data/app/assets/javascripts/materialize/buttons.js +0 -267
  108. data/app/assets/javascripts/materialize/cards.js +0 -26
  109. data/app/assets/javascripts/materialize/carousel.js +0 -454
  110. data/app/assets/javascripts/materialize/character_counter.js +0 -72
  111. data/app/assets/javascripts/materialize/chips.js +0 -289
  112. data/app/assets/javascripts/materialize/collapsible.js +0 -160
  113. data/app/assets/javascripts/materialize/date_picker/picker.date.js +0 -1430
  114. data/app/assets/javascripts/materialize/date_picker/picker.js +0 -1123
  115. data/app/assets/javascripts/materialize/dropdown.js +0 -265
  116. data/app/assets/javascripts/materialize/extras/nouislider.js +0 -1666
  117. data/app/assets/javascripts/materialize/extras/nouislider.min.js +0 -1
  118. data/app/assets/javascripts/materialize/forms.js +0 -682
  119. data/app/assets/javascripts/materialize/global.js +0 -98
  120. data/app/assets/javascripts/materialize/hammer.min.js +0 -1
  121. data/app/assets/javascripts/materialize/init.js +0 -174
  122. data/app/assets/javascripts/materialize/initial.js +0 -11
  123. data/app/assets/javascripts/materialize/jquery.easing.1.3.js +0 -205
  124. data/app/assets/javascripts/materialize/jquery.hammer.js +0 -33
  125. data/app/assets/javascripts/materialize/jquery.timeago.min.js +0 -1
  126. data/app/assets/javascripts/materialize/materialbox.js +0 -269
  127. data/app/assets/javascripts/materialize/modal.js +0 -184
  128. data/app/assets/javascripts/materialize/parallax.js +0 -58
  129. data/app/assets/javascripts/materialize/prism.js +0 -8
  130. data/app/assets/javascripts/materialize/pushpin.js +0 -71
  131. data/app/assets/javascripts/materialize/scrollFire.js +0 -48
  132. data/app/assets/javascripts/materialize/scrollspy.js +0 -284
  133. data/app/assets/javascripts/materialize/sideNav.js +0 -370
  134. data/app/assets/javascripts/materialize/slider.js +0 -321
  135. data/app/assets/javascripts/materialize/tabs.js +0 -164
  136. data/app/assets/javascripts/materialize/toasts.js +0 -137
  137. data/app/assets/javascripts/materialize/tooltip.js +0 -236
  138. data/app/assets/javascripts/materialize/transitions.js +0 -169
  139. data/app/assets/javascripts/materialize/velocity.min.js +0 -5
  140. data/app/assets/javascripts/materialize.js +0 -5
  141. data/app/assets/stylesheets/materialize/components/_mixins.scss +0 -5
  142. data/app/assets/stylesheets/materialize/components/_normalize.scss +0 -424
  143. data/app/assets/stylesheets/materialize/components/_prefixer.scss +0 -384
  144. data/app/assets/stylesheets/materialize/components/_roboto.scss +0 -49
  145. data/app/assets/stylesheets/materialize/components/_waves.scss +0 -177
  146. data/app/assets/stylesheets/materialize/components/date_picker/_default.date.scss +0 -435
  147. data/app/assets/stylesheets/materialize/components/date_picker/_default.scss +0 -201
  148. data/app/assets/stylesheets/materialize/components/date_picker/_default.time.scss +0 -125
  149. data/app/assets/stylesheets/materialize/components/forms/_radio-buttons.scss +0 -117
  150. data/app/assets/stylesheets/materialize/extras/nouislider.css +0 -259
@@ -1,1666 +0,0 @@
1
- /*!
2
- * Materialize v0.97.8 (http://materializecss.com)
3
- * Copyright 2014-2015 Materialize
4
- * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE)
5
- */
6
- // wNumb
7
- (function(){function r(b){return b.split("").reverse().join("")}function s(b,f,c){if((b[f]||b[c])&&b[f]===b[c])throw Error(f);}function v(b,f,c,d,e,p,q,k,l,h,n,a){q=a;var m,g=n="";p&&(a=p(a));if("number"!==typeof a||!isFinite(a))return!1;b&&0===parseFloat(a.toFixed(b))&&(a=0);0>a&&(m=!0,a=Math.abs(a));b&&(p=Math.pow(10,b),a=(Math.round(a*p)/p).toFixed(b));a=a.toString();-1!==a.indexOf(".")&&(b=a.split("."),a=b[0],c&&(n=c+b[1]));f&&(a=r(a).match(/.{1,3}/g),a=r(a.join(r(f))));m&&k&&(g+=k);d&&(g+=d);
8
- m&&l&&(g+=l);g=g+a+n;e&&(g+=e);h&&(g=h(g,q));return g}function w(b,f,c,d,e,h,q,k,l,r,n,a){var m;b="";n&&(a=n(a));if(!a||"string"!==typeof a)return!1;k&&a.substring(0,k.length)===k&&(a=a.replace(k,""),m=!0);d&&a.substring(0,d.length)===d&&(a=a.replace(d,""));l&&a.substring(0,l.length)===l&&(a=a.replace(l,""),m=!0);e&&a.slice(-1*e.length)===e&&(a=a.slice(0,-1*e.length));f&&(a=a.split(f).join(""));c&&(a=a.replace(c,"."));m&&(b+="-");b=Number((b+a).replace(/[^0-9\.\-.]/g,""));q&&(b=q(b));return"number"===
9
- typeof b&&isFinite(b)?b:!1}function x(b){var f,c,d,e={};for(f=0;f<h.length;f+=1)c=h[f],d=b[c],void 0===d?e[c]="negative"!==c||e.negativeBefore?"mark"===c&&"."!==e.thousand?".":!1:"-":"decimals"===c?0<d&&8>d&&(e[c]=d):"encoder"===c||"decoder"===c||"edit"===c||"undo"===c?"function"===typeof d&&(e[c]=d):"string"===typeof d&&(e[c]=d);s(e,"mark","thousand");s(e,"prefix","negative");s(e,"prefix","negativeBefore");return e}function u(b,f,c){var d,e=[];for(d=0;d<h.length;d+=1)e.push(b[h[d]]);e.push(c);return f.apply("",
10
- e)}function t(b){if(!(this instanceof t))return new t(b);"object"===typeof b&&(b=x(b),this.to=function(f){return u(b,v,f)},this.from=function(f){return u(b,w,f)})}var h="decimals thousand mark prefix postfix encoder decoder negativeBefore negative edit undo".split(" ");window.wNumb=t})();
11
-
12
-
13
- /*! nouislider - 8.0.2 - 2015-07-06 13:22:09 */
14
-
15
- /*jslint browser: true */
16
- /*jslint white: true */
17
-
18
- (function (factory) {
19
-
20
- if ( typeof define === 'function' && define.amd ) {
21
-
22
- // AMD. Register as an anonymous module.
23
- define([], factory);
24
-
25
- } else if ( typeof exports === 'object' ) {
26
-
27
- var fs = require('fs');
28
-
29
- // Node/CommonJS
30
- module.exports = factory();
31
- module.exports.css = function () {
32
- return fs.readFileSync(__dirname + '/nouislider.min.css', 'utf8');
33
- };
34
-
35
- } else {
36
-
37
- // Browser globals
38
- window.noUiSlider = factory();
39
- }
40
-
41
- }(function( ){
42
-
43
- 'use strict';
44
-
45
-
46
- // Removes duplicates from an array.
47
- function unique(array) {
48
- return array.filter(function(a){
49
- return !this[a] ? this[a] = true : false;
50
- }, {});
51
- }
52
-
53
- // Round a value to the closest 'to'.
54
- function closest ( value, to ) {
55
- return Math.round(value / to) * to;
56
- }
57
-
58
- // Current position of an element relative to the document.
59
- function offset ( elem ) {
60
-
61
- var rect = elem.getBoundingClientRect(),
62
- doc = elem.ownerDocument,
63
- win = doc.defaultView || doc.parentWindow,
64
- docElem = doc.documentElement,
65
- xOff = win.pageXOffset;
66
-
67
- // getBoundingClientRect contains left scroll in Chrome on Android.
68
- // I haven't found a feature detection that proves this. Worst case
69
- // scenario on mis-match: the 'tap' feature on horizontal sliders breaks.
70
- if ( /webkit.*Chrome.*Mobile/i.test(navigator.userAgent) ) {
71
- xOff = 0;
72
- }
73
-
74
- return {
75
- top: rect.top + win.pageYOffset - docElem.clientTop,
76
- left: rect.left + xOff - docElem.clientLeft
77
- };
78
- }
79
-
80
- // Checks whether a value is numerical.
81
- function isNumeric ( a ) {
82
- return typeof a === 'number' && !isNaN( a ) && isFinite( a );
83
- }
84
-
85
- // Rounds a number to 7 supported decimals.
86
- function accurateNumber( number ) {
87
- var p = Math.pow(10, 7);
88
- return Number((Math.round(number*p)/p).toFixed(7));
89
- }
90
-
91
- // Sets a class and removes it after [duration] ms.
92
- function addClassFor ( element, className, duration ) {
93
- addClass(element, className);
94
- setTimeout(function(){
95
- removeClass(element, className);
96
- }, duration);
97
- }
98
-
99
- // Limits a value to 0 - 100
100
- function limit ( a ) {
101
- return Math.max(Math.min(a, 100), 0);
102
- }
103
-
104
- // Wraps a variable as an array, if it isn't one yet.
105
- function asArray ( a ) {
106
- return Array.isArray(a) ? a : [a];
107
- }
108
-
109
- // Counts decimals
110
- function countDecimals ( numStr ) {
111
- var pieces = numStr.split(".");
112
- return pieces.length > 1 ? pieces[1].length : 0;
113
- }
114
-
115
- // http://youmightnotneedjquery.com/#add_class
116
- function addClass ( el, className ) {
117
- if ( el.classList ) {
118
- el.classList.add(className);
119
- } else {
120
- el.className += ' ' + className;
121
- }
122
- }
123
-
124
- // http://youmightnotneedjquery.com/#remove_class
125
- function removeClass ( el, className ) {
126
- if ( el.classList ) {
127
- el.classList.remove(className);
128
- } else {
129
- el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
130
- }
131
- }
132
-
133
- // http://youmightnotneedjquery.com/#has_class
134
- function hasClass ( el, className ) {
135
- if ( el.classList ) {
136
- el.classList.contains(className);
137
- } else {
138
- new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
139
- }
140
- }
141
-
142
-
143
- var
144
- // Determine the events to bind. IE11 implements pointerEvents without
145
- // a prefix, which breaks compatibility with the IE10 implementation.
146
- /** @const */
147
- actions = window.navigator.pointerEnabled ? {
148
- start: 'pointerdown',
149
- move: 'pointermove',
150
- end: 'pointerup'
151
- } : window.navigator.msPointerEnabled ? {
152
- start: 'MSPointerDown',
153
- move: 'MSPointerMove',
154
- end: 'MSPointerUp'
155
- } : {
156
- start: 'mousedown touchstart',
157
- move: 'mousemove touchmove',
158
- end: 'mouseup touchend'
159
- },
160
- // Re-usable list of classes;
161
- /** @const */
162
- Classes = [
163
- /* 0 */ 'noUi-target'
164
- /* 1 */ ,'noUi-base'
165
- /* 2 */ ,'noUi-origin'
166
- /* 3 */ ,'noUi-handle'
167
- /* 4 */ ,'noUi-horizontal'
168
- /* 5 */ ,'noUi-vertical'
169
- /* 6 */ ,'noUi-background'
170
- /* 7 */ ,'noUi-connect'
171
- /* 8 */ ,'noUi-ltr'
172
- /* 9 */ ,'noUi-rtl'
173
- /* 10 */ ,'noUi-dragable'
174
- /* 11 */ ,''
175
- /* 12 */ ,'noUi-state-drag'
176
- /* 13 */ ,''
177
- /* 14 */ ,'noUi-state-tap'
178
- /* 15 */ ,'noUi-active'
179
- /* 16 */ ,''
180
- /* 17 */ ,'noUi-stacking'
181
- ];
182
-
183
-
184
- // Value calculation
185
-
186
- // Determine the size of a sub-range in relation to a full range.
187
- function subRangeRatio ( pa, pb ) {
188
- return (100 / (pb - pa));
189
- }
190
-
191
- // (percentage) How many percent is this value of this range?
192
- function fromPercentage ( range, value ) {
193
- return (value * 100) / ( range[1] - range[0] );
194
- }
195
-
196
- // (percentage) Where is this value on this range?
197
- function toPercentage ( range, value ) {
198
- return fromPercentage( range, range[0] < 0 ?
199
- value + Math.abs(range[0]) :
200
- value - range[0] );
201
- }
202
-
203
- // (value) How much is this percentage on this range?
204
- function isPercentage ( range, value ) {
205
- return ((value * ( range[1] - range[0] )) / 100) + range[0];
206
- }
207
-
208
-
209
- // Range conversion
210
-
211
- function getJ ( value, arr ) {
212
-
213
- var j = 1;
214
-
215
- while ( value >= arr[j] ){
216
- j += 1;
217
- }
218
-
219
- return j;
220
- }
221
-
222
- // (percentage) Input a value, find where, on a scale of 0-100, it applies.
223
- function toStepping ( xVal, xPct, value ) {
224
-
225
- if ( value >= xVal.slice(-1)[0] ){
226
- return 100;
227
- }
228
-
229
- var j = getJ( value, xVal ), va, vb, pa, pb;
230
-
231
- va = xVal[j-1];
232
- vb = xVal[j];
233
- pa = xPct[j-1];
234
- pb = xPct[j];
235
-
236
- return pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb));
237
- }
238
-
239
- // (value) Input a percentage, find where it is on the specified range.
240
- function fromStepping ( xVal, xPct, value ) {
241
-
242
- // There is no range group that fits 100
243
- if ( value >= 100 ){
244
- return xVal.slice(-1)[0];
245
- }
246
-
247
- var j = getJ( value, xPct ), va, vb, pa, pb;
248
-
249
- va = xVal[j-1];
250
- vb = xVal[j];
251
- pa = xPct[j-1];
252
- pb = xPct[j];
253
-
254
- return isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb));
255
- }
256
-
257
- // (percentage) Get the step that applies at a certain value.
258
- function getStep ( xPct, xSteps, snap, value ) {
259
-
260
- if ( value === 100 ) {
261
- return value;
262
- }
263
-
264
- var j = getJ( value, xPct ), a, b;
265
-
266
- // If 'snap' is set, steps are used as fixed points on the slider.
267
- if ( snap ) {
268
-
269
- a = xPct[j-1];
270
- b = xPct[j];
271
-
272
- // Find the closest position, a or b.
273
- if ((value - a) > ((b-a)/2)){
274
- return b;
275
- }
276
-
277
- return a;
278
- }
279
-
280
- if ( !xSteps[j-1] ){
281
- return value;
282
- }
283
-
284
- return xPct[j-1] + closest(
285
- value - xPct[j-1],
286
- xSteps[j-1]
287
- );
288
- }
289
-
290
-
291
- // Entry parsing
292
-
293
- function handleEntryPoint ( index, value, that ) {
294
-
295
- var percentage;
296
-
297
- // Wrap numerical input in an array.
298
- if ( typeof value === "number" ) {
299
- value = [value];
300
- }
301
-
302
- // Reject any invalid input, by testing whether value is an array.
303
- if ( Object.prototype.toString.call( value ) !== '[object Array]' ){
304
- throw new Error("noUiSlider: 'range' contains invalid value.");
305
- }
306
-
307
- // Covert min/max syntax to 0 and 100.
308
- if ( index === 'min' ) {
309
- percentage = 0;
310
- } else if ( index === 'max' ) {
311
- percentage = 100;
312
- } else {
313
- percentage = parseFloat( index );
314
- }
315
-
316
- // Check for correct input.
317
- if ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) {
318
- throw new Error("noUiSlider: 'range' value isn't numeric.");
319
- }
320
-
321
- // Store values.
322
- that.xPct.push( percentage );
323
- that.xVal.push( value[0] );
324
-
325
- // NaN will evaluate to false too, but to keep
326
- // logging clear, set step explicitly. Make sure
327
- // not to override the 'step' setting with false.
328
- if ( !percentage ) {
329
- if ( !isNaN( value[1] ) ) {
330
- that.xSteps[0] = value[1];
331
- }
332
- } else {
333
- that.xSteps.push( isNaN(value[1]) ? false : value[1] );
334
- }
335
- }
336
-
337
- function handleStepPoint ( i, n, that ) {
338
-
339
- // Ignore 'false' stepping.
340
- if ( !n ) {
341
- return true;
342
- }
343
-
344
- // Factor to range ratio
345
- that.xSteps[i] = fromPercentage([
346
- that.xVal[i]
347
- ,that.xVal[i+1]
348
- ], n) / subRangeRatio (
349
- that.xPct[i],
350
- that.xPct[i+1] );
351
- }
352
-
353
-
354
- // Interface
355
-
356
- // The interface to Spectrum handles all direction-based
357
- // conversions, so the above values are unaware.
358
-
359
- function Spectrum ( entry, snap, direction, singleStep ) {
360
-
361
- this.xPct = [];
362
- this.xVal = [];
363
- this.xSteps = [ singleStep || false ];
364
- this.xNumSteps = [ false ];
365
-
366
- this.snap = snap;
367
- this.direction = direction;
368
-
369
- var index, ordered = [ /* [0, 'min'], [1, '50%'], [2, 'max'] */ ];
370
-
371
- // Map the object keys to an array.
372
- for ( index in entry ) {
373
- if ( entry.hasOwnProperty(index) ) {
374
- ordered.push([entry[index], index]);
375
- }
376
- }
377
-
378
- // Sort all entries by value (numeric sort).
379
- ordered.sort(function(a, b) { return a[0] - b[0]; });
380
-
381
- // Convert all entries to subranges.
382
- for ( index = 0; index < ordered.length; index++ ) {
383
- handleEntryPoint(ordered[index][1], ordered[index][0], this);
384
- }
385
-
386
- // Store the actual step values.
387
- // xSteps is sorted in the same order as xPct and xVal.
388
- this.xNumSteps = this.xSteps.slice(0);
389
-
390
- // Convert all numeric steps to the percentage of the subrange they represent.
391
- for ( index = 0; index < this.xNumSteps.length; index++ ) {
392
- handleStepPoint(index, this.xNumSteps[index], this);
393
- }
394
- }
395
-
396
- Spectrum.prototype.getMargin = function ( value ) {
397
- return this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false;
398
- };
399
-
400
- Spectrum.prototype.toStepping = function ( value ) {
401
-
402
- value = toStepping( this.xVal, this.xPct, value );
403
-
404
- // Invert the value if this is a right-to-left slider.
405
- if ( this.direction ) {
406
- value = 100 - value;
407
- }
408
-
409
- return value;
410
- };
411
-
412
- Spectrum.prototype.fromStepping = function ( value ) {
413
-
414
- // Invert the value if this is a right-to-left slider.
415
- if ( this.direction ) {
416
- value = 100 - value;
417
- }
418
-
419
- return accurateNumber(fromStepping( this.xVal, this.xPct, value ));
420
- };
421
-
422
- Spectrum.prototype.getStep = function ( value ) {
423
-
424
- // Find the proper step for rtl sliders by search in inverse direction.
425
- // Fixes issue #262.
426
- if ( this.direction ) {
427
- value = 100 - value;
428
- }
429
-
430
- value = getStep(this.xPct, this.xSteps, this.snap, value );
431
-
432
- if ( this.direction ) {
433
- value = 100 - value;
434
- }
435
-
436
- return value;
437
- };
438
-
439
- Spectrum.prototype.getApplicableStep = function ( value ) {
440
-
441
- // If the value is 100%, return the negative step twice.
442
- var j = getJ(value, this.xPct), offset = value === 100 ? 2 : 1;
443
- return [this.xNumSteps[j-2], this.xVal[j-offset], this.xNumSteps[j-offset]];
444
- };
445
-
446
- // Outside testing
447
- Spectrum.prototype.convert = function ( value ) {
448
- return this.getStep(this.toStepping(value));
449
- };
450
-
451
- /* Every input option is tested and parsed. This'll prevent
452
- endless validation in internal methods. These tests are
453
- structured with an item for every option available. An
454
- option can be marked as required by setting the 'r' flag.
455
- The testing function is provided with three arguments:
456
- - The provided value for the option;
457
- - A reference to the options object;
458
- - The name for the option;
459
-
460
- The testing function returns false when an error is detected,
461
- or true when everything is OK. It can also modify the option
462
- object, to make sure all values can be correctly looped elsewhere. */
463
-
464
- var defaultFormatter = { 'to': function( value ){
465
- return value.toFixed(2);
466
- }, 'from': Number };
467
-
468
- function testStep ( parsed, entry ) {
469
-
470
- if ( !isNumeric( entry ) ) {
471
- throw new Error("noUiSlider: 'step' is not numeric.");
472
- }
473
-
474
- // The step option can still be used to set stepping
475
- // for linear sliders. Overwritten if set in 'range'.
476
- parsed.singleStep = entry;
477
- }
478
-
479
- function testRange ( parsed, entry ) {
480
-
481
- // Filter incorrect input.
482
- if ( typeof entry !== 'object' || Array.isArray(entry) ) {
483
- throw new Error("noUiSlider: 'range' is not an object.");
484
- }
485
-
486
- // Catch missing start or end.
487
- if ( entry.min === undefined || entry.max === undefined ) {
488
- throw new Error("noUiSlider: Missing 'min' or 'max' in 'range'.");
489
- }
490
-
491
- parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.dir, parsed.singleStep);
492
- }
493
-
494
- function testStart ( parsed, entry ) {
495
-
496
- entry = asArray(entry);
497
-
498
- // Validate input. Values aren't tested, as the public .val method
499
- // will always provide a valid location.
500
- if ( !Array.isArray( entry ) || !entry.length || entry.length > 2 ) {
501
- throw new Error("noUiSlider: 'start' option is incorrect.");
502
- }
503
-
504
- // Store the number of handles.
505
- parsed.handles = entry.length;
506
-
507
- // When the slider is initialized, the .val method will
508
- // be called with the start options.
509
- parsed.start = entry;
510
- }
511
-
512
- function testSnap ( parsed, entry ) {
513
-
514
- // Enforce 100% stepping within subranges.
515
- parsed.snap = entry;
516
-
517
- if ( typeof entry !== 'boolean' ){
518
- throw new Error("noUiSlider: 'snap' option must be a boolean.");
519
- }
520
- }
521
-
522
- function testAnimate ( parsed, entry ) {
523
-
524
- // Enforce 100% stepping within subranges.
525
- parsed.animate = entry;
526
-
527
- if ( typeof entry !== 'boolean' ){
528
- throw new Error("noUiSlider: 'animate' option must be a boolean.");
529
- }
530
- }
531
-
532
- function testConnect ( parsed, entry ) {
533
-
534
- if ( entry === 'lower' && parsed.handles === 1 ) {
535
- parsed.connect = 1;
536
- } else if ( entry === 'upper' && parsed.handles === 1 ) {
537
- parsed.connect = 2;
538
- } else if ( entry === true && parsed.handles === 2 ) {
539
- parsed.connect = 3;
540
- } else if ( entry === false ) {
541
- parsed.connect = 0;
542
- } else {
543
- throw new Error("noUiSlider: 'connect' option doesn't match handle count.");
544
- }
545
- }
546
-
547
- function testOrientation ( parsed, entry ) {
548
-
549
- // Set orientation to an a numerical value for easy
550
- // array selection.
551
- switch ( entry ){
552
- case 'horizontal':
553
- parsed.ort = 0;
554
- break;
555
- case 'vertical':
556
- parsed.ort = 1;
557
- break;
558
- default:
559
- throw new Error("noUiSlider: 'orientation' option is invalid.");
560
- }
561
- }
562
-
563
- function testMargin ( parsed, entry ) {
564
-
565
- if ( !isNumeric(entry) ){
566
- throw new Error("noUiSlider: 'margin' option must be numeric.");
567
- }
568
-
569
- parsed.margin = parsed.spectrum.getMargin(entry);
570
-
571
- if ( !parsed.margin ) {
572
- throw new Error("noUiSlider: 'margin' option is only supported on linear sliders.");
573
- }
574
- }
575
-
576
- function testLimit ( parsed, entry ) {
577
-
578
- if ( !isNumeric(entry) ){
579
- throw new Error("noUiSlider: 'limit' option must be numeric.");
580
- }
581
-
582
- parsed.limit = parsed.spectrum.getMargin(entry);
583
-
584
- if ( !parsed.limit ) {
585
- throw new Error("noUiSlider: 'limit' option is only supported on linear sliders.");
586
- }
587
- }
588
-
589
- function testDirection ( parsed, entry ) {
590
-
591
- // Set direction as a numerical value for easy parsing.
592
- // Invert connection for RTL sliders, so that the proper
593
- // handles get the connect/background classes.
594
- switch ( entry ) {
595
- case 'ltr':
596
- parsed.dir = 0;
597
- break;
598
- case 'rtl':
599
- parsed.dir = 1;
600
- parsed.connect = [0,2,1,3][parsed.connect];
601
- break;
602
- default:
603
- throw new Error("noUiSlider: 'direction' option was not recognized.");
604
- }
605
- }
606
-
607
- function testBehaviour ( parsed, entry ) {
608
-
609
- // Make sure the input is a string.
610
- if ( typeof entry !== 'string' ) {
611
- throw new Error("noUiSlider: 'behaviour' must be a string containing options.");
612
- }
613
-
614
- // Check if the string contains any keywords.
615
- // None are required.
616
- var tap = entry.indexOf('tap') >= 0,
617
- drag = entry.indexOf('drag') >= 0,
618
- fixed = entry.indexOf('fixed') >= 0,
619
- snap = entry.indexOf('snap') >= 0;
620
-
621
- parsed.events = {
622
- tap: tap || snap,
623
- drag: drag,
624
- fixed: fixed,
625
- snap: snap
626
- };
627
- }
628
-
629
- function testFormat ( parsed, entry ) {
630
-
631
- parsed.format = entry;
632
-
633
- // Any object with a to and from method is supported.
634
- if ( typeof entry.to === 'function' && typeof entry.from === 'function' ) {
635
- return true;
636
- }
637
-
638
- throw new Error( "noUiSlider: 'format' requires 'to' and 'from' methods.");
639
- }
640
-
641
- // Test all developer settings and parse to assumption-safe values.
642
- function testOptions ( options ) {
643
-
644
- var parsed = {
645
- margin: 0,
646
- limit: 0,
647
- animate: true,
648
- format: defaultFormatter
649
- }, tests;
650
-
651
- // Tests are executed in the order they are presented here.
652
- tests = {
653
- 'step': { r: false, t: testStep },
654
- 'start': { r: true, t: testStart },
655
- 'connect': { r: true, t: testConnect },
656
- 'direction': { r: true, t: testDirection },
657
- 'snap': { r: false, t: testSnap },
658
- 'animate': { r: false, t: testAnimate },
659
- 'range': { r: true, t: testRange },
660
- 'orientation': { r: false, t: testOrientation },
661
- 'margin': { r: false, t: testMargin },
662
- 'limit': { r: false, t: testLimit },
663
- 'behaviour': { r: true, t: testBehaviour },
664
- 'format': { r: false, t: testFormat }
665
- };
666
-
667
- var defaults = {
668
- 'connect': false,
669
- 'direction': 'ltr',
670
- 'behaviour': 'tap',
671
- 'orientation': 'horizontal'
672
- };
673
-
674
- // Set defaults where applicable.
675
- Object.keys(defaults).forEach(function ( name ) {
676
- if ( options[name] === undefined ) {
677
- options[name] = defaults[name];
678
- }
679
- });
680
-
681
- // Run all options through a testing mechanism to ensure correct
682
- // input. It should be noted that options might get modified to
683
- // be handled properly. E.g. wrapping integers in arrays.
684
- Object.keys(tests).forEach(function( name ){
685
-
686
- var test = tests[name];
687
-
688
- // If the option isn't set, but it is required, throw an error.
689
- if ( options[name] === undefined ) {
690
-
691
- if ( test.r ) {
692
- throw new Error("noUiSlider: '" + name + "' is required.");
693
- }
694
-
695
- return true;
696
- }
697
-
698
- test.t( parsed, options[name] );
699
- });
700
-
701
- // Forward pips options
702
- parsed.pips = options.pips;
703
-
704
- // Pre-define the styles.
705
- parsed.style = parsed.ort ? 'top' : 'left';
706
-
707
- return parsed;
708
- }
709
-
710
-
711
- // Delimit proposed values for handle positions.
712
- function getPositions ( a, b, delimit ) {
713
-
714
- // Add movement to current position.
715
- var c = a + b[0], d = a + b[1];
716
-
717
- // Only alter the other position on drag,
718
- // not on standard sliding.
719
- if ( delimit ) {
720
- if ( c < 0 ) {
721
- d += Math.abs(c);
722
- }
723
- if ( d > 100 ) {
724
- c -= ( d - 100 );
725
- }
726
-
727
- // Limit values to 0 and 100.
728
- return [limit(c), limit(d)];
729
- }
730
-
731
- return [c,d];
732
- }
733
-
734
- // Provide a clean event with standardized offset values.
735
- function fixEvent ( e ) {
736
-
737
- // Prevent scrolling and panning on touch events, while
738
- // attempting to slide. The tap event also depends on this.
739
- e.preventDefault();
740
-
741
- // Filter the event to register the type, which can be
742
- // touch, mouse or pointer. Offset changes need to be
743
- // made on an event specific basis.
744
- var touch = e.type.indexOf('touch') === 0,
745
- mouse = e.type.indexOf('mouse') === 0,
746
- pointer = e.type.indexOf('pointer') === 0,
747
- x,y, event = e;
748
-
749
- // IE10 implemented pointer events with a prefix;
750
- if ( e.type.indexOf('MSPointer') === 0 ) {
751
- pointer = true;
752
- }
753
-
754
- if ( touch ) {
755
- // noUiSlider supports one movement at a time,
756
- // so we can select the first 'changedTouch'.
757
- x = e.changedTouches[0].pageX;
758
- y = e.changedTouches[0].pageY;
759
- }
760
-
761
- if ( mouse || pointer ) {
762
- x = e.clientX + window.pageXOffset;
763
- y = e.clientY + window.pageYOffset;
764
- }
765
-
766
- event.points = [x, y];
767
- event.cursor = mouse || pointer; // Fix #435
768
-
769
- return event;
770
- }
771
-
772
- // Append a handle to the base.
773
- function addHandle ( direction, index ) {
774
-
775
- var origin = document.createElement('div'),
776
- handle = document.createElement('div'),
777
- additions = [ '-lower', '-upper' ];
778
-
779
- if ( direction ) {
780
- additions.reverse();
781
- }
782
-
783
- addClass(handle, Classes[3]);
784
- addClass(handle, Classes[3] + additions[index]);
785
-
786
- addClass(origin, Classes[2]);
787
- origin.appendChild(handle);
788
-
789
- return origin;
790
- }
791
-
792
- // Add the proper connection classes.
793
- function addConnection ( connect, target, handles ) {
794
-
795
- // Apply the required connection classes to the elements
796
- // that need them. Some classes are made up for several
797
- // segments listed in the class list, to allow easy
798
- // renaming and provide a minor compression benefit.
799
- switch ( connect ) {
800
- case 1: addClass(target, Classes[7]);
801
- addClass(handles[0], Classes[6]);
802
- break;
803
- case 3: addClass(handles[1], Classes[6]);
804
- /* falls through */
805
- case 2: addClass(handles[0], Classes[7]);
806
- /* falls through */
807
- case 0: addClass(target, Classes[6]);
808
- break;
809
- }
810
- }
811
-
812
- // Add handles to the slider base.
813
- function addHandles ( nrHandles, direction, base ) {
814
-
815
- var index, handles = [];
816
-
817
- // Append handles.
818
- for ( index = 0; index < nrHandles; index += 1 ) {
819
-
820
- // Keep a list of all added handles.
821
- handles.push( base.appendChild(addHandle( direction, index )) );
822
- }
823
-
824
- return handles;
825
- }
826
-
827
- // Initialize a single slider.
828
- function addSlider ( direction, orientation, target ) {
829
-
830
- // Apply classes and data to the target.
831
- addClass(target, Classes[0]);
832
- addClass(target, Classes[8 + direction]);
833
- addClass(target, Classes[4 + orientation]);
834
-
835
- var div = document.createElement('div');
836
- addClass(div, Classes[1]);
837
- target.appendChild(div);
838
- return div;
839
- }
840
-
841
-
842
- function closure ( target, options ){
843
-
844
- // All variables local to 'closure' are prefixed with 'scope_'
845
- var scope_Target = target,
846
- scope_Locations = [-1, -1],
847
- scope_Base,
848
- scope_Handles,
849
- scope_Spectrum = options.spectrum,
850
- scope_Values = [],
851
- scope_Events = {};
852
-
853
-
854
- function getGroup ( mode, values, stepped ) {
855
-
856
- // Use the range.
857
- if ( mode === 'range' || mode === 'steps' ) {
858
- return scope_Spectrum.xVal;
859
- }
860
-
861
- if ( mode === 'count' ) {
862
-
863
- // Divide 0 - 100 in 'count' parts.
864
- var spread = ( 100 / (values-1) ), v, i = 0;
865
- values = [];
866
-
867
- // List these parts and have them handled as 'positions'.
868
- while ((v=i++*spread) <= 100 ) {
869
- values.push(v);
870
- }
871
-
872
- mode = 'positions';
873
- }
874
-
875
- if ( mode === 'positions' ) {
876
-
877
- // Map all percentages to on-range values.
878
- return values.map(function( value ){
879
- return scope_Spectrum.fromStepping( stepped ? scope_Spectrum.getStep( value ) : value );
880
- });
881
- }
882
-
883
- if ( mode === 'values' ) {
884
-
885
- // If the value must be stepped, it needs to be converted to a percentage first.
886
- if ( stepped ) {
887
-
888
- return values.map(function( value ){
889
-
890
- // Convert to percentage, apply step, return to value.
891
- return scope_Spectrum.fromStepping( scope_Spectrum.getStep( scope_Spectrum.toStepping( value ) ) );
892
- });
893
-
894
- }
895
-
896
- // Otherwise, we can simply use the values.
897
- return values;
898
- }
899
- }
900
-
901
- function generateSpread ( density, mode, group ) {
902
-
903
- var originalSpectrumDirection = scope_Spectrum.direction,
904
- indexes = {},
905
- firstInRange = scope_Spectrum.xVal[0],
906
- lastInRange = scope_Spectrum.xVal[scope_Spectrum.xVal.length-1],
907
- ignoreFirst = false,
908
- ignoreLast = false,
909
- prevPct = 0;
910
-
911
- // This function loops the spectrum in an ltr linear fashion,
912
- // while the toStepping method is direction aware. Trick it into
913
- // believing it is ltr.
914
- scope_Spectrum.direction = 0;
915
-
916
- // Create a copy of the group, sort it and filter away all duplicates.
917
- group = unique(group.slice().sort(function(a, b){ return a - b; }));
918
-
919
- // Make sure the range starts with the first element.
920
- if ( group[0] !== firstInRange ) {
921
- group.unshift(firstInRange);
922
- ignoreFirst = true;
923
- }
924
-
925
- // Likewise for the last one.
926
- if ( group[group.length - 1] !== lastInRange ) {
927
- group.push(lastInRange);
928
- ignoreLast = true;
929
- }
930
-
931
- group.forEach(function ( current, index ) {
932
-
933
- // Get the current step and the lower + upper positions.
934
- var step, i, q,
935
- low = current,
936
- high = group[index+1],
937
- newPct, pctDifference, pctPos, type,
938
- steps, realSteps, stepsize;
939
-
940
- // When using 'steps' mode, use the provided steps.
941
- // Otherwise, we'll step on to the next subrange.
942
- if ( mode === 'steps' ) {
943
- step = scope_Spectrum.xNumSteps[ index ];
944
- }
945
-
946
- // Default to a 'full' step.
947
- if ( !step ) {
948
- step = high-low;
949
- }
950
-
951
- // Low can be 0, so test for false. If high is undefined,
952
- // we are at the last subrange. Index 0 is already handled.
953
- if ( low === false || high === undefined ) {
954
- return;
955
- }
956
-
957
- // Find all steps in the subrange.
958
- for ( i = low; i <= high; i += step ) {
959
-
960
- // Get the percentage value for the current step,
961
- // calculate the size for the subrange.
962
- newPct = scope_Spectrum.toStepping( i );
963
- pctDifference = newPct - prevPct;
964
-
965
- steps = pctDifference / density;
966
- realSteps = Math.round(steps);
967
-
968
- // This ratio represents the ammount of percentage-space a point indicates.
969
- // For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-devided.
970
- // Round the percentage offset to an even number, then divide by two
971
- // to spread the offset on both sides of the range.
972
- stepsize = pctDifference/realSteps;
973
-
974
- // Divide all points evenly, adding the correct number to this subrange.
975
- // Run up to <= so that 100% gets a point, event if ignoreLast is set.
976
- for ( q = 1; q <= realSteps; q += 1 ) {
977
-
978
- // The ratio between the rounded value and the actual size might be ~1% off.
979
- // Correct the percentage offset by the number of points
980
- // per subrange. density = 1 will result in 100 points on the
981
- // full range, 2 for 50, 4 for 25, etc.
982
- pctPos = prevPct + ( q * stepsize );
983
- indexes[pctPos.toFixed(5)] = ['x', 0];
984
- }
985
-
986
- // Determine the point type.
987
- type = (group.indexOf(i) > -1) ? 1 : ( mode === 'steps' ? 2 : 0 );
988
-
989
- // Enforce the 'ignoreFirst' option by overwriting the type for 0.
990
- if ( !index && ignoreFirst ) {
991
- type = 0;
992
- }
993
-
994
- if ( !(i === high && ignoreLast)) {
995
- // Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value.
996
- indexes[newPct.toFixed(5)] = [i, type];
997
- }
998
-
999
- // Update the percentage count.
1000
- prevPct = newPct;
1001
- }
1002
- });
1003
-
1004
- // Reset the spectrum.
1005
- scope_Spectrum.direction = originalSpectrumDirection;
1006
-
1007
- return indexes;
1008
- }
1009
-
1010
- function addMarking ( spread, filterFunc, formatter ) {
1011
-
1012
- var style = ['horizontal', 'vertical'][options.ort],
1013
- element = document.createElement('div');
1014
-
1015
- addClass(element, 'noUi-pips');
1016
- addClass(element, 'noUi-pips-' + style);
1017
-
1018
- function getSize( type ){
1019
- return [ '-normal', '-large', '-sub' ][type];
1020
- }
1021
-
1022
- function getTags( offset, source, values ) {
1023
- return 'class="' + source + ' ' +
1024
- source + '-' + style + ' ' +
1025
- source + getSize(values[1]) +
1026
- '" style="' + options.style + ': ' + offset + '%"';
1027
- }
1028
-
1029
- function addSpread ( offset, values ){
1030
-
1031
- if ( scope_Spectrum.direction ) {
1032
- offset = 100 - offset;
1033
- }
1034
-
1035
- // Apply the filter function, if it is set.
1036
- values[1] = (values[1] && filterFunc) ? filterFunc(values[0], values[1]) : values[1];
1037
-
1038
- // Add a marker for every point
1039
- element.innerHTML += '<div ' + getTags(offset, 'noUi-marker', values) + '></div>';
1040
-
1041
- // Values are only appended for points marked '1' or '2'.
1042
- if ( values[1] ) {
1043
- element.innerHTML += '<div '+getTags(offset, 'noUi-value', values)+'>' + formatter.to(values[0]) + '</div>';
1044
- }
1045
- }
1046
-
1047
- // Append all points.
1048
- Object.keys(spread).forEach(function(a){
1049
- addSpread(a, spread[a]);
1050
- });
1051
-
1052
- return element;
1053
- }
1054
-
1055
- function pips ( grid ) {
1056
-
1057
- var mode = grid.mode,
1058
- density = grid.density || 1,
1059
- filter = grid.filter || false,
1060
- values = grid.values || false,
1061
- stepped = grid.stepped || false,
1062
- group = getGroup( mode, values, stepped ),
1063
- spread = generateSpread( density, mode, group ),
1064
- format = grid.format || {
1065
- to: Math.round
1066
- };
1067
-
1068
- return scope_Target.appendChild(addMarking(
1069
- spread,
1070
- filter,
1071
- format
1072
- ));
1073
- }
1074
-
1075
-
1076
- // Shorthand for base dimensions.
1077
- function baseSize ( ) {
1078
- return scope_Base['offset' + ['Width', 'Height'][options.ort]];
1079
- }
1080
-
1081
- // External event handling
1082
- function fireEvent ( event, handleNumber ) {
1083
-
1084
- if ( handleNumber !== undefined ) {
1085
- handleNumber = Math.abs(handleNumber - options.dir);
1086
- }
1087
-
1088
- Object.keys(scope_Events).forEach(function( targetEvent ) {
1089
-
1090
- var eventType = targetEvent.split('.')[0];
1091
-
1092
- if ( event === eventType ) {
1093
- scope_Events[targetEvent].forEach(function( callback ) {
1094
- // .reverse is in place
1095
- // Return values as array, so arg_1[arg_2] is always valid.
1096
- callback( asArray(valueGet()), handleNumber, inSliderOrder(Array.prototype.slice.call(scope_Values)) );
1097
- });
1098
- }
1099
- });
1100
- }
1101
-
1102
- // Returns the input array, respecting the slider direction configuration.
1103
- function inSliderOrder ( values ) {
1104
-
1105
- // If only one handle is used, return a single value.
1106
- if ( values.length === 1 ){
1107
- return values[0];
1108
- }
1109
-
1110
- if ( options.dir ) {
1111
- return values.reverse();
1112
- }
1113
-
1114
- return values;
1115
- }
1116
-
1117
-
1118
- // Handler for attaching events trough a proxy.
1119
- function attach ( events, element, callback, data ) {
1120
-
1121
- // This function can be used to 'filter' events to the slider.
1122
- // element is a node, not a nodeList
1123
-
1124
- var method = function ( e ){
1125
-
1126
- if ( scope_Target.hasAttribute('disabled') ) {
1127
- return false;
1128
- }
1129
-
1130
- // Stop if an active 'tap' transition is taking place.
1131
- if ( hasClass(scope_Target, Classes[14]) ) {
1132
- return false;
1133
- }
1134
-
1135
- e = fixEvent(e);
1136
-
1137
- // Ignore right or middle clicks on start #454
1138
- if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) {
1139
- return false;
1140
- }
1141
-
1142
- e.calcPoint = e.points[ options.ort ];
1143
-
1144
- // Call the event handler with the event [ and additional data ].
1145
- callback ( e, data );
1146
-
1147
- }, methods = [];
1148
-
1149
- // Bind a closure on the target for every event type.
1150
- events.split(' ').forEach(function( eventName ){
1151
- element.addEventListener(eventName, method, false);
1152
- methods.push([eventName, method]);
1153
- });
1154
-
1155
- return methods;
1156
- }
1157
-
1158
- // Handle movement on document for handle and range drag.
1159
- function move ( event, data ) {
1160
-
1161
- var handles = data.handles || scope_Handles, positions, state = false,
1162
- proposal = ((event.calcPoint - data.start) * 100) / baseSize(),
1163
- handleNumber = handles[0] === scope_Handles[0] ? 0 : 1, i;
1164
-
1165
- // Calculate relative positions for the handles.
1166
- positions = getPositions( proposal, data.positions, handles.length > 1);
1167
-
1168
- state = setHandle ( handles[0], positions[handleNumber], handles.length === 1 );
1169
-
1170
- if ( handles.length > 1 ) {
1171
-
1172
- state = setHandle ( handles[1], positions[handleNumber?0:1], false ) || state;
1173
-
1174
- if ( state ) {
1175
- // fire for both handles
1176
- for ( i = 0; i < data.handles.length; i++ ) {
1177
- fireEvent('slide', i);
1178
- }
1179
- }
1180
- } else if ( state ) {
1181
- // Fire for a single handle
1182
- fireEvent('slide', handleNumber);
1183
- }
1184
- }
1185
-
1186
- // Unbind move events on document, call callbacks.
1187
- function end ( event, data ) {
1188
-
1189
- // The handle is no longer active, so remove the class.
1190
- var active = scope_Base.getElementsByClassName(Classes[15]),
1191
- handleNumber = data.handles[0] === scope_Handles[0] ? 0 : 1;
1192
-
1193
- if ( active.length ) {
1194
- removeClass(active[0], Classes[15]);
1195
- }
1196
-
1197
- // Remove cursor styles and text-selection events bound to the body.
1198
- if ( event.cursor ) {
1199
- document.body.style.cursor = '';
1200
- document.body.removeEventListener('selectstart', document.body.noUiListener);
1201
- }
1202
-
1203
- var d = document.documentElement;
1204
-
1205
- // Unbind the move and end events, which are added on 'start'.
1206
- d.noUiListeners.forEach(function( c ) {
1207
- d.removeEventListener(c[0], c[1]);
1208
- });
1209
-
1210
- // Remove dragging class.
1211
- removeClass(scope_Target, Classes[12]);
1212
-
1213
- // Fire the change and set events.
1214
- fireEvent('set', handleNumber);
1215
- fireEvent('change', handleNumber);
1216
- }
1217
-
1218
- // Bind move events on document.
1219
- function start ( event, data ) {
1220
-
1221
- var d = document.documentElement;
1222
-
1223
- // Mark the handle as 'active' so it can be styled.
1224
- if ( data.handles.length === 1 ) {
1225
- addClass(data.handles[0].children[0], Classes[15]);
1226
-
1227
- // Support 'disabled' handles
1228
- if ( data.handles[0].hasAttribute('disabled') ) {
1229
- return false;
1230
- }
1231
- }
1232
-
1233
- // A drag should never propagate up to the 'tap' event.
1234
- event.stopPropagation();
1235
-
1236
- // Attach the move and end events.
1237
- var moveEvent = attach(actions.move, d, move, {
1238
- start: event.calcPoint,
1239
- handles: data.handles,
1240
- positions: [
1241
- scope_Locations[0],
1242
- scope_Locations[scope_Handles.length - 1]
1243
- ]
1244
- }), endEvent = attach(actions.end, d, end, {
1245
- handles: data.handles
1246
- });
1247
-
1248
- d.noUiListeners = moveEvent.concat(endEvent);
1249
-
1250
- // Text selection isn't an issue on touch devices,
1251
- // so adding cursor styles can be skipped.
1252
- if ( event.cursor ) {
1253
-
1254
- // Prevent the 'I' cursor and extend the range-drag cursor.
1255
- document.body.style.cursor = getComputedStyle(event.target).cursor;
1256
-
1257
- // Mark the target with a dragging state.
1258
- if ( scope_Handles.length > 1 ) {
1259
- addClass(scope_Target, Classes[12]);
1260
- }
1261
-
1262
- var f = function(){
1263
- return false;
1264
- };
1265
-
1266
- document.body.noUiListener = f;
1267
-
1268
- // Prevent text selection when dragging the handles.
1269
- document.body.addEventListener('selectstart', f, false);
1270
- }
1271
- }
1272
-
1273
- // Move closest handle to tapped location.
1274
- function tap ( event ) {
1275
-
1276
- var location = event.calcPoint, total = 0, handleNumber, to;
1277
-
1278
- // The tap event shouldn't propagate up and cause 'edge' to run.
1279
- event.stopPropagation();
1280
-
1281
- // Add up the handle offsets.
1282
- scope_Handles.forEach(function(a){
1283
- total += offset(a)[ options.style ];
1284
- });
1285
-
1286
- // Find the handle closest to the tapped position.
1287
- handleNumber = ( location < total/2 || scope_Handles.length === 1 ) ? 0 : 1;
1288
-
1289
- location -= offset(scope_Base)[ options.style ];
1290
-
1291
- // Calculate the new position.
1292
- to = ( location * 100 ) / baseSize();
1293
-
1294
- if ( !options.events.snap ) {
1295
- // Flag the slider as it is now in a transitional state.
1296
- // Transition takes 300 ms, so re-enable the slider afterwards.
1297
- addClassFor( scope_Target, Classes[14], 300 );
1298
- }
1299
-
1300
- // Support 'disabled' handles
1301
- if ( scope_Handles[handleNumber].hasAttribute('disabled') ) {
1302
- return false;
1303
- }
1304
-
1305
- // Find the closest handle and calculate the tapped point.
1306
- // The set handle to the new position.
1307
- setHandle( scope_Handles[handleNumber], to );
1308
-
1309
- fireEvent('slide', handleNumber);
1310
- fireEvent('set', handleNumber);
1311
- fireEvent('change', handleNumber);
1312
-
1313
- if ( options.events.snap ) {
1314
- start(event, { handles: [scope_Handles[total]] });
1315
- }
1316
- }
1317
-
1318
- // Attach events to several slider parts.
1319
- function events ( behaviour ) {
1320
-
1321
- var i, drag;
1322
-
1323
- // Attach the standard drag event to the handles.
1324
- if ( !behaviour.fixed ) {
1325
-
1326
- for ( i = 0; i < scope_Handles.length; i += 1 ) {
1327
-
1328
- // These events are only bound to the visual handle
1329
- // element, not the 'real' origin element.
1330
- attach ( actions.start, scope_Handles[i].children[0], start, {
1331
- handles: [ scope_Handles[i] ]
1332
- });
1333
- }
1334
- }
1335
-
1336
- // Attach the tap event to the slider base.
1337
- if ( behaviour.tap ) {
1338
-
1339
- attach ( actions.start, scope_Base, tap, {
1340
- handles: scope_Handles
1341
- });
1342
- }
1343
-
1344
- // Make the range dragable.
1345
- if ( behaviour.drag ){
1346
-
1347
- drag = [scope_Base.getElementsByClassName( Classes[7] )[0]];
1348
- addClass(drag[0], Classes[10]);
1349
-
1350
- // When the range is fixed, the entire range can
1351
- // be dragged by the handles. The handle in the first
1352
- // origin will propagate the start event upward,
1353
- // but it needs to be bound manually on the other.
1354
- if ( behaviour.fixed ) {
1355
- drag.push(scope_Handles[(drag[0] === scope_Handles[0] ? 1 : 0)].children[0]);
1356
- }
1357
-
1358
- drag.forEach(function( element ) {
1359
- attach ( actions.start, element, start, {
1360
- handles: scope_Handles
1361
- });
1362
- });
1363
- }
1364
- }
1365
-
1366
-
1367
- // Test suggested values and apply margin, step.
1368
- function setHandle ( handle, to, noLimitOption ) {
1369
-
1370
- var trigger = handle !== scope_Handles[0] ? 1 : 0,
1371
- lowerMargin = scope_Locations[0] + options.margin,
1372
- upperMargin = scope_Locations[1] - options.margin,
1373
- lowerLimit = scope_Locations[0] + options.limit,
1374
- upperLimit = scope_Locations[1] - options.limit;
1375
-
1376
- // For sliders with multiple handles,
1377
- // limit movement to the other handle.
1378
- // Apply the margin option by adding it to the handle positions.
1379
- if ( scope_Handles.length > 1 ) {
1380
- to = trigger ? Math.max( to, lowerMargin ) : Math.min( to, upperMargin );
1381
- }
1382
-
1383
- // The limit option has the opposite effect, limiting handles to a
1384
- // maximum distance from another. Limit must be > 0, as otherwise
1385
- // handles would be unmoveable. 'noLimitOption' is set to 'false'
1386
- // for the .val() method, except for pass 4/4.
1387
- if ( noLimitOption !== false && options.limit && scope_Handles.length > 1 ) {
1388
- to = trigger ? Math.min ( to, lowerLimit ) : Math.max( to, upperLimit );
1389
- }
1390
-
1391
- // Handle the step option.
1392
- to = scope_Spectrum.getStep( to );
1393
-
1394
- // Limit to 0/100 for .val input, trim anything beyond 7 digits, as
1395
- // JavaScript has some issues in its floating point implementation.
1396
- to = limit(parseFloat(to.toFixed(7)));
1397
-
1398
- // Return false if handle can't move.
1399
- if ( to === scope_Locations[trigger] ) {
1400
- return false;
1401
- }
1402
-
1403
- // Set the handle to the new position.
1404
- handle.style[options.style] = to + '%';
1405
-
1406
- // Force proper handle stacking
1407
- if ( !handle.previousSibling ) {
1408
- removeClass(handle, Classes[17]);
1409
- if ( to > 50 ) {
1410
- addClass(handle, Classes[17]);
1411
- }
1412
- }
1413
-
1414
- // Update locations.
1415
- scope_Locations[trigger] = to;
1416
-
1417
- // Convert the value to the slider stepping/range.
1418
- scope_Values[trigger] = scope_Spectrum.fromStepping( to );
1419
-
1420
- fireEvent('update', trigger);
1421
-
1422
- return true;
1423
- }
1424
-
1425
- // Loop values from value method and apply them.
1426
- function setValues ( count, values ) {
1427
-
1428
- var i, trigger, to;
1429
-
1430
- // With the limit option, we'll need another limiting pass.
1431
- if ( options.limit ) {
1432
- count += 1;
1433
- }
1434
-
1435
- // If there are multiple handles to be set run the setting
1436
- // mechanism twice for the first handle, to make sure it
1437
- // can be bounced of the second one properly.
1438
- for ( i = 0; i < count; i += 1 ) {
1439
-
1440
- trigger = i%2;
1441
-
1442
- // Get the current argument from the array.
1443
- to = values[trigger];
1444
-
1445
- // Setting with null indicates an 'ignore'.
1446
- // Inputting 'false' is invalid.
1447
- if ( to !== null && to !== false ) {
1448
-
1449
- // If a formatted number was passed, attemt to decode it.
1450
- if ( typeof to === 'number' ) {
1451
- to = String(to);
1452
- }
1453
-
1454
- to = options.format.from( to );
1455
-
1456
- // Request an update for all links if the value was invalid.
1457
- // Do so too if setting the handle fails.
1458
- if ( to === false || isNaN(to) || setHandle( scope_Handles[trigger], scope_Spectrum.toStepping( to ), i === (3 - options.dir) ) === false ) {
1459
- fireEvent('update', trigger);
1460
- }
1461
- }
1462
- }
1463
- }
1464
-
1465
- // Set the slider value.
1466
- function valueSet ( input ) {
1467
-
1468
- var count, values = asArray( input ), i;
1469
-
1470
- // The RTL settings is implemented by reversing the front-end,
1471
- // internal mechanisms are the same.
1472
- if ( options.dir && options.handles > 1 ) {
1473
- values.reverse();
1474
- }
1475
-
1476
- // Animation is optional.
1477
- // Make sure the initial values where set before using animated placement.
1478
- if ( options.animate && scope_Locations[0] !== -1 ) {
1479
- addClassFor( scope_Target, Classes[14], 300 );
1480
- }
1481
-
1482
- // Determine how often to set the handles.
1483
- count = scope_Handles.length > 1 ? 3 : 1;
1484
-
1485
- if ( values.length === 1 ) {
1486
- count = 1;
1487
- }
1488
-
1489
- setValues ( count, values );
1490
-
1491
- // Fire the 'set' event for both handles.
1492
- for ( i = 0; i < scope_Handles.length; i++ ) {
1493
- fireEvent('set', i);
1494
- }
1495
- }
1496
-
1497
- // Get the slider value.
1498
- function valueGet ( ) {
1499
-
1500
- var i, retour = [];
1501
-
1502
- // Get the value from all handles.
1503
- for ( i = 0; i < options.handles; i += 1 ){
1504
- retour[i] = options.format.to( scope_Values[i] );
1505
- }
1506
-
1507
- return inSliderOrder( retour );
1508
- }
1509
-
1510
- // Removes classes from the root and empties it.
1511
- function destroy ( ) {
1512
- Classes.forEach(function(cls){
1513
- if ( !cls ) { return; } // Ignore empty classes
1514
- removeClass(scope_Target, cls);
1515
- });
1516
- scope_Target.innerHTML = '';
1517
- delete scope_Target.noUiSlider;
1518
- }
1519
-
1520
- // Get the current step size for the slider.
1521
- function getCurrentStep ( ) {
1522
-
1523
- // Check all locations, map them to their stepping point.
1524
- // Get the step point, then find it in the input list.
1525
- var retour = scope_Locations.map(function( location, index ){
1526
-
1527
- var step = scope_Spectrum.getApplicableStep( location ),
1528
-
1529
- // As per #391, the comparison for the decrement step can have some rounding issues.
1530
- // Round the value to the precision used in the step.
1531
- stepDecimals = countDecimals(String(step[2])),
1532
-
1533
- // Get the current numeric value
1534
- value = scope_Values[index],
1535
-
1536
- // To move the slider 'one step up', the current step value needs to be added.
1537
- // Use null if we are at the maximum slider value.
1538
- increment = location === 100 ? null : step[2],
1539
-
1540
- // Going 'one step down' might put the slider in a different sub-range, so we
1541
- // need to switch between the current or the previous step.
1542
- prev = Number((value - step[2]).toFixed(stepDecimals)),
1543
-
1544
- // If the value fits the step, return the current step value. Otherwise, use the
1545
- // previous step. Return null if the slider is at its minimum value.
1546
- decrement = location === 0 ? null : (prev >= step[1]) ? step[2] : (step[0] || false);
1547
-
1548
- return [decrement, increment];
1549
- });
1550
-
1551
- // Return values in the proper order.
1552
- return inSliderOrder( retour );
1553
- }
1554
-
1555
- // Attach an event to this slider, possibly including a namespace
1556
- function bindEvent ( namespacedEvent, callback ) {
1557
- scope_Events[namespacedEvent] = scope_Events[namespacedEvent] || [];
1558
- scope_Events[namespacedEvent].push(callback);
1559
-
1560
- // If the event bound is 'update,' fire it immediately for all handles.
1561
- if ( namespacedEvent.split('.')[0] === 'update' ) {
1562
- scope_Handles.forEach(function(a, index){
1563
- fireEvent('update', index);
1564
- });
1565
- }
1566
- }
1567
-
1568
- // Undo attachment of event
1569
- function removeEvent ( namespacedEvent ) {
1570
-
1571
- var event = namespacedEvent.split('.')[0],
1572
- namespace = namespacedEvent.substring(event.length);
1573
-
1574
- Object.keys(scope_Events).forEach(function( bind ){
1575
-
1576
- var tEvent = bind.split('.')[0],
1577
- tNamespace = bind.substring(tEvent.length);
1578
-
1579
- if ( (!event || event === tEvent) && (!namespace || namespace === tNamespace) ) {
1580
- delete scope_Events[bind];
1581
- }
1582
- });
1583
- }
1584
-
1585
-
1586
- // Throw an error if the slider was already initialized.
1587
- if ( scope_Target.noUiSlider ) {
1588
- throw new Error('Slider was already initialized.');
1589
- }
1590
-
1591
-
1592
- // Create the base element, initialise HTML and set classes.
1593
- // Add handles and links.
1594
- scope_Base = addSlider( options.dir, options.ort, scope_Target );
1595
- scope_Handles = addHandles( options.handles, options.dir, scope_Base );
1596
-
1597
- // Set the connect classes.
1598
- addConnection ( options.connect, scope_Target, scope_Handles );
1599
-
1600
- // Attach user events.
1601
- events( options.events );
1602
-
1603
- if ( options.pips ) {
1604
- pips(options.pips);
1605
- }
1606
-
1607
- return {
1608
- destroy: destroy,
1609
- steps: getCurrentStep,
1610
- on: bindEvent,
1611
- off: removeEvent,
1612
- get: valueGet,
1613
- set: valueSet
1614
- };
1615
-
1616
- }
1617
-
1618
-
1619
- // Run the standard initializer
1620
- function initialize ( target, originalOptions ) {
1621
-
1622
- if ( !target.nodeName ) {
1623
- throw new Error('noUiSlider.create requires a single element.');
1624
- }
1625
-
1626
- // Test the options and create the slider environment;
1627
- var options = testOptions( originalOptions, target ),
1628
- slider = closure( target, options );
1629
-
1630
- // Use the public value method to set the start values.
1631
- slider.set(options.start);
1632
-
1633
- target.noUiSlider = slider;
1634
-
1635
- if (originalOptions.tooltips === true || originalOptions.tooltips === undefined) {
1636
- // Tooltips
1637
- var tipHandles = target.getElementsByClassName('noUi-handle'),
1638
- tooltips = [];
1639
-
1640
- // Add divs to the slider handles.
1641
- for ( var i = 0; i < tipHandles.length; i++ ){
1642
- tooltips[i] = document.createElement('div');
1643
- tipHandles[i].appendChild(tooltips[i]);
1644
- // Add a class for styling
1645
- tooltips[i].className += 'range-label';
1646
- // Add additional markup
1647
- tooltips[i].innerHTML = '<span></span>';
1648
- // Replace the tooltip reference with the span we just added
1649
- tooltips[i] = tooltips[i].getElementsByTagName('span')[0];
1650
- }
1651
-
1652
-
1653
- // When the slider changes, write the value to the tooltips.
1654
- target.noUiSlider.on('update', function( values, handle ){
1655
-
1656
- tooltips[handle].innerHTML = values[handle];
1657
- });
1658
- }
1659
- }
1660
-
1661
- // Use an object instead of a function for future expansibility;
1662
- return {
1663
- create: initialize
1664
- };
1665
-
1666
- }));