phcthemes_web_theme_pack 4.0.0 → 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/themes/antlr/theme/bootstrap.min.js +7 -0
  3. data/app/assets/javascripts/themes/antlr/theme/covervid.min.js +1 -0
  4. data/app/assets/javascripts/themes/antlr/theme/custom.js +1 -0
  5. data/app/assets/javascripts/themes/antlr/theme/filter.js +64 -0
  6. data/app/assets/javascripts/themes/antlr/theme/gdpr-cookie.js +43 -0
  7. data/app/assets/javascripts/themes/antlr/theme/isotope.min.js +5 -5
  8. data/app/assets/javascripts/themes/antlr/theme/jquery.circliful.min.js +92 -0
  9. data/app/assets/javascripts/themes/antlr/theme/jquery.countdown.js +17 -0
  10. data/app/assets/javascripts/themes/antlr/theme/jquery.min.js +2 -0
  11. data/app/assets/javascripts/themes/antlr/theme/jquery.viewportchecker.min.js +1 -0
  12. data/app/assets/javascripts/themes/antlr/theme/lazysizes.min.js +3 -2
  13. data/app/assets/javascripts/themes/antlr/theme/lib/i18next.min.js +3 -0
  14. data/app/assets/javascripts/themes/antlr/theme/lib/i18nextXHRBackend.min.js +1 -0
  15. data/app/assets/javascripts/themes/antlr/theme/lib/jquery-i18next.min.js +1 -0
  16. data/app/assets/javascripts/themes/antlr/theme/mixevents.js +104 -0
  17. data/app/assets/javascripts/themes/antlr/theme/mixitup.min.js +18 -0
  18. data/app/assets/javascripts/themes/antlr/theme/mixitup.multifilter.min.js +18 -0
  19. data/app/assets/javascripts/themes/antlr/theme/modernizr.js +3 -0
  20. data/app/assets/javascripts/themes/antlr/theme/nouislider.js +2514 -0
  21. data/app/assets/javascripts/themes/antlr/theme/popper.min.js +5 -0
  22. data/app/assets/javascripts/themes/antlr/theme/scripts.js +99 -108
  23. data/app/assets/javascripts/themes/antlr/theme/scripts.min.js +1 -0
  24. data/app/assets/javascripts/themes/antlr/theme/swiper.min.js +4 -4
  25. data/app/assets/javascripts/themes/antlr/theme/variables.js +25 -0
  26. data/app/assets/stylesheets/phcthemes_web_theme_pack_antlr.scss +5 -5
  27. data/app/assets/stylesheets/themes/antlr/css/style.css +13 -2
  28. data/app/assets/stylesheets/themes/antlr/img/logo-light.svg +11 -11
  29. data/app/assets/stylesheets/themes/antlr/img/topbanner17.jpg +0 -0
  30. data/app/assets/stylesheets/themes/antlr/locales/de-DE/translations.json +6 -0
  31. data/app/assets/stylesheets/themes/antlr/locales/de/translations.json +0 -0
  32. data/app/assets/stylesheets/themes/antlr/locales/dev/translations.json +0 -0
  33. data/app/assets/stylesheets/themes/antlr/locales/en-US/translations.json +63 -0
  34. data/app/assets/stylesheets/themes/antlr/locales/en/translations.json +0 -0
  35. data/app/assets/stylesheets/themes/antlr/locales/pt-PT/translations.json +63 -0
  36. data/app/assets/stylesheets/themes/antlr/locales/pt/translations.json +0 -0
  37. data/app/assets/stylesheets/themes/antlr/patterns/blackfriday25.svg +1479 -0
  38. data/app/assets/stylesheets/themes/antlr/patterns/cybermonday.svg +1411 -0
  39. data/app/assets/stylesheets/themes/antlr/patterns/ssd.svg +140 -73
  40. data/lib/phcthemes_web_theme_pack/version.rb +1 -1
  41. metadata +31 -2
@@ -0,0 +1,3 @@
1
+ /*! modernizr 3.6.0 (Custom Build) | MIT *
2
+ * https://modernizr.com/download/?-setclasses !*/
3
+ !function(n,e,s){function o(n,e){return typeof n===e}function a(){var n,e,s,a,i,l,r;for(var c in f)if(f.hasOwnProperty(c)){if(n=[],e=f[c],e.name&&(n.push(e.name.toLowerCase()),e.options&&e.options.aliases&&e.options.aliases.length))for(s=0;s<e.options.aliases.length;s++)n.push(e.options.aliases[s].toLowerCase());for(a=o(e.fn,"function")?e.fn():e.fn,i=0;i<n.length;i++)l=n[i],r=l.split("."),1===r.length?Modernizr[r[0]]=a:(!Modernizr[r[0]]||Modernizr[r[0]]instanceof Boolean||(Modernizr[r[0]]=new Boolean(Modernizr[r[0]])),Modernizr[r[0]][r[1]]=a),t.push((a?"":"no-")+r.join("-"))}}function i(n){var e=r.className,s=Modernizr._config.classPrefix||"";if(c&&(e=e.baseVal),Modernizr._config.enableJSClass){var o=new RegExp("(^|\\s)"+s+"no-js(\\s|$)");e=e.replace(o,"$1"+s+"js$2")}Modernizr._config.enableClasses&&(e+=" "+s+n.join(" "+s),c?r.className.baseVal=e:r.className=e)}var t=[],f=[],l={_version:"3.6.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(n,e){var s=this;setTimeout(function(){e(s[n])},0)},addTest:function(n,e,s){f.push({name:n,fn:e,options:s})},addAsyncTest:function(n){f.push({name:null,fn:n})}},Modernizr=function(){};Modernizr.prototype=l,Modernizr=new Modernizr;var r=e.documentElement,c="svg"===r.nodeName.toLowerCase();a(),i(t),delete l.addTest,delete l.addAsyncTest;for(var u=0;u<Modernizr._q.length;u++)Modernizr._q[u]();n.Modernizr=Modernizr}(window,document);
@@ -0,0 +1,2514 @@
1
+ /*! nouislider - 14.1.1 - 12/15/2019 */
2
+ (function(factory) {
3
+ if (typeof define === "function" && define.amd) {
4
+ // AMD. Register as an anonymous module.
5
+ define([], factory);
6
+ } else if (typeof exports === "object") {
7
+ // Node/CommonJS
8
+ module.exports = factory();
9
+ } else {
10
+ // Browser globals
11
+ window.noUiSlider = factory();
12
+ }
13
+ })(function() {
14
+ "use strict";
15
+
16
+ var VERSION = "14.1.1";
17
+
18
+ //region Helper Methods
19
+
20
+ function isValidFormatter(entry) {
21
+ return typeof entry === "object" && typeof entry.to === "function" && typeof entry.from === "function";
22
+ }
23
+
24
+ function removeElement(el) {
25
+ el.parentElement.removeChild(el);
26
+ }
27
+
28
+ function isSet(value) {
29
+ return value !== null && value !== undefined;
30
+ }
31
+
32
+ // Bindable version
33
+ function preventDefault(e) {
34
+ e.preventDefault();
35
+ }
36
+
37
+ // Removes duplicates from an array.
38
+ function unique(array) {
39
+ return array.filter(function(a) {
40
+ return !this[a] ? (this[a] = true) : false;
41
+ }, {});
42
+ }
43
+
44
+ // Round a value to the closest 'to'.
45
+ function closest(value, to) {
46
+ return Math.round(value / to) * to;
47
+ }
48
+
49
+ // Current position of an element relative to the document.
50
+ function offset(elem, orientation) {
51
+ var rect = elem.getBoundingClientRect();
52
+ var doc = elem.ownerDocument;
53
+ var docElem = doc.documentElement;
54
+ var pageOffset = getPageOffset(doc);
55
+
56
+ // getBoundingClientRect contains left scroll in Chrome on Android.
57
+ // I haven't found a feature detection that proves this. Worst case
58
+ // scenario on mis-match: the 'tap' feature on horizontal sliders breaks.
59
+ if (/webkit.*Chrome.*Mobile/i.test(navigator.userAgent)) {
60
+ pageOffset.x = 0;
61
+ }
62
+
63
+ return orientation
64
+ ? rect.top + pageOffset.y - docElem.clientTop
65
+ : rect.left + pageOffset.x - docElem.clientLeft;
66
+ }
67
+
68
+ // Checks whether a value is numerical.
69
+ function isNumeric(a) {
70
+ return typeof a === "number" && !isNaN(a) && isFinite(a);
71
+ }
72
+
73
+ // Sets a class and removes it after [duration] ms.
74
+ function addClassFor(element, className, duration) {
75
+ if (duration > 0) {
76
+ addClass(element, className);
77
+ setTimeout(function() {
78
+ removeClass(element, className);
79
+ }, duration);
80
+ }
81
+ }
82
+
83
+ // Limits a value to 0 - 100
84
+ function limit(a) {
85
+ return Math.max(Math.min(a, 100), 0);
86
+ }
87
+
88
+ // Wraps a variable as an array, if it isn't one yet.
89
+ // Note that an input array is returned by reference!
90
+ function asArray(a) {
91
+ return Array.isArray(a) ? a : [a];
92
+ }
93
+
94
+ // Counts decimals
95
+ function countDecimals(numStr) {
96
+ numStr = String(numStr);
97
+ var pieces = numStr.split(".");
98
+ return pieces.length > 1 ? pieces[1].length : 0;
99
+ }
100
+
101
+ // http://youmightnotneedjquery.com/#add_class
102
+ function addClass(el, className) {
103
+ if (el.classList) {
104
+ el.classList.add(className);
105
+ } else {
106
+ el.className += " " + className;
107
+ }
108
+ }
109
+
110
+ // http://youmightnotneedjquery.com/#remove_class
111
+ function removeClass(el, className) {
112
+ if (el.classList) {
113
+ el.classList.remove(className);
114
+ } else {
115
+ el.className = el.className.replace(
116
+ new RegExp("(^|\\b)" + className.split(" ").join("|") + "(\\b|$)", "gi"),
117
+ " "
118
+ );
119
+ }
120
+ }
121
+
122
+ // https://plainjs.com/javascript/attributes/adding-removing-and-testing-for-classes-9/
123
+ function hasClass(el, className) {
124
+ return el.classList
125
+ ? el.classList.contains(className)
126
+ : new RegExp("\\b" + className + "\\b").test(el.className);
127
+ }
128
+
129
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes
130
+ function getPageOffset(doc) {
131
+ var supportPageOffset = window.pageXOffset !== undefined;
132
+ var isCSS1Compat = (doc.compatMode || "") === "CSS1Compat";
133
+ var x = supportPageOffset
134
+ ? window.pageXOffset
135
+ : isCSS1Compat
136
+ ? doc.documentElement.scrollLeft
137
+ : doc.body.scrollLeft;
138
+ var y = supportPageOffset
139
+ ? window.pageYOffset
140
+ : isCSS1Compat
141
+ ? doc.documentElement.scrollTop
142
+ : doc.body.scrollTop;
143
+
144
+ return {
145
+ x: x,
146
+ y: y
147
+ };
148
+ }
149
+
150
+ // we provide a function to compute constants instead
151
+ // of accessing window.* as soon as the module needs it
152
+ // so that we do not compute anything if not needed
153
+ function getActions() {
154
+ // Determine the events to bind. IE11 implements pointerEvents without
155
+ // a prefix, which breaks compatibility with the IE10 implementation.
156
+ return window.navigator.pointerEnabled
157
+ ? {
158
+ start: "pointerdown",
159
+ move: "pointermove",
160
+ end: "pointerup"
161
+ }
162
+ : window.navigator.msPointerEnabled
163
+ ? {
164
+ start: "MSPointerDown",
165
+ move: "MSPointerMove",
166
+ end: "MSPointerUp"
167
+ }
168
+ : {
169
+ start: "mousedown touchstart",
170
+ move: "mousemove touchmove",
171
+ end: "mouseup touchend"
172
+ };
173
+ }
174
+
175
+ // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
176
+ // Issue #785
177
+ function getSupportsPassive() {
178
+ var supportsPassive = false;
179
+
180
+ /* eslint-disable */
181
+ try {
182
+ var opts = Object.defineProperty({}, "passive", {
183
+ get: function() {
184
+ supportsPassive = true;
185
+ }
186
+ });
187
+
188
+ window.addEventListener("test", null, opts);
189
+ } catch (e) {}
190
+ /* eslint-enable */
191
+
192
+ return supportsPassive;
193
+ }
194
+
195
+ function getSupportsTouchActionNone() {
196
+ return window.CSS && CSS.supports && CSS.supports("touch-action", "none");
197
+ }
198
+
199
+ //endregion
200
+
201
+ //region Range Calculation
202
+
203
+ // Determine the size of a sub-range in relation to a full range.
204
+ function subRangeRatio(pa, pb) {
205
+ return 100 / (pb - pa);
206
+ }
207
+
208
+ // (percentage) How many percent is this value of this range?
209
+ function fromPercentage(range, value) {
210
+ return (value * 100) / (range[1] - range[0]);
211
+ }
212
+
213
+ // (percentage) Where is this value on this range?
214
+ function toPercentage(range, value) {
215
+ return fromPercentage(range, range[0] < 0 ? value + Math.abs(range[0]) : value - range[0]);
216
+ }
217
+
218
+ // (value) How much is this percentage on this range?
219
+ function isPercentage(range, value) {
220
+ return (value * (range[1] - range[0])) / 100 + range[0];
221
+ }
222
+
223
+ function getJ(value, arr) {
224
+ var j = 1;
225
+
226
+ while (value >= arr[j]) {
227
+ j += 1;
228
+ }
229
+
230
+ return j;
231
+ }
232
+
233
+ // (percentage) Input a value, find where, on a scale of 0-100, it applies.
234
+ function toStepping(xVal, xPct, value) {
235
+ if (value >= xVal.slice(-1)[0]) {
236
+ return 100;
237
+ }
238
+
239
+ var j = getJ(value, xVal);
240
+ var va = xVal[j - 1];
241
+ var vb = xVal[j];
242
+ var pa = xPct[j - 1];
243
+ var pb = xPct[j];
244
+
245
+ return pa + toPercentage([va, vb], value) / subRangeRatio(pa, pb);
246
+ }
247
+
248
+ // (value) Input a percentage, find where it is on the specified range.
249
+ function fromStepping(xVal, xPct, value) {
250
+ // There is no range group that fits 100
251
+ if (value >= 100) {
252
+ return xVal.slice(-1)[0];
253
+ }
254
+
255
+ var j = getJ(value, xPct);
256
+ var va = xVal[j - 1];
257
+ var vb = xVal[j];
258
+ var pa = xPct[j - 1];
259
+ var pb = xPct[j];
260
+
261
+ return isPercentage([va, vb], (value - pa) * subRangeRatio(pa, pb));
262
+ }
263
+
264
+ // (percentage) Get the step that applies at a certain value.
265
+ function getStep(xPct, xSteps, snap, value) {
266
+ if (value === 100) {
267
+ return value;
268
+ }
269
+
270
+ var j = getJ(value, xPct);
271
+ var a = xPct[j - 1];
272
+ var b = xPct[j];
273
+
274
+ // If 'snap' is set, steps are used as fixed points on the slider.
275
+ if (snap) {
276
+ // Find the closest position, a or b.
277
+ if (value - a > (b - a) / 2) {
278
+ return b;
279
+ }
280
+
281
+ return a;
282
+ }
283
+
284
+ if (!xSteps[j - 1]) {
285
+ return value;
286
+ }
287
+
288
+ return xPct[j - 1] + closest(value - xPct[j - 1], xSteps[j - 1]);
289
+ }
290
+
291
+ function handleEntryPoint(index, value, that) {
292
+ var percentage;
293
+
294
+ // Wrap numerical input in an array.
295
+ if (typeof value === "number") {
296
+ value = [value];
297
+ }
298
+
299
+ // Reject any invalid input, by testing whether value is an array.
300
+ if (!Array.isArray(value)) {
301
+ throw new Error("noUiSlider (" + VERSION + "): 'range' contains invalid value.");
302
+ }
303
+
304
+ // Covert min/max syntax to 0 and 100.
305
+ if (index === "min") {
306
+ percentage = 0;
307
+ } else if (index === "max") {
308
+ percentage = 100;
309
+ } else {
310
+ percentage = parseFloat(index);
311
+ }
312
+
313
+ // Check for correct input.
314
+ if (!isNumeric(percentage) || !isNumeric(value[0])) {
315
+ throw new Error("noUiSlider (" + VERSION + "): 'range' value isn't numeric.");
316
+ }
317
+
318
+ // Store values.
319
+ that.xPct.push(percentage);
320
+ that.xVal.push(value[0]);
321
+
322
+ // NaN will evaluate to false too, but to keep
323
+ // logging clear, set step explicitly. Make sure
324
+ // not to override the 'step' setting with false.
325
+ if (!percentage) {
326
+ if (!isNaN(value[1])) {
327
+ that.xSteps[0] = value[1];
328
+ }
329
+ } else {
330
+ that.xSteps.push(isNaN(value[1]) ? false : value[1]);
331
+ }
332
+
333
+ that.xHighestCompleteStep.push(0);
334
+ }
335
+
336
+ function handleStepPoint(i, n, that) {
337
+ // Ignore 'false' stepping.
338
+ if (!n) {
339
+ return;
340
+ }
341
+
342
+ // Step over zero-length ranges (#948);
343
+ if (that.xVal[i] === that.xVal[i + 1]) {
344
+ that.xSteps[i] = that.xHighestCompleteStep[i] = that.xVal[i];
345
+
346
+ return;
347
+ }
348
+
349
+ // Factor to range ratio
350
+ that.xSteps[i] =
351
+ fromPercentage([that.xVal[i], that.xVal[i + 1]], n) / subRangeRatio(that.xPct[i], that.xPct[i + 1]);
352
+
353
+ var totalSteps = (that.xVal[i + 1] - that.xVal[i]) / that.xNumSteps[i];
354
+ var highestStep = Math.ceil(Number(totalSteps.toFixed(3)) - 1);
355
+ var step = that.xVal[i] + that.xNumSteps[i] * highestStep;
356
+
357
+ that.xHighestCompleteStep[i] = step;
358
+ }
359
+
360
+ //endregion
361
+
362
+ //region Spectrum
363
+
364
+ function Spectrum(entry, snap, singleStep) {
365
+ this.xPct = [];
366
+ this.xVal = [];
367
+ this.xSteps = [singleStep || false];
368
+ this.xNumSteps = [false];
369
+ this.xHighestCompleteStep = [];
370
+
371
+ this.snap = snap;
372
+
373
+ var index;
374
+ var ordered = []; // [0, 'min'], [1, '50%'], [2, 'max']
375
+
376
+ // Map the object keys to an array.
377
+ for (index in entry) {
378
+ if (entry.hasOwnProperty(index)) {
379
+ ordered.push([entry[index], index]);
380
+ }
381
+ }
382
+
383
+ // Sort all entries by value (numeric sort).
384
+ if (ordered.length && typeof ordered[0][0] === "object") {
385
+ ordered.sort(function(a, b) {
386
+ return a[0][0] - b[0][0];
387
+ });
388
+ } else {
389
+ ordered.sort(function(a, b) {
390
+ return a[0] - b[0];
391
+ });
392
+ }
393
+
394
+ // Convert all entries to subranges.
395
+ for (index = 0; index < ordered.length; index++) {
396
+ handleEntryPoint(ordered[index][1], ordered[index][0], this);
397
+ }
398
+
399
+ // Store the actual step values.
400
+ // xSteps is sorted in the same order as xPct and xVal.
401
+ this.xNumSteps = this.xSteps.slice(0);
402
+
403
+ // Convert all numeric steps to the percentage of the subrange they represent.
404
+ for (index = 0; index < this.xNumSteps.length; index++) {
405
+ handleStepPoint(index, this.xNumSteps[index], this);
406
+ }
407
+ }
408
+
409
+ Spectrum.prototype.getMargin = function(value) {
410
+ var step = this.xNumSteps[0];
411
+
412
+ if (step && (value / step) % 1 !== 0) {
413
+ throw new Error("noUiSlider (" + VERSION + "): 'limit', 'margin' and 'padding' must be divisible by step.");
414
+ }
415
+
416
+ return this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false;
417
+ };
418
+
419
+ Spectrum.prototype.toStepping = function(value) {
420
+ value = toStepping(this.xVal, this.xPct, value);
421
+
422
+ return value;
423
+ };
424
+
425
+ Spectrum.prototype.fromStepping = function(value) {
426
+ return fromStepping(this.xVal, this.xPct, value);
427
+ };
428
+
429
+ Spectrum.prototype.getStep = function(value) {
430
+ value = getStep(this.xPct, this.xSteps, this.snap, value);
431
+
432
+ return value;
433
+ };
434
+
435
+ Spectrum.prototype.getDefaultStep = function(value, isDown, size) {
436
+ var j = getJ(value, this.xPct);
437
+
438
+ // When at the top or stepping down, look at the previous sub-range
439
+ if (value === 100 || (isDown && value === this.xPct[j - 1])) {
440
+ j = Math.max(j - 1, 1);
441
+ }
442
+
443
+ return (this.xVal[j] - this.xVal[j - 1]) / size;
444
+ };
445
+
446
+ Spectrum.prototype.getNearbySteps = function(value) {
447
+ var j = getJ(value, this.xPct);
448
+
449
+ return {
450
+ stepBefore: {
451
+ startValue: this.xVal[j - 2],
452
+ step: this.xNumSteps[j - 2],
453
+ highestStep: this.xHighestCompleteStep[j - 2]
454
+ },
455
+ thisStep: {
456
+ startValue: this.xVal[j - 1],
457
+ step: this.xNumSteps[j - 1],
458
+ highestStep: this.xHighestCompleteStep[j - 1]
459
+ },
460
+ stepAfter: {
461
+ startValue: this.xVal[j],
462
+ step: this.xNumSteps[j],
463
+ highestStep: this.xHighestCompleteStep[j]
464
+ }
465
+ };
466
+ };
467
+
468
+ Spectrum.prototype.countStepDecimals = function() {
469
+ var stepDecimals = this.xNumSteps.map(countDecimals);
470
+ return Math.max.apply(null, stepDecimals);
471
+ };
472
+
473
+ // Outside testing
474
+ Spectrum.prototype.convert = function(value) {
475
+ return this.getStep(this.toStepping(value));
476
+ };
477
+
478
+ //endregion
479
+
480
+ //region Options
481
+
482
+ /* Every input option is tested and parsed. This'll prevent
483
+ endless validation in internal methods. These tests are
484
+ structured with an item for every option available. An
485
+ option can be marked as required by setting the 'r' flag.
486
+ The testing function is provided with three arguments:
487
+ - The provided value for the option;
488
+ - A reference to the options object;
489
+ - The name for the option;
490
+
491
+ The testing function returns false when an error is detected,
492
+ or true when everything is OK. It can also modify the option
493
+ object, to make sure all values can be correctly looped elsewhere. */
494
+
495
+ var defaultFormatter = {
496
+ to: function(value) {
497
+ return value !== undefined && value.toFixed(2);
498
+ },
499
+ from: Number
500
+ };
501
+
502
+ function validateFormat(entry) {
503
+ // Any object with a to and from method is supported.
504
+ if (isValidFormatter(entry)) {
505
+ return true;
506
+ }
507
+
508
+ throw new Error("noUiSlider (" + VERSION + "): 'format' requires 'to' and 'from' methods.");
509
+ }
510
+
511
+ function testStep(parsed, entry) {
512
+ if (!isNumeric(entry)) {
513
+ throw new Error("noUiSlider (" + VERSION + "): 'step' is not numeric.");
514
+ }
515
+
516
+ // The step option can still be used to set stepping
517
+ // for linear sliders. Overwritten if set in 'range'.
518
+ parsed.singleStep = entry;
519
+ }
520
+
521
+ function testRange(parsed, entry) {
522
+ // Filter incorrect input.
523
+ if (typeof entry !== "object" || Array.isArray(entry)) {
524
+ throw new Error("noUiSlider (" + VERSION + "): 'range' is not an object.");
525
+ }
526
+
527
+ // Catch missing start or end.
528
+ if (entry.min === undefined || entry.max === undefined) {
529
+ throw new Error("noUiSlider (" + VERSION + "): Missing 'min' or 'max' in 'range'.");
530
+ }
531
+
532
+ // Catch equal start or end.
533
+ if (entry.min === entry.max) {
534
+ throw new Error("noUiSlider (" + VERSION + "): 'range' 'min' and 'max' cannot be equal.");
535
+ }
536
+
537
+ parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.singleStep);
538
+ }
539
+
540
+ function testStart(parsed, entry) {
541
+ entry = asArray(entry);
542
+
543
+ // Validate input. Values aren't tested, as the public .val method
544
+ // will always provide a valid location.
545
+ if (!Array.isArray(entry) || !entry.length) {
546
+ throw new Error("noUiSlider (" + VERSION + "): 'start' option is incorrect.");
547
+ }
548
+
549
+ // Store the number of handles.
550
+ parsed.handles = entry.length;
551
+
552
+ // When the slider is initialized, the .val method will
553
+ // be called with the start options.
554
+ parsed.start = entry;
555
+ }
556
+
557
+ function testSnap(parsed, entry) {
558
+ // Enforce 100% stepping within subranges.
559
+ parsed.snap = entry;
560
+
561
+ if (typeof entry !== "boolean") {
562
+ throw new Error("noUiSlider (" + VERSION + "): 'snap' option must be a boolean.");
563
+ }
564
+ }
565
+
566
+ function testAnimate(parsed, entry) {
567
+ // Enforce 100% stepping within subranges.
568
+ parsed.animate = entry;
569
+
570
+ if (typeof entry !== "boolean") {
571
+ throw new Error("noUiSlider (" + VERSION + "): 'animate' option must be a boolean.");
572
+ }
573
+ }
574
+
575
+ function testAnimationDuration(parsed, entry) {
576
+ parsed.animationDuration = entry;
577
+
578
+ if (typeof entry !== "number") {
579
+ throw new Error("noUiSlider (" + VERSION + "): 'animationDuration' option must be a number.");
580
+ }
581
+ }
582
+
583
+ function testConnect(parsed, entry) {
584
+ var connect = [false];
585
+ var i;
586
+
587
+ // Map legacy options
588
+ if (entry === "lower") {
589
+ entry = [true, false];
590
+ } else if (entry === "upper") {
591
+ entry = [false, true];
592
+ }
593
+
594
+ // Handle boolean options
595
+ if (entry === true || entry === false) {
596
+ for (i = 1; i < parsed.handles; i++) {
597
+ connect.push(entry);
598
+ }
599
+
600
+ connect.push(false);
601
+ }
602
+
603
+ // Reject invalid input
604
+ else if (!Array.isArray(entry) || !entry.length || entry.length !== parsed.handles + 1) {
605
+ throw new Error("noUiSlider (" + VERSION + "): 'connect' option doesn't match handle count.");
606
+ } else {
607
+ connect = entry;
608
+ }
609
+
610
+ parsed.connect = connect;
611
+ }
612
+
613
+ function testOrientation(parsed, entry) {
614
+ // Set orientation to an a numerical value for easy
615
+ // array selection.
616
+ switch (entry) {
617
+ case "horizontal":
618
+ parsed.ort = 0;
619
+ break;
620
+ case "vertical":
621
+ parsed.ort = 1;
622
+ break;
623
+ default:
624
+ throw new Error("noUiSlider (" + VERSION + "): 'orientation' option is invalid.");
625
+ }
626
+ }
627
+
628
+ function testMargin(parsed, entry) {
629
+ if (!isNumeric(entry)) {
630
+ throw new Error("noUiSlider (" + VERSION + "): 'margin' option must be numeric.");
631
+ }
632
+
633
+ // Issue #582
634
+ if (entry === 0) {
635
+ return;
636
+ }
637
+
638
+ parsed.margin = parsed.spectrum.getMargin(entry);
639
+
640
+ if (!parsed.margin) {
641
+ throw new Error("noUiSlider (" + VERSION + "): 'margin' option is only supported on linear sliders.");
642
+ }
643
+ }
644
+
645
+ function testLimit(parsed, entry) {
646
+ if (!isNumeric(entry)) {
647
+ throw new Error("noUiSlider (" + VERSION + "): 'limit' option must be numeric.");
648
+ }
649
+
650
+ parsed.limit = parsed.spectrum.getMargin(entry);
651
+
652
+ if (!parsed.limit || parsed.handles < 2) {
653
+ throw new Error(
654
+ "noUiSlider (" +
655
+ VERSION +
656
+ "): 'limit' option is only supported on linear sliders with 2 or more handles."
657
+ );
658
+ }
659
+ }
660
+
661
+ function testPadding(parsed, entry) {
662
+ if (!isNumeric(entry) && !Array.isArray(entry)) {
663
+ throw new Error(
664
+ "noUiSlider (" + VERSION + "): 'padding' option must be numeric or array of exactly 2 numbers."
665
+ );
666
+ }
667
+
668
+ if (Array.isArray(entry) && !(entry.length === 2 || isNumeric(entry[0]) || isNumeric(entry[1]))) {
669
+ throw new Error(
670
+ "noUiSlider (" + VERSION + "): 'padding' option must be numeric or array of exactly 2 numbers."
671
+ );
672
+ }
673
+
674
+ if (entry === 0) {
675
+ return;
676
+ }
677
+
678
+ if (!Array.isArray(entry)) {
679
+ entry = [entry, entry];
680
+ }
681
+
682
+ // 'getMargin' returns false for invalid values.
683
+ parsed.padding = [parsed.spectrum.getMargin(entry[0]), parsed.spectrum.getMargin(entry[1])];
684
+
685
+ if (parsed.padding[0] === false || parsed.padding[1] === false) {
686
+ throw new Error("noUiSlider (" + VERSION + "): 'padding' option is only supported on linear sliders.");
687
+ }
688
+
689
+ if (parsed.padding[0] < 0 || parsed.padding[1] < 0) {
690
+ throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be a positive number(s).");
691
+ }
692
+
693
+ if (parsed.padding[0] + parsed.padding[1] > 100) {
694
+ throw new Error("noUiSlider (" + VERSION + "): 'padding' option must not exceed 100% of the range.");
695
+ }
696
+ }
697
+
698
+ function testDirection(parsed, entry) {
699
+ // Set direction as a numerical value for easy parsing.
700
+ // Invert connection for RTL sliders, so that the proper
701
+ // handles get the connect/background classes.
702
+ switch (entry) {
703
+ case "ltr":
704
+ parsed.dir = 0;
705
+ break;
706
+ case "rtl":
707
+ parsed.dir = 1;
708
+ break;
709
+ default:
710
+ throw new Error("noUiSlider (" + VERSION + "): 'direction' option was not recognized.");
711
+ }
712
+ }
713
+
714
+ function testBehaviour(parsed, entry) {
715
+ // Make sure the input is a string.
716
+ if (typeof entry !== "string") {
717
+ throw new Error("noUiSlider (" + VERSION + "): 'behaviour' must be a string containing options.");
718
+ }
719
+
720
+ // Check if the string contains any keywords.
721
+ // None are required.
722
+ var tap = entry.indexOf("tap") >= 0;
723
+ var drag = entry.indexOf("drag") >= 0;
724
+ var fixed = entry.indexOf("fixed") >= 0;
725
+ var snap = entry.indexOf("snap") >= 0;
726
+ var hover = entry.indexOf("hover") >= 0;
727
+ var unconstrained = entry.indexOf("unconstrained") >= 0;
728
+
729
+ if (fixed) {
730
+ if (parsed.handles !== 2) {
731
+ throw new Error("noUiSlider (" + VERSION + "): 'fixed' behaviour must be used with 2 handles");
732
+ }
733
+
734
+ // Use margin to enforce fixed state
735
+ testMargin(parsed, parsed.start[1] - parsed.start[0]);
736
+ }
737
+
738
+ if (unconstrained && (parsed.margin || parsed.limit)) {
739
+ throw new Error(
740
+ "noUiSlider (" + VERSION + "): 'unconstrained' behaviour cannot be used with margin or limit"
741
+ );
742
+ }
743
+
744
+ parsed.events = {
745
+ tap: tap || snap,
746
+ drag: drag,
747
+ fixed: fixed,
748
+ snap: snap,
749
+ hover: hover,
750
+ unconstrained: unconstrained
751
+ };
752
+ }
753
+
754
+ function testTooltips(parsed, entry) {
755
+ if (entry === false) {
756
+ return;
757
+ }
758
+
759
+ if (entry === true) {
760
+ parsed.tooltips = [];
761
+
762
+ for (var i = 0; i < parsed.handles; i++) {
763
+ parsed.tooltips.push(true);
764
+ }
765
+ } else {
766
+ parsed.tooltips = asArray(entry);
767
+
768
+ if (parsed.tooltips.length !== parsed.handles) {
769
+ throw new Error("noUiSlider (" + VERSION + "): must pass a formatter for all handles.");
770
+ }
771
+
772
+ parsed.tooltips.forEach(function(formatter) {
773
+ if (
774
+ typeof formatter !== "boolean" &&
775
+ (typeof formatter !== "object" || typeof formatter.to !== "function")
776
+ ) {
777
+ throw new Error("noUiSlider (" + VERSION + "): 'tooltips' must be passed a formatter or 'false'.");
778
+ }
779
+ });
780
+ }
781
+ }
782
+
783
+ function testAriaFormat(parsed, entry) {
784
+ parsed.ariaFormat = entry;
785
+ validateFormat(entry);
786
+ }
787
+
788
+ function testFormat(parsed, entry) {
789
+ parsed.format = entry;
790
+ validateFormat(entry);
791
+ }
792
+
793
+ function testKeyboardSupport(parsed, entry) {
794
+ parsed.keyboardSupport = entry;
795
+
796
+ if (typeof entry !== "boolean") {
797
+ throw new Error("noUiSlider (" + VERSION + "): 'keyboardSupport' option must be a boolean.");
798
+ }
799
+ }
800
+
801
+ function testDocumentElement(parsed, entry) {
802
+ // This is an advanced option. Passed values are used without validation.
803
+ parsed.documentElement = entry;
804
+ }
805
+
806
+ function testCssPrefix(parsed, entry) {
807
+ if (typeof entry !== "string" && entry !== false) {
808
+ throw new Error("noUiSlider (" + VERSION + "): 'cssPrefix' must be a string or `false`.");
809
+ }
810
+
811
+ parsed.cssPrefix = entry;
812
+ }
813
+
814
+ function testCssClasses(parsed, entry) {
815
+ if (typeof entry !== "object") {
816
+ throw new Error("noUiSlider (" + VERSION + "): 'cssClasses' must be an object.");
817
+ }
818
+
819
+ if (typeof parsed.cssPrefix === "string") {
820
+ parsed.cssClasses = {};
821
+
822
+ for (var key in entry) {
823
+ if (!entry.hasOwnProperty(key)) {
824
+ continue;
825
+ }
826
+
827
+ parsed.cssClasses[key] = parsed.cssPrefix + entry[key];
828
+ }
829
+ } else {
830
+ parsed.cssClasses = entry;
831
+ }
832
+ }
833
+
834
+ // Test all developer settings and parse to assumption-safe values.
835
+ function testOptions(options) {
836
+ // To prove a fix for #537, freeze options here.
837
+ // If the object is modified, an error will be thrown.
838
+ // Object.freeze(options);
839
+
840
+ var parsed = {
841
+ margin: 0,
842
+ limit: 0,
843
+ padding: 0,
844
+ animate: true,
845
+ animationDuration: 300,
846
+ ariaFormat: defaultFormatter,
847
+ format: defaultFormatter
848
+ };
849
+
850
+ // Tests are executed in the order they are presented here.
851
+ var tests = {
852
+ step: { r: false, t: testStep },
853
+ start: { r: true, t: testStart },
854
+ connect: { r: true, t: testConnect },
855
+ direction: { r: true, t: testDirection },
856
+ snap: { r: false, t: testSnap },
857
+ animate: { r: false, t: testAnimate },
858
+ animationDuration: { r: false, t: testAnimationDuration },
859
+ range: { r: true, t: testRange },
860
+ orientation: { r: false, t: testOrientation },
861
+ margin: { r: false, t: testMargin },
862
+ limit: { r: false, t: testLimit },
863
+ padding: { r: false, t: testPadding },
864
+ behaviour: { r: true, t: testBehaviour },
865
+ ariaFormat: { r: false, t: testAriaFormat },
866
+ format: { r: false, t: testFormat },
867
+ tooltips: { r: false, t: testTooltips },
868
+ keyboardSupport: { r: true, t: testKeyboardSupport },
869
+ documentElement: { r: false, t: testDocumentElement },
870
+ cssPrefix: { r: true, t: testCssPrefix },
871
+ cssClasses: { r: true, t: testCssClasses }
872
+ };
873
+
874
+ var defaults = {
875
+ connect: false,
876
+ direction: "ltr",
877
+ behaviour: "tap",
878
+ orientation: "horizontal",
879
+ keyboardSupport: true,
880
+ cssPrefix: "noUi-",
881
+ cssClasses: {
882
+ target: "target",
883
+ base: "base",
884
+ origin: "origin",
885
+ handle: "handle",
886
+ handleLower: "handle-lower",
887
+ handleUpper: "handle-upper",
888
+ touchArea: "touch-area",
889
+ horizontal: "horizontal",
890
+ vertical: "vertical",
891
+ background: "background",
892
+ connect: "connect",
893
+ connects: "connects",
894
+ ltr: "ltr",
895
+ rtl: "rtl",
896
+ textDirectionLtr: "txt-dir-ltr",
897
+ textDirectionRtl: "txt-dir-rtl",
898
+ draggable: "draggable",
899
+ drag: "state-drag",
900
+ tap: "state-tap",
901
+ active: "active",
902
+ tooltip: "tooltip",
903
+ pips: "pips",
904
+ pipsHorizontal: "pips-horizontal",
905
+ pipsVertical: "pips-vertical",
906
+ marker: "marker",
907
+ markerHorizontal: "marker-horizontal",
908
+ markerVertical: "marker-vertical",
909
+ markerNormal: "marker-normal",
910
+ markerLarge: "marker-large",
911
+ markerSub: "marker-sub",
912
+ value: "value",
913
+ valueHorizontal: "value-horizontal",
914
+ valueVertical: "value-vertical",
915
+ valueNormal: "value-normal",
916
+ valueLarge: "value-large",
917
+ valueSub: "value-sub"
918
+ }
919
+ };
920
+
921
+ // AriaFormat defaults to regular format, if any.
922
+ if (options.format && !options.ariaFormat) {
923
+ options.ariaFormat = options.format;
924
+ }
925
+
926
+ // Run all options through a testing mechanism to ensure correct
927
+ // input. It should be noted that options might get modified to
928
+ // be handled properly. E.g. wrapping integers in arrays.
929
+ Object.keys(tests).forEach(function(name) {
930
+ // If the option isn't set, but it is required, throw an error.
931
+ if (!isSet(options[name]) && defaults[name] === undefined) {
932
+ if (tests[name].r) {
933
+ throw new Error("noUiSlider (" + VERSION + "): '" + name + "' is required.");
934
+ }
935
+
936
+ return true;
937
+ }
938
+
939
+ tests[name].t(parsed, !isSet(options[name]) ? defaults[name] : options[name]);
940
+ });
941
+
942
+ // Forward pips options
943
+ parsed.pips = options.pips;
944
+
945
+ // All recent browsers accept unprefixed transform.
946
+ // We need -ms- for IE9 and -webkit- for older Android;
947
+ // Assume use of -webkit- if unprefixed and -ms- are not supported.
948
+ // https://caniuse.com/#feat=transforms2d
949
+ var d = document.createElement("div");
950
+ var msPrefix = d.style.msTransform !== undefined;
951
+ var noPrefix = d.style.transform !== undefined;
952
+
953
+ parsed.transformRule = noPrefix ? "transform" : msPrefix ? "msTransform" : "webkitTransform";
954
+
955
+ // Pips don't move, so we can place them using left/top.
956
+ var styles = [["left", "top"], ["right", "bottom"]];
957
+
958
+ parsed.style = styles[parsed.dir][parsed.ort];
959
+
960
+ return parsed;
961
+ }
962
+
963
+ //endregion
964
+
965
+ function scope(target, options, originalOptions) {
966
+ var actions = getActions();
967
+ var supportsTouchActionNone = getSupportsTouchActionNone();
968
+ var supportsPassive = supportsTouchActionNone && getSupportsPassive();
969
+
970
+ // All variables local to 'scope' are prefixed with 'scope_'
971
+
972
+ // Slider DOM Nodes
973
+ var scope_Target = target;
974
+ var scope_Base;
975
+ var scope_Handles;
976
+ var scope_Connects;
977
+ var scope_Pips;
978
+ var scope_Tooltips;
979
+
980
+ // Slider state values
981
+ var scope_Spectrum = options.spectrum;
982
+ var scope_Values = [];
983
+ var scope_Locations = [];
984
+ var scope_HandleNumbers = [];
985
+ var scope_ActiveHandlesCount = 0;
986
+ var scope_Events = {};
987
+
988
+ // Exposed API
989
+ var scope_Self;
990
+
991
+ // Document Nodes
992
+ var scope_Document = target.ownerDocument;
993
+ var scope_DocumentElement = options.documentElement || scope_Document.documentElement;
994
+ var scope_Body = scope_Document.body;
995
+
996
+ // Pips constants
997
+ var PIPS_NONE = -1;
998
+ var PIPS_NO_VALUE = 0;
999
+ var PIPS_LARGE_VALUE = 1;
1000
+ var PIPS_SMALL_VALUE = 2;
1001
+
1002
+ // For horizontal sliders in standard ltr documents,
1003
+ // make .noUi-origin overflow to the left so the document doesn't scroll.
1004
+ var scope_DirOffset = scope_Document.dir === "rtl" || options.ort === 1 ? 0 : 100;
1005
+
1006
+ // Creates a node, adds it to target, returns the new node.
1007
+ function addNodeTo(addTarget, className) {
1008
+ var div = scope_Document.createElement("div");
1009
+
1010
+ if (className) {
1011
+ addClass(div, className);
1012
+ }
1013
+
1014
+ addTarget.appendChild(div);
1015
+
1016
+ return div;
1017
+ }
1018
+
1019
+ // Append a origin to the base
1020
+ function addOrigin(base, handleNumber) {
1021
+ var origin = addNodeTo(base, options.cssClasses.origin);
1022
+ var handle = addNodeTo(origin, options.cssClasses.handle);
1023
+
1024
+ addNodeTo(handle, options.cssClasses.touchArea);
1025
+
1026
+ handle.setAttribute("data-handle", handleNumber);
1027
+
1028
+ if (options.keyboardSupport) {
1029
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
1030
+ // 0 = focusable and reachable
1031
+ handle.setAttribute("tabindex", "0");
1032
+ handle.addEventListener("keydown", function(event) {
1033
+ return eventKeydown(event, handleNumber);
1034
+ });
1035
+ }
1036
+
1037
+ handle.setAttribute("role", "slider");
1038
+ handle.setAttribute("aria-orientation", options.ort ? "vertical" : "horizontal");
1039
+
1040
+ if (handleNumber === 0) {
1041
+ addClass(handle, options.cssClasses.handleLower);
1042
+ } else if (handleNumber === options.handles - 1) {
1043
+ addClass(handle, options.cssClasses.handleUpper);
1044
+ }
1045
+
1046
+ return origin;
1047
+ }
1048
+
1049
+ // Insert nodes for connect elements
1050
+ function addConnect(base, add) {
1051
+ if (!add) {
1052
+ return false;
1053
+ }
1054
+
1055
+ return addNodeTo(base, options.cssClasses.connect);
1056
+ }
1057
+
1058
+ // Add handles to the slider base.
1059
+ function addElements(connectOptions, base) {
1060
+ var connectBase = addNodeTo(base, options.cssClasses.connects);
1061
+
1062
+ scope_Handles = [];
1063
+ scope_Connects = [];
1064
+
1065
+ scope_Connects.push(addConnect(connectBase, connectOptions[0]));
1066
+
1067
+ // [::::O====O====O====]
1068
+ // connectOptions = [0, 1, 1, 1]
1069
+
1070
+ for (var i = 0; i < options.handles; i++) {
1071
+ // Keep a list of all added handles.
1072
+ scope_Handles.push(addOrigin(base, i));
1073
+ scope_HandleNumbers[i] = i;
1074
+ scope_Connects.push(addConnect(connectBase, connectOptions[i + 1]));
1075
+ }
1076
+ }
1077
+
1078
+ // Initialize a single slider.
1079
+ function addSlider(addTarget) {
1080
+ // Apply classes and data to the target.
1081
+ addClass(addTarget, options.cssClasses.target);
1082
+
1083
+ if (options.dir === 0) {
1084
+ addClass(addTarget, options.cssClasses.ltr);
1085
+ } else {
1086
+ addClass(addTarget, options.cssClasses.rtl);
1087
+ }
1088
+
1089
+ if (options.ort === 0) {
1090
+ addClass(addTarget, options.cssClasses.horizontal);
1091
+ } else {
1092
+ addClass(addTarget, options.cssClasses.vertical);
1093
+ }
1094
+
1095
+ var textDirection = getComputedStyle(addTarget).direction;
1096
+
1097
+ if (textDirection === "rtl") {
1098
+ addClass(addTarget, options.cssClasses.textDirectionRtl);
1099
+ } else {
1100
+ addClass(addTarget, options.cssClasses.textDirectionLtr);
1101
+ }
1102
+
1103
+ return addNodeTo(addTarget, options.cssClasses.base);
1104
+ }
1105
+
1106
+ function addTooltip(handle, handleNumber) {
1107
+ if (!options.tooltips[handleNumber]) {
1108
+ return false;
1109
+ }
1110
+
1111
+ return addNodeTo(handle.firstChild, options.cssClasses.tooltip);
1112
+ }
1113
+
1114
+ function isSliderDisabled() {
1115
+ return scope_Target.hasAttribute("disabled");
1116
+ }
1117
+
1118
+ // Disable the slider dragging if any handle is disabled
1119
+ function isHandleDisabled(handleNumber) {
1120
+ var handleOrigin = scope_Handles[handleNumber];
1121
+ return handleOrigin.hasAttribute("disabled");
1122
+ }
1123
+
1124
+ function removeTooltips() {
1125
+ if (scope_Tooltips) {
1126
+ removeEvent("update.tooltips");
1127
+ scope_Tooltips.forEach(function(tooltip) {
1128
+ if (tooltip) {
1129
+ removeElement(tooltip);
1130
+ }
1131
+ });
1132
+ scope_Tooltips = null;
1133
+ }
1134
+ }
1135
+
1136
+ // The tooltips option is a shorthand for using the 'update' event.
1137
+ function tooltips() {
1138
+ removeTooltips();
1139
+
1140
+ // Tooltips are added with options.tooltips in original order.
1141
+ scope_Tooltips = scope_Handles.map(addTooltip);
1142
+
1143
+ bindEvent("update.tooltips", function(values, handleNumber, unencoded) {
1144
+ if (!scope_Tooltips[handleNumber]) {
1145
+ return;
1146
+ }
1147
+
1148
+ var formattedValue = values[handleNumber];
1149
+
1150
+ if (options.tooltips[handleNumber] !== true) {
1151
+ formattedValue = options.tooltips[handleNumber].to(unencoded[handleNumber]);
1152
+ }
1153
+
1154
+ scope_Tooltips[handleNumber].innerHTML = formattedValue;
1155
+ });
1156
+ }
1157
+
1158
+ function aria() {
1159
+ bindEvent("update", function(values, handleNumber, unencoded, tap, positions) {
1160
+ // Update Aria Values for all handles, as a change in one changes min and max values for the next.
1161
+ scope_HandleNumbers.forEach(function(index) {
1162
+ var handle = scope_Handles[index];
1163
+
1164
+ var min = checkHandlePosition(scope_Locations, index, 0, true, true, true);
1165
+ var max = checkHandlePosition(scope_Locations, index, 100, true, true, true);
1166
+
1167
+ var now = positions[index];
1168
+
1169
+ // Formatted value for display
1170
+ var text = options.ariaFormat.to(unencoded[index]);
1171
+
1172
+ // Map to slider range values
1173
+ min = scope_Spectrum.fromStepping(min).toFixed(1);
1174
+ max = scope_Spectrum.fromStepping(max).toFixed(1);
1175
+ now = scope_Spectrum.fromStepping(now).toFixed(1);
1176
+
1177
+ handle.children[0].setAttribute("aria-valuemin", min);
1178
+ handle.children[0].setAttribute("aria-valuemax", max);
1179
+ handle.children[0].setAttribute("aria-valuenow", now);
1180
+ handle.children[0].setAttribute("aria-valuetext", text);
1181
+ });
1182
+ });
1183
+ }
1184
+
1185
+ function getGroup(mode, values, stepped) {
1186
+ // Use the range.
1187
+ if (mode === "range" || mode === "steps") {
1188
+ return scope_Spectrum.xVal;
1189
+ }
1190
+
1191
+ if (mode === "count") {
1192
+ if (values < 2) {
1193
+ throw new Error("noUiSlider (" + VERSION + "): 'values' (>= 2) required for mode 'count'.");
1194
+ }
1195
+
1196
+ // Divide 0 - 100 in 'count' parts.
1197
+ var interval = values - 1;
1198
+ var spread = 100 / interval;
1199
+
1200
+ values = [];
1201
+
1202
+ // List these parts and have them handled as 'positions'.
1203
+ while (interval--) {
1204
+ values[interval] = interval * spread;
1205
+ }
1206
+
1207
+ values.push(100);
1208
+
1209
+ mode = "positions";
1210
+ }
1211
+
1212
+ if (mode === "positions") {
1213
+ // Map all percentages to on-range values.
1214
+ return values.map(function(value) {
1215
+ return scope_Spectrum.fromStepping(stepped ? scope_Spectrum.getStep(value) : value);
1216
+ });
1217
+ }
1218
+
1219
+ if (mode === "values") {
1220
+ // If the value must be stepped, it needs to be converted to a percentage first.
1221
+ if (stepped) {
1222
+ return values.map(function(value) {
1223
+ // Convert to percentage, apply step, return to value.
1224
+ return scope_Spectrum.fromStepping(scope_Spectrum.getStep(scope_Spectrum.toStepping(value)));
1225
+ });
1226
+ }
1227
+
1228
+ // Otherwise, we can simply use the values.
1229
+ return values;
1230
+ }
1231
+ }
1232
+
1233
+ function generateSpread(density, mode, group) {
1234
+ function safeIncrement(value, increment) {
1235
+ // Avoid floating point variance by dropping the smallest decimal places.
1236
+ return (value + increment).toFixed(7) / 1;
1237
+ }
1238
+
1239
+ var indexes = {};
1240
+ var firstInRange = scope_Spectrum.xVal[0];
1241
+ var lastInRange = scope_Spectrum.xVal[scope_Spectrum.xVal.length - 1];
1242
+ var ignoreFirst = false;
1243
+ var ignoreLast = false;
1244
+ var prevPct = 0;
1245
+
1246
+ // Create a copy of the group, sort it and filter away all duplicates.
1247
+ group = unique(
1248
+ group.slice().sort(function(a, b) {
1249
+ return a - b;
1250
+ })
1251
+ );
1252
+
1253
+ // Make sure the range starts with the first element.
1254
+ if (group[0] !== firstInRange) {
1255
+ group.unshift(firstInRange);
1256
+ ignoreFirst = true;
1257
+ }
1258
+
1259
+ // Likewise for the last one.
1260
+ if (group[group.length - 1] !== lastInRange) {
1261
+ group.push(lastInRange);
1262
+ ignoreLast = true;
1263
+ }
1264
+
1265
+ group.forEach(function(current, index) {
1266
+ // Get the current step and the lower + upper positions.
1267
+ var step;
1268
+ var i;
1269
+ var q;
1270
+ var low = current;
1271
+ var high = group[index + 1];
1272
+ var newPct;
1273
+ var pctDifference;
1274
+ var pctPos;
1275
+ var type;
1276
+ var steps;
1277
+ var realSteps;
1278
+ var stepSize;
1279
+ var isSteps = mode === "steps";
1280
+
1281
+ // When using 'steps' mode, use the provided steps.
1282
+ // Otherwise, we'll step on to the next subrange.
1283
+ if (isSteps) {
1284
+ step = scope_Spectrum.xNumSteps[index];
1285
+ }
1286
+
1287
+ // Default to a 'full' step.
1288
+ if (!step) {
1289
+ step = high - low;
1290
+ }
1291
+
1292
+ // Low can be 0, so test for false. If high is undefined,
1293
+ // we are at the last subrange. Index 0 is already handled.
1294
+ if (low === false || high === undefined) {
1295
+ return;
1296
+ }
1297
+
1298
+ // Make sure step isn't 0, which would cause an infinite loop (#654)
1299
+ step = Math.max(step, 0.0000001);
1300
+
1301
+ // Find all steps in the subrange.
1302
+ for (i = low; i <= high; i = safeIncrement(i, step)) {
1303
+ // Get the percentage value for the current step,
1304
+ // calculate the size for the subrange.
1305
+ newPct = scope_Spectrum.toStepping(i);
1306
+ pctDifference = newPct - prevPct;
1307
+
1308
+ steps = pctDifference / density;
1309
+ realSteps = Math.round(steps);
1310
+
1311
+ // This ratio represents the amount of percentage-space a point indicates.
1312
+ // For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-divided.
1313
+ // Round the percentage offset to an even number, then divide by two
1314
+ // to spread the offset on both sides of the range.
1315
+ stepSize = pctDifference / realSteps;
1316
+
1317
+ // Divide all points evenly, adding the correct number to this subrange.
1318
+ // Run up to <= so that 100% gets a point, event if ignoreLast is set.
1319
+ for (q = 1; q <= realSteps; q += 1) {
1320
+ // The ratio between the rounded value and the actual size might be ~1% off.
1321
+ // Correct the percentage offset by the number of points
1322
+ // per subrange. density = 1 will result in 100 points on the
1323
+ // full range, 2 for 50, 4 for 25, etc.
1324
+ pctPos = prevPct + q * stepSize;
1325
+ indexes[pctPos.toFixed(5)] = [scope_Spectrum.fromStepping(pctPos), 0];
1326
+ }
1327
+
1328
+ // Determine the point type.
1329
+ type = group.indexOf(i) > -1 ? PIPS_LARGE_VALUE : isSteps ? PIPS_SMALL_VALUE : PIPS_NO_VALUE;
1330
+
1331
+ // Enforce the 'ignoreFirst' option by overwriting the type for 0.
1332
+ if (!index && ignoreFirst) {
1333
+ type = 0;
1334
+ }
1335
+
1336
+ if (!(i === high && ignoreLast)) {
1337
+ // Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value.
1338
+ indexes[newPct.toFixed(5)] = [i, type];
1339
+ }
1340
+
1341
+ // Update the percentage count.
1342
+ prevPct = newPct;
1343
+ }
1344
+ });
1345
+
1346
+ return indexes;
1347
+ }
1348
+
1349
+ function addMarking(spread, filterFunc, formatter) {
1350
+ var element = scope_Document.createElement("div");
1351
+
1352
+ var valueSizeClasses = [];
1353
+ valueSizeClasses[PIPS_NO_VALUE] = options.cssClasses.valueNormal;
1354
+ valueSizeClasses[PIPS_LARGE_VALUE] = options.cssClasses.valueLarge;
1355
+ valueSizeClasses[PIPS_SMALL_VALUE] = options.cssClasses.valueSub;
1356
+
1357
+ var markerSizeClasses = [];
1358
+ markerSizeClasses[PIPS_NO_VALUE] = options.cssClasses.markerNormal;
1359
+ markerSizeClasses[PIPS_LARGE_VALUE] = options.cssClasses.markerLarge;
1360
+ markerSizeClasses[PIPS_SMALL_VALUE] = options.cssClasses.markerSub;
1361
+
1362
+ var valueOrientationClasses = [options.cssClasses.valueHorizontal, options.cssClasses.valueVertical];
1363
+ var markerOrientationClasses = [options.cssClasses.markerHorizontal, options.cssClasses.markerVertical];
1364
+
1365
+ addClass(element, options.cssClasses.pips);
1366
+ addClass(element, options.ort === 0 ? options.cssClasses.pipsHorizontal : options.cssClasses.pipsVertical);
1367
+
1368
+ function getClasses(type, source) {
1369
+ var a = source === options.cssClasses.value;
1370
+ var orientationClasses = a ? valueOrientationClasses : markerOrientationClasses;
1371
+ var sizeClasses = a ? valueSizeClasses : markerSizeClasses;
1372
+
1373
+ return source + " " + orientationClasses[options.ort] + " " + sizeClasses[type];
1374
+ }
1375
+
1376
+ function addSpread(offset, value, type) {
1377
+ // Apply the filter function, if it is set.
1378
+ type = filterFunc ? filterFunc(value, type) : type;
1379
+
1380
+ if (type === PIPS_NONE) {
1381
+ return;
1382
+ }
1383
+
1384
+ // Add a marker for every point
1385
+ var node = addNodeTo(element, false);
1386
+ node.className = getClasses(type, options.cssClasses.marker);
1387
+ node.style[options.style] = offset + "%";
1388
+
1389
+ // Values are only appended for points marked '1' or '2'.
1390
+ if (type > PIPS_NO_VALUE) {
1391
+ node = addNodeTo(element, false);
1392
+ node.className = getClasses(type, options.cssClasses.value);
1393
+ node.setAttribute("data-value", value);
1394
+ node.style[options.style] = offset + "%";
1395
+ node.innerHTML = formatter.to(value);
1396
+ }
1397
+ }
1398
+
1399
+ // Append all points.
1400
+ Object.keys(spread).forEach(function(offset) {
1401
+ addSpread(offset, spread[offset][0], spread[offset][1]);
1402
+ });
1403
+
1404
+ return element;
1405
+ }
1406
+
1407
+ function removePips() {
1408
+ if (scope_Pips) {
1409
+ removeElement(scope_Pips);
1410
+ scope_Pips = null;
1411
+ }
1412
+ }
1413
+
1414
+ function pips(grid) {
1415
+ // Fix #669
1416
+ removePips();
1417
+
1418
+ var mode = grid.mode;
1419
+ var density = grid.density || 1;
1420
+ var filter = grid.filter || false;
1421
+ var values = grid.values || false;
1422
+ var stepped = grid.stepped || false;
1423
+ var group = getGroup(mode, values, stepped);
1424
+ var spread = generateSpread(density, mode, group);
1425
+ var format = grid.format || {
1426
+ to: Math.round
1427
+ };
1428
+
1429
+ scope_Pips = scope_Target.appendChild(addMarking(spread, filter, format));
1430
+
1431
+ return scope_Pips;
1432
+ }
1433
+
1434
+ // Shorthand for base dimensions.
1435
+ function baseSize() {
1436
+ var rect = scope_Base.getBoundingClientRect();
1437
+ var alt = "offset" + ["Width", "Height"][options.ort];
1438
+ return options.ort === 0 ? rect.width || scope_Base[alt] : rect.height || scope_Base[alt];
1439
+ }
1440
+
1441
+ // Handler for attaching events trough a proxy.
1442
+ function attachEvent(events, element, callback, data) {
1443
+ // This function can be used to 'filter' events to the slider.
1444
+ // element is a node, not a nodeList
1445
+
1446
+ var method = function(e) {
1447
+ e = fixEvent(e, data.pageOffset, data.target || element);
1448
+
1449
+ // fixEvent returns false if this event has a different target
1450
+ // when handling (multi-) touch events;
1451
+ if (!e) {
1452
+ return false;
1453
+ }
1454
+
1455
+ // doNotReject is passed by all end events to make sure released touches
1456
+ // are not rejected, leaving the slider "stuck" to the cursor;
1457
+ if (isSliderDisabled() && !data.doNotReject) {
1458
+ return false;
1459
+ }
1460
+
1461
+ // Stop if an active 'tap' transition is taking place.
1462
+ if (hasClass(scope_Target, options.cssClasses.tap) && !data.doNotReject) {
1463
+ return false;
1464
+ }
1465
+
1466
+ // Ignore right or middle clicks on start #454
1467
+ if (events === actions.start && e.buttons !== undefined && e.buttons > 1) {
1468
+ return false;
1469
+ }
1470
+
1471
+ // Ignore right or middle clicks on start #454
1472
+ if (data.hover && e.buttons) {
1473
+ return false;
1474
+ }
1475
+
1476
+ // 'supportsPassive' is only true if a browser also supports touch-action: none in CSS.
1477
+ // iOS safari does not, so it doesn't get to benefit from passive scrolling. iOS does support
1478
+ // touch-action: manipulation, but that allows panning, which breaks
1479
+ // sliders after zooming/on non-responsive pages.
1480
+ // See: https://bugs.webkit.org/show_bug.cgi?id=133112
1481
+ if (!supportsPassive) {
1482
+ e.preventDefault();
1483
+ }
1484
+
1485
+ e.calcPoint = e.points[options.ort];
1486
+
1487
+ // Call the event handler with the event [ and additional data ].
1488
+ callback(e, data);
1489
+ };
1490
+
1491
+ var methods = [];
1492
+
1493
+ // Bind a closure on the target for every event type.
1494
+ events.split(" ").forEach(function(eventName) {
1495
+ element.addEventListener(eventName, method, supportsPassive ? { passive: true } : false);
1496
+ methods.push([eventName, method]);
1497
+ });
1498
+
1499
+ return methods;
1500
+ }
1501
+
1502
+ // Provide a clean event with standardized offset values.
1503
+ function fixEvent(e, pageOffset, eventTarget) {
1504
+ // Filter the event to register the type, which can be
1505
+ // touch, mouse or pointer. Offset changes need to be
1506
+ // made on an event specific basis.
1507
+ var touch = e.type.indexOf("touch") === 0;
1508
+ var mouse = e.type.indexOf("mouse") === 0;
1509
+ var pointer = e.type.indexOf("pointer") === 0;
1510
+
1511
+ var x;
1512
+ var y;
1513
+
1514
+ // IE10 implemented pointer events with a prefix;
1515
+ if (e.type.indexOf("MSPointer") === 0) {
1516
+ pointer = true;
1517
+ }
1518
+
1519
+ // The only thing one handle should be concerned about is the touches that originated on top of it.
1520
+ if (touch) {
1521
+ // Returns true if a touch originated on the target.
1522
+ var isTouchOnTarget = function(checkTouch) {
1523
+ return checkTouch.target === eventTarget || eventTarget.contains(checkTouch.target);
1524
+ };
1525
+
1526
+ // In the case of touchstart events, we need to make sure there is still no more than one
1527
+ // touch on the target so we look amongst all touches.
1528
+ if (e.type === "touchstart") {
1529
+ var targetTouches = Array.prototype.filter.call(e.touches, isTouchOnTarget);
1530
+
1531
+ // Do not support more than one touch per handle.
1532
+ if (targetTouches.length > 1) {
1533
+ return false;
1534
+ }
1535
+
1536
+ x = targetTouches[0].pageX;
1537
+ y = targetTouches[0].pageY;
1538
+ } else {
1539
+ // In the other cases, find on changedTouches is enough.
1540
+ var targetTouch = Array.prototype.find.call(e.changedTouches, isTouchOnTarget);
1541
+
1542
+ // Cancel if the target touch has not moved.
1543
+ if (!targetTouch) {
1544
+ return false;
1545
+ }
1546
+
1547
+ x = targetTouch.pageX;
1548
+ y = targetTouch.pageY;
1549
+ }
1550
+ }
1551
+
1552
+ pageOffset = pageOffset || getPageOffset(scope_Document);
1553
+
1554
+ if (mouse || pointer) {
1555
+ x = e.clientX + pageOffset.x;
1556
+ y = e.clientY + pageOffset.y;
1557
+ }
1558
+
1559
+ e.pageOffset = pageOffset;
1560
+ e.points = [x, y];
1561
+ e.cursor = mouse || pointer; // Fix #435
1562
+
1563
+ return e;
1564
+ }
1565
+
1566
+ // Translate a coordinate in the document to a percentage on the slider
1567
+ function calcPointToPercentage(calcPoint) {
1568
+ var location = calcPoint - offset(scope_Base, options.ort);
1569
+ var proposal = (location * 100) / baseSize();
1570
+
1571
+ // Clamp proposal between 0% and 100%
1572
+ // Out-of-bound coordinates may occur when .noUi-base pseudo-elements
1573
+ // are used (e.g. contained handles feature)
1574
+ proposal = limit(proposal);
1575
+
1576
+ return options.dir ? 100 - proposal : proposal;
1577
+ }
1578
+
1579
+ // Find handle closest to a certain percentage on the slider
1580
+ function getClosestHandle(clickedPosition) {
1581
+ var smallestDifference = 100;
1582
+ var handleNumber = false;
1583
+
1584
+ scope_Handles.forEach(function(handle, index) {
1585
+ // Disabled handles are ignored
1586
+ if (isHandleDisabled(index)) {
1587
+ return;
1588
+ }
1589
+
1590
+ var handlePosition = scope_Locations[index];
1591
+ var differenceWithThisHandle = Math.abs(handlePosition - clickedPosition);
1592
+
1593
+ // Initial state
1594
+ var clickAtEdge = differenceWithThisHandle === 100 && smallestDifference === 100;
1595
+
1596
+ // Difference with this handle is smaller than the previously checked handle
1597
+ var isCloser = differenceWithThisHandle < smallestDifference;
1598
+ var isCloserAfter = differenceWithThisHandle <= smallestDifference && clickedPosition > handlePosition;
1599
+
1600
+ if (isCloser || isCloserAfter || clickAtEdge) {
1601
+ handleNumber = index;
1602
+ smallestDifference = differenceWithThisHandle;
1603
+ }
1604
+ });
1605
+
1606
+ return handleNumber;
1607
+ }
1608
+
1609
+ // Fire 'end' when a mouse or pen leaves the document.
1610
+ function documentLeave(event, data) {
1611
+ if (event.type === "mouseout" && event.target.nodeName === "HTML" && event.relatedTarget === null) {
1612
+ eventEnd(event, data);
1613
+ }
1614
+ }
1615
+
1616
+ // Handle movement on document for handle and range drag.
1617
+ function eventMove(event, data) {
1618
+ // Fix #498
1619
+ // Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty).
1620
+ // https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero
1621
+ // IE9 has .buttons and .which zero on mousemove.
1622
+ // Firefox breaks the spec MDN defines.
1623
+ if (navigator.appVersion.indexOf("MSIE 9") === -1 && event.buttons === 0 && data.buttonsProperty !== 0) {
1624
+ return eventEnd(event, data);
1625
+ }
1626
+
1627
+ // Check if we are moving up or down
1628
+ var movement = (options.dir ? -1 : 1) * (event.calcPoint - data.startCalcPoint);
1629
+
1630
+ // Convert the movement into a percentage of the slider width/height
1631
+ var proposal = (movement * 100) / data.baseSize;
1632
+
1633
+ moveHandles(movement > 0, proposal, data.locations, data.handleNumbers);
1634
+ }
1635
+
1636
+ // Unbind move events on document, call callbacks.
1637
+ function eventEnd(event, data) {
1638
+ // The handle is no longer active, so remove the class.
1639
+ if (data.handle) {
1640
+ removeClass(data.handle, options.cssClasses.active);
1641
+ scope_ActiveHandlesCount -= 1;
1642
+ }
1643
+
1644
+ // Unbind the move and end events, which are added on 'start'.
1645
+ data.listeners.forEach(function(c) {
1646
+ scope_DocumentElement.removeEventListener(c[0], c[1]);
1647
+ });
1648
+
1649
+ if (scope_ActiveHandlesCount === 0) {
1650
+ // Remove dragging class.
1651
+ removeClass(scope_Target, options.cssClasses.drag);
1652
+ setZindex();
1653
+
1654
+ // Remove cursor styles and text-selection events bound to the body.
1655
+ if (event.cursor) {
1656
+ scope_Body.style.cursor = "";
1657
+ scope_Body.removeEventListener("selectstart", preventDefault);
1658
+ }
1659
+ }
1660
+
1661
+ data.handleNumbers.forEach(function(handleNumber) {
1662
+ fireEvent("change", handleNumber);
1663
+ fireEvent("set", handleNumber);
1664
+ fireEvent("end", handleNumber);
1665
+ });
1666
+ }
1667
+
1668
+ // Bind move events on document.
1669
+ function eventStart(event, data) {
1670
+ // Ignore event if any handle is disabled
1671
+ if (data.handleNumbers.some(isHandleDisabled)) {
1672
+ return false;
1673
+ }
1674
+
1675
+ var handle;
1676
+
1677
+ if (data.handleNumbers.length === 1) {
1678
+ var handleOrigin = scope_Handles[data.handleNumbers[0]];
1679
+
1680
+ handle = handleOrigin.children[0];
1681
+ scope_ActiveHandlesCount += 1;
1682
+
1683
+ // Mark the handle as 'active' so it can be styled.
1684
+ addClass(handle, options.cssClasses.active);
1685
+ }
1686
+
1687
+ // A drag should never propagate up to the 'tap' event.
1688
+ event.stopPropagation();
1689
+
1690
+ // Record the event listeners.
1691
+ var listeners = [];
1692
+
1693
+ // Attach the move and end events.
1694
+ var moveEvent = attachEvent(actions.move, scope_DocumentElement, eventMove, {
1695
+ // The event target has changed so we need to propagate the original one so that we keep
1696
+ // relying on it to extract target touches.
1697
+ target: event.target,
1698
+ handle: handle,
1699
+ listeners: listeners,
1700
+ startCalcPoint: event.calcPoint,
1701
+ baseSize: baseSize(),
1702
+ pageOffset: event.pageOffset,
1703
+ handleNumbers: data.handleNumbers,
1704
+ buttonsProperty: event.buttons,
1705
+ locations: scope_Locations.slice()
1706
+ });
1707
+
1708
+ var endEvent = attachEvent(actions.end, scope_DocumentElement, eventEnd, {
1709
+ target: event.target,
1710
+ handle: handle,
1711
+ listeners: listeners,
1712
+ doNotReject: true,
1713
+ handleNumbers: data.handleNumbers
1714
+ });
1715
+
1716
+ var outEvent = attachEvent("mouseout", scope_DocumentElement, documentLeave, {
1717
+ target: event.target,
1718
+ handle: handle,
1719
+ listeners: listeners,
1720
+ doNotReject: true,
1721
+ handleNumbers: data.handleNumbers
1722
+ });
1723
+
1724
+ // We want to make sure we pushed the listeners in the listener list rather than creating
1725
+ // a new one as it has already been passed to the event handlers.
1726
+ listeners.push.apply(listeners, moveEvent.concat(endEvent, outEvent));
1727
+
1728
+ // Text selection isn't an issue on touch devices,
1729
+ // so adding cursor styles can be skipped.
1730
+ if (event.cursor) {
1731
+ // Prevent the 'I' cursor and extend the range-drag cursor.
1732
+ scope_Body.style.cursor = getComputedStyle(event.target).cursor;
1733
+
1734
+ // Mark the target with a dragging state.
1735
+ if (scope_Handles.length > 1) {
1736
+ addClass(scope_Target, options.cssClasses.drag);
1737
+ }
1738
+
1739
+ // Prevent text selection when dragging the handles.
1740
+ // In noUiSlider <= 9.2.0, this was handled by calling preventDefault on mouse/touch start/move,
1741
+ // which is scroll blocking. The selectstart event is supported by FireFox starting from version 52,
1742
+ // meaning the only holdout is iOS Safari. This doesn't matter: text selection isn't triggered there.
1743
+ // The 'cursor' flag is false.
1744
+ // See: http://caniuse.com/#search=selectstart
1745
+ scope_Body.addEventListener("selectstart", preventDefault, false);
1746
+ }
1747
+
1748
+ data.handleNumbers.forEach(function(handleNumber) {
1749
+ fireEvent("start", handleNumber);
1750
+ });
1751
+ }
1752
+
1753
+ // Move closest handle to tapped location.
1754
+ function eventTap(event) {
1755
+ // The tap event shouldn't propagate up
1756
+ event.stopPropagation();
1757
+
1758
+ var proposal = calcPointToPercentage(event.calcPoint);
1759
+ var handleNumber = getClosestHandle(proposal);
1760
+
1761
+ // Tackle the case that all handles are 'disabled'.
1762
+ if (handleNumber === false) {
1763
+ return false;
1764
+ }
1765
+
1766
+ // Flag the slider as it is now in a transitional state.
1767
+ // Transition takes a configurable amount of ms (default 300). Re-enable the slider after that.
1768
+ if (!options.events.snap) {
1769
+ addClassFor(scope_Target, options.cssClasses.tap, options.animationDuration);
1770
+ }
1771
+
1772
+ setHandle(handleNumber, proposal, true, true);
1773
+
1774
+ setZindex();
1775
+
1776
+ fireEvent("slide", handleNumber, true);
1777
+ fireEvent("update", handleNumber, true);
1778
+ fireEvent("change", handleNumber, true);
1779
+ fireEvent("set", handleNumber, true);
1780
+
1781
+ if (options.events.snap) {
1782
+ eventStart(event, { handleNumbers: [handleNumber] });
1783
+ }
1784
+ }
1785
+
1786
+ // Fires a 'hover' event for a hovered mouse/pen position.
1787
+ function eventHover(event) {
1788
+ var proposal = calcPointToPercentage(event.calcPoint);
1789
+
1790
+ var to = scope_Spectrum.getStep(proposal);
1791
+ var value = scope_Spectrum.fromStepping(to);
1792
+
1793
+ Object.keys(scope_Events).forEach(function(targetEvent) {
1794
+ if ("hover" === targetEvent.split(".")[0]) {
1795
+ scope_Events[targetEvent].forEach(function(callback) {
1796
+ callback.call(scope_Self, value);
1797
+ });
1798
+ }
1799
+ });
1800
+ }
1801
+
1802
+ // Handles keydown on focused handles
1803
+ // Don't move the document when pressing arrow keys on focused handles
1804
+ function eventKeydown(event, handleNumber) {
1805
+ if (isSliderDisabled() || isHandleDisabled(handleNumber)) {
1806
+ return false;
1807
+ }
1808
+
1809
+ var horizontalKeys = ["Left", "Right"];
1810
+ var verticalKeys = ["Down", "Up"];
1811
+ var largeStepKeys = ["PageDown", "PageUp"];
1812
+ var edgeKeys = ["Home", "End"];
1813
+
1814
+ if (options.dir && !options.ort) {
1815
+ // On an right-to-left slider, the left and right keys act inverted
1816
+ horizontalKeys.reverse();
1817
+ } else if (options.ort && !options.dir) {
1818
+ // On a top-to-bottom slider, the up and down keys act inverted
1819
+ verticalKeys.reverse();
1820
+ largeStepKeys.reverse();
1821
+ }
1822
+
1823
+ // Strip "Arrow" for IE compatibility. https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
1824
+ var key = event.key.replace("Arrow", "");
1825
+
1826
+ var isLargeDown = key === largeStepKeys[0];
1827
+ var isLargeUp = key === largeStepKeys[1];
1828
+ var isDown = key === verticalKeys[0] || key === horizontalKeys[0] || isLargeDown;
1829
+ var isUp = key === verticalKeys[1] || key === horizontalKeys[1] || isLargeUp;
1830
+ var isMin = key === edgeKeys[0];
1831
+ var isMax = key === edgeKeys[1];
1832
+
1833
+ if (!isDown && !isUp && !isMin && !isMax) {
1834
+ return true;
1835
+ }
1836
+
1837
+ event.preventDefault();
1838
+
1839
+ var to;
1840
+
1841
+ if (isUp || isDown) {
1842
+ var multiplier = 5;
1843
+ var direction = isDown ? 0 : 1;
1844
+ var steps = getNextStepsForHandle(handleNumber);
1845
+ var step = steps[direction];
1846
+
1847
+ // At the edge of a slider, do nothing
1848
+ if (step === null) {
1849
+ return false;
1850
+ }
1851
+
1852
+ // No step set, use the default of 10% of the sub-range
1853
+ if (step === false) {
1854
+ step = scope_Spectrum.getDefaultStep(scope_Locations[handleNumber], isDown, 10);
1855
+ }
1856
+
1857
+ if (isLargeUp || isLargeDown) {
1858
+ step *= multiplier;
1859
+ }
1860
+
1861
+ // Step over zero-length ranges (#948);
1862
+ step = Math.max(step, 0.0000001);
1863
+
1864
+ // Decrement for down steps
1865
+ step = (isDown ? -1 : 1) * step;
1866
+
1867
+ to = scope_Values[handleNumber] + step;
1868
+ } else if (isMax) {
1869
+ // End key
1870
+ to = options.spectrum.xVal[options.spectrum.xVal.length - 1];
1871
+ } else {
1872
+ // Home key
1873
+ to = options.spectrum.xVal[0];
1874
+ }
1875
+
1876
+ setHandle(handleNumber, scope_Spectrum.toStepping(to), true, true);
1877
+
1878
+ fireEvent("slide", handleNumber);
1879
+ fireEvent("update", handleNumber);
1880
+ fireEvent("change", handleNumber);
1881
+ fireEvent("set", handleNumber);
1882
+
1883
+ return false;
1884
+ }
1885
+
1886
+ // Attach events to several slider parts.
1887
+ function bindSliderEvents(behaviour) {
1888
+ // Attach the standard drag event to the handles.
1889
+ if (!behaviour.fixed) {
1890
+ scope_Handles.forEach(function(handle, index) {
1891
+ // These events are only bound to the visual handle
1892
+ // element, not the 'real' origin element.
1893
+ attachEvent(actions.start, handle.children[0], eventStart, {
1894
+ handleNumbers: [index]
1895
+ });
1896
+ });
1897
+ }
1898
+
1899
+ // Attach the tap event to the slider base.
1900
+ if (behaviour.tap) {
1901
+ attachEvent(actions.start, scope_Base, eventTap, {});
1902
+ }
1903
+
1904
+ // Fire hover events
1905
+ if (behaviour.hover) {
1906
+ attachEvent(actions.move, scope_Base, eventHover, {
1907
+ hover: true
1908
+ });
1909
+ }
1910
+
1911
+ // Make the range draggable.
1912
+ if (behaviour.drag) {
1913
+ scope_Connects.forEach(function(connect, index) {
1914
+ if (connect === false || index === 0 || index === scope_Connects.length - 1) {
1915
+ return;
1916
+ }
1917
+
1918
+ var handleBefore = scope_Handles[index - 1];
1919
+ var handleAfter = scope_Handles[index];
1920
+ var eventHolders = [connect];
1921
+
1922
+ addClass(connect, options.cssClasses.draggable);
1923
+
1924
+ // When the range is fixed, the entire range can
1925
+ // be dragged by the handles. The handle in the first
1926
+ // origin will propagate the start event upward,
1927
+ // but it needs to be bound manually on the other.
1928
+ if (behaviour.fixed) {
1929
+ eventHolders.push(handleBefore.children[0]);
1930
+ eventHolders.push(handleAfter.children[0]);
1931
+ }
1932
+
1933
+ eventHolders.forEach(function(eventHolder) {
1934
+ attachEvent(actions.start, eventHolder, eventStart, {
1935
+ handles: [handleBefore, handleAfter],
1936
+ handleNumbers: [index - 1, index]
1937
+ });
1938
+ });
1939
+ });
1940
+ }
1941
+ }
1942
+
1943
+ // Attach an event to this slider, possibly including a namespace
1944
+ function bindEvent(namespacedEvent, callback) {
1945
+ scope_Events[namespacedEvent] = scope_Events[namespacedEvent] || [];
1946
+ scope_Events[namespacedEvent].push(callback);
1947
+
1948
+ // If the event bound is 'update,' fire it immediately for all handles.
1949
+ if (namespacedEvent.split(".")[0] === "update") {
1950
+ scope_Handles.forEach(function(a, index) {
1951
+ fireEvent("update", index);
1952
+ });
1953
+ }
1954
+ }
1955
+
1956
+ // Undo attachment of event
1957
+ function removeEvent(namespacedEvent) {
1958
+ var event = namespacedEvent && namespacedEvent.split(".")[0];
1959
+ var namespace = event && namespacedEvent.substring(event.length);
1960
+
1961
+ Object.keys(scope_Events).forEach(function(bind) {
1962
+ var tEvent = bind.split(".")[0];
1963
+ var tNamespace = bind.substring(tEvent.length);
1964
+
1965
+ if ((!event || event === tEvent) && (!namespace || namespace === tNamespace)) {
1966
+ delete scope_Events[bind];
1967
+ }
1968
+ });
1969
+ }
1970
+
1971
+ // External event handling
1972
+ function fireEvent(eventName, handleNumber, tap) {
1973
+ Object.keys(scope_Events).forEach(function(targetEvent) {
1974
+ var eventType = targetEvent.split(".")[0];
1975
+
1976
+ if (eventName === eventType) {
1977
+ scope_Events[targetEvent].forEach(function(callback) {
1978
+ callback.call(
1979
+ // Use the slider public API as the scope ('this')
1980
+ scope_Self,
1981
+ // Return values as array, so arg_1[arg_2] is always valid.
1982
+ scope_Values.map(options.format.to),
1983
+ // Handle index, 0 or 1
1984
+ handleNumber,
1985
+ // Un-formatted slider values
1986
+ scope_Values.slice(),
1987
+ // Event is fired by tap, true or false
1988
+ tap || false,
1989
+ // Left offset of the handle, in relation to the slider
1990
+ scope_Locations.slice()
1991
+ );
1992
+ });
1993
+ }
1994
+ });
1995
+ }
1996
+
1997
+ // Split out the handle positioning logic so the Move event can use it, too
1998
+ function checkHandlePosition(reference, handleNumber, to, lookBackward, lookForward, getValue) {
1999
+ // For sliders with multiple handles, limit movement to the other handle.
2000
+ // Apply the margin option by adding it to the handle positions.
2001
+ if (scope_Handles.length > 1 && !options.events.unconstrained) {
2002
+ if (lookBackward && handleNumber > 0) {
2003
+ to = Math.max(to, reference[handleNumber - 1] + options.margin);
2004
+ }
2005
+
2006
+ if (lookForward && handleNumber < scope_Handles.length - 1) {
2007
+ to = Math.min(to, reference[handleNumber + 1] - options.margin);
2008
+ }
2009
+ }
2010
+
2011
+ // The limit option has the opposite effect, limiting handles to a
2012
+ // maximum distance from another. Limit must be > 0, as otherwise
2013
+ // handles would be unmovable.
2014
+ if (scope_Handles.length > 1 && options.limit) {
2015
+ if (lookBackward && handleNumber > 0) {
2016
+ to = Math.min(to, reference[handleNumber - 1] + options.limit);
2017
+ }
2018
+
2019
+ if (lookForward && handleNumber < scope_Handles.length - 1) {
2020
+ to = Math.max(to, reference[handleNumber + 1] - options.limit);
2021
+ }
2022
+ }
2023
+
2024
+ // The padding option keeps the handles a certain distance from the
2025
+ // edges of the slider. Padding must be > 0.
2026
+ if (options.padding) {
2027
+ if (handleNumber === 0) {
2028
+ to = Math.max(to, options.padding[0]);
2029
+ }
2030
+
2031
+ if (handleNumber === scope_Handles.length - 1) {
2032
+ to = Math.min(to, 100 - options.padding[1]);
2033
+ }
2034
+ }
2035
+
2036
+ to = scope_Spectrum.getStep(to);
2037
+
2038
+ // Limit percentage to the 0 - 100 range
2039
+ to = limit(to);
2040
+
2041
+ // Return false if handle can't move
2042
+ if (to === reference[handleNumber] && !getValue) {
2043
+ return false;
2044
+ }
2045
+
2046
+ return to;
2047
+ }
2048
+
2049
+ // Uses slider orientation to create CSS rules. a = base value;
2050
+ function inRuleOrder(v, a) {
2051
+ var o = options.ort;
2052
+ return (o ? a : v) + ", " + (o ? v : a);
2053
+ }
2054
+
2055
+ // Moves handle(s) by a percentage
2056
+ // (bool, % to move, [% where handle started, ...], [index in scope_Handles, ...])
2057
+ function moveHandles(upward, proposal, locations, handleNumbers) {
2058
+ var proposals = locations.slice();
2059
+
2060
+ var b = [!upward, upward];
2061
+ var f = [upward, !upward];
2062
+
2063
+ // Copy handleNumbers so we don't change the dataset
2064
+ handleNumbers = handleNumbers.slice();
2065
+
2066
+ // Check to see which handle is 'leading'.
2067
+ // If that one can't move the second can't either.
2068
+ if (upward) {
2069
+ handleNumbers.reverse();
2070
+ }
2071
+
2072
+ // Step 1: get the maximum percentage that any of the handles can move
2073
+ if (handleNumbers.length > 1) {
2074
+ handleNumbers.forEach(function(handleNumber, o) {
2075
+ var to = checkHandlePosition(
2076
+ proposals,
2077
+ handleNumber,
2078
+ proposals[handleNumber] + proposal,
2079
+ b[o],
2080
+ f[o],
2081
+ false
2082
+ );
2083
+
2084
+ // Stop if one of the handles can't move.
2085
+ if (to === false) {
2086
+ proposal = 0;
2087
+ } else {
2088
+ proposal = to - proposals[handleNumber];
2089
+ proposals[handleNumber] = to;
2090
+ }
2091
+ });
2092
+ }
2093
+
2094
+ // If using one handle, check backward AND forward
2095
+ else {
2096
+ b = f = [true];
2097
+ }
2098
+
2099
+ var state = false;
2100
+
2101
+ // Step 2: Try to set the handles with the found percentage
2102
+ handleNumbers.forEach(function(handleNumber, o) {
2103
+ state = setHandle(handleNumber, locations[handleNumber] + proposal, b[o], f[o]) || state;
2104
+ });
2105
+
2106
+ // Step 3: If a handle moved, fire events
2107
+ if (state) {
2108
+ handleNumbers.forEach(function(handleNumber) {
2109
+ fireEvent("update", handleNumber);
2110
+ fireEvent("slide", handleNumber);
2111
+ });
2112
+ }
2113
+ }
2114
+
2115
+ // Takes a base value and an offset. This offset is used for the connect bar size.
2116
+ // In the initial design for this feature, the origin element was 1% wide.
2117
+ // Unfortunately, a rounding bug in Chrome makes it impossible to implement this feature
2118
+ // in this manner: https://bugs.chromium.org/p/chromium/issues/detail?id=798223
2119
+ function transformDirection(a, b) {
2120
+ return options.dir ? 100 - a - b : a;
2121
+ }
2122
+
2123
+ // Updates scope_Locations and scope_Values, updates visual state
2124
+ function updateHandlePosition(handleNumber, to) {
2125
+ // Update locations.
2126
+ scope_Locations[handleNumber] = to;
2127
+
2128
+ // Convert the value to the slider stepping/range.
2129
+ scope_Values[handleNumber] = scope_Spectrum.fromStepping(to);
2130
+
2131
+ var translation = 10 * (transformDirection(to, 0) - scope_DirOffset);
2132
+ var translateRule = "translate(" + inRuleOrder(translation + "%", "0") + ")";
2133
+
2134
+ scope_Handles[handleNumber].style[options.transformRule] = translateRule;
2135
+
2136
+ updateConnect(handleNumber);
2137
+ updateConnect(handleNumber + 1);
2138
+ }
2139
+
2140
+ // Handles before the slider middle are stacked later = higher,
2141
+ // Handles after the middle later is lower
2142
+ // [[7] [8] .......... | .......... [5] [4]
2143
+ function setZindex() {
2144
+ scope_HandleNumbers.forEach(function(handleNumber) {
2145
+ var dir = scope_Locations[handleNumber] > 50 ? -1 : 1;
2146
+ var zIndex = 3 + (scope_Handles.length + dir * handleNumber);
2147
+ scope_Handles[handleNumber].style.zIndex = zIndex;
2148
+ });
2149
+ }
2150
+
2151
+ // Test suggested values and apply margin, step.
2152
+ function setHandle(handleNumber, to, lookBackward, lookForward) {
2153
+ to = checkHandlePosition(scope_Locations, handleNumber, to, lookBackward, lookForward, false);
2154
+
2155
+ if (to === false) {
2156
+ return false;
2157
+ }
2158
+
2159
+ updateHandlePosition(handleNumber, to);
2160
+
2161
+ return true;
2162
+ }
2163
+
2164
+ // Updates style attribute for connect nodes
2165
+ function updateConnect(index) {
2166
+ // Skip connects set to false
2167
+ if (!scope_Connects[index]) {
2168
+ return;
2169
+ }
2170
+
2171
+ var l = 0;
2172
+ var h = 100;
2173
+
2174
+ if (index !== 0) {
2175
+ l = scope_Locations[index - 1];
2176
+ }
2177
+
2178
+ if (index !== scope_Connects.length - 1) {
2179
+ h = scope_Locations[index];
2180
+ }
2181
+
2182
+ // We use two rules:
2183
+ // 'translate' to change the left/top offset;
2184
+ // 'scale' to change the width of the element;
2185
+ // As the element has a width of 100%, a translation of 100% is equal to 100% of the parent (.noUi-base)
2186
+ var connectWidth = h - l;
2187
+ var translateRule = "translate(" + inRuleOrder(transformDirection(l, connectWidth) + "%", "0") + ")";
2188
+ var scaleRule = "scale(" + inRuleOrder(connectWidth / 100, "1") + ")";
2189
+
2190
+ scope_Connects[index].style[options.transformRule] = translateRule + " " + scaleRule;
2191
+ }
2192
+
2193
+ // Parses value passed to .set method. Returns current value if not parse-able.
2194
+ function resolveToValue(to, handleNumber) {
2195
+ // Setting with null indicates an 'ignore'.
2196
+ // Inputting 'false' is invalid.
2197
+ if (to === null || to === false || to === undefined) {
2198
+ return scope_Locations[handleNumber];
2199
+ }
2200
+
2201
+ // If a formatted number was passed, attempt to decode it.
2202
+ if (typeof to === "number") {
2203
+ to = String(to);
2204
+ }
2205
+
2206
+ to = options.format.from(to);
2207
+ to = scope_Spectrum.toStepping(to);
2208
+
2209
+ // If parsing the number failed, use the current value.
2210
+ if (to === false || isNaN(to)) {
2211
+ return scope_Locations[handleNumber];
2212
+ }
2213
+
2214
+ return to;
2215
+ }
2216
+
2217
+ // Set the slider value.
2218
+ function valueSet(input, fireSetEvent) {
2219
+ var values = asArray(input);
2220
+ var isInit = scope_Locations[0] === undefined;
2221
+
2222
+ // Event fires by default
2223
+ fireSetEvent = fireSetEvent === undefined ? true : !!fireSetEvent;
2224
+
2225
+ // Animation is optional.
2226
+ // Make sure the initial values were set before using animated placement.
2227
+ if (options.animate && !isInit) {
2228
+ addClassFor(scope_Target, options.cssClasses.tap, options.animationDuration);
2229
+ }
2230
+
2231
+ // First pass, without lookAhead but with lookBackward. Values are set from left to right.
2232
+ scope_HandleNumbers.forEach(function(handleNumber) {
2233
+ setHandle(handleNumber, resolveToValue(values[handleNumber], handleNumber), true, false);
2234
+ });
2235
+
2236
+ var i = scope_HandleNumbers.length === 1 ? 0 : 1;
2237
+
2238
+ // Secondary passes. Now that all base values are set, apply constraints.
2239
+ // Iterate all handles to ensure constraints are applied for the entire slider (Issue #1009)
2240
+ for (; i < scope_HandleNumbers.length; ++i) {
2241
+ scope_HandleNumbers.forEach(function(handleNumber) {
2242
+ setHandle(handleNumber, scope_Locations[handleNumber], true, true);
2243
+ });
2244
+ }
2245
+
2246
+ setZindex();
2247
+
2248
+ scope_HandleNumbers.forEach(function(handleNumber) {
2249
+ fireEvent("update", handleNumber);
2250
+
2251
+ // Fire the event only for handles that received a new value, as per #579
2252
+ if (values[handleNumber] !== null && fireSetEvent) {
2253
+ fireEvent("set", handleNumber);
2254
+ }
2255
+ });
2256
+ }
2257
+
2258
+ // Reset slider to initial values
2259
+ function valueReset(fireSetEvent) {
2260
+ valueSet(options.start, fireSetEvent);
2261
+ }
2262
+
2263
+ // Set value for a single handle
2264
+ function valueSetHandle(handleNumber, value, fireSetEvent) {
2265
+ // Ensure numeric input
2266
+ handleNumber = Number(handleNumber);
2267
+
2268
+ if (!(handleNumber >= 0 && handleNumber < scope_HandleNumbers.length)) {
2269
+ throw new Error("noUiSlider (" + VERSION + "): invalid handle number, got: " + handleNumber);
2270
+ }
2271
+
2272
+ // Look both backward and forward, since we don't want this handle to "push" other handles (#960);
2273
+ setHandle(handleNumber, resolveToValue(value, handleNumber), true, true);
2274
+
2275
+ fireEvent("update", handleNumber);
2276
+
2277
+ if (fireSetEvent) {
2278
+ fireEvent("set", handleNumber);
2279
+ }
2280
+ }
2281
+
2282
+ // Get the slider value.
2283
+ function valueGet() {
2284
+ var values = scope_Values.map(options.format.to);
2285
+
2286
+ // If only one handle is used, return a single value.
2287
+ if (values.length === 1) {
2288
+ return values[0];
2289
+ }
2290
+
2291
+ return values;
2292
+ }
2293
+
2294
+ // Removes classes from the root and empties it.
2295
+ function destroy() {
2296
+ for (var key in options.cssClasses) {
2297
+ if (!options.cssClasses.hasOwnProperty(key)) {
2298
+ continue;
2299
+ }
2300
+ removeClass(scope_Target, options.cssClasses[key]);
2301
+ }
2302
+
2303
+ while (scope_Target.firstChild) {
2304
+ scope_Target.removeChild(scope_Target.firstChild);
2305
+ }
2306
+
2307
+ delete scope_Target.noUiSlider;
2308
+ }
2309
+
2310
+ function getNextStepsForHandle(handleNumber) {
2311
+ var location = scope_Locations[handleNumber];
2312
+ var nearbySteps = scope_Spectrum.getNearbySteps(location);
2313
+ var value = scope_Values[handleNumber];
2314
+ var increment = nearbySteps.thisStep.step;
2315
+ var decrement = null;
2316
+
2317
+ // If snapped, directly use defined step value
2318
+ if (options.snap) {
2319
+ return [
2320
+ value - nearbySteps.stepBefore.startValue || null,
2321
+ nearbySteps.stepAfter.startValue - value || null
2322
+ ];
2323
+ }
2324
+
2325
+ // If the next value in this step moves into the next step,
2326
+ // the increment is the start of the next step - the current value
2327
+ if (increment !== false) {
2328
+ if (value + increment > nearbySteps.stepAfter.startValue) {
2329
+ increment = nearbySteps.stepAfter.startValue - value;
2330
+ }
2331
+ }
2332
+
2333
+ // If the value is beyond the starting point
2334
+ if (value > nearbySteps.thisStep.startValue) {
2335
+ decrement = nearbySteps.thisStep.step;
2336
+ } else if (nearbySteps.stepBefore.step === false) {
2337
+ decrement = false;
2338
+ }
2339
+
2340
+ // If a handle is at the start of a step, it always steps back into the previous step first
2341
+ else {
2342
+ decrement = value - nearbySteps.stepBefore.highestStep;
2343
+ }
2344
+
2345
+ // Now, if at the slider edges, there is no in/decrement
2346
+ if (location === 100) {
2347
+ increment = null;
2348
+ } else if (location === 0) {
2349
+ decrement = null;
2350
+ }
2351
+
2352
+ // As per #391, the comparison for the decrement step can have some rounding issues.
2353
+ var stepDecimals = scope_Spectrum.countStepDecimals();
2354
+
2355
+ // Round per #391
2356
+ if (increment !== null && increment !== false) {
2357
+ increment = Number(increment.toFixed(stepDecimals));
2358
+ }
2359
+
2360
+ if (decrement !== null && decrement !== false) {
2361
+ decrement = Number(decrement.toFixed(stepDecimals));
2362
+ }
2363
+
2364
+ return [decrement, increment];
2365
+ }
2366
+
2367
+ // Get the current step size for the slider.
2368
+ function getNextSteps() {
2369
+ return scope_HandleNumbers.map(getNextStepsForHandle);
2370
+ }
2371
+
2372
+ // Updateable: margin, limit, padding, step, range, animate, snap
2373
+ function updateOptions(optionsToUpdate, fireSetEvent) {
2374
+ // Spectrum is created using the range, snap, direction and step options.
2375
+ // 'snap' and 'step' can be updated.
2376
+ // If 'snap' and 'step' are not passed, they should remain unchanged.
2377
+ var v = valueGet();
2378
+
2379
+ var updateAble = [
2380
+ "margin",
2381
+ "limit",
2382
+ "padding",
2383
+ "range",
2384
+ "animate",
2385
+ "snap",
2386
+ "step",
2387
+ "format",
2388
+ "pips",
2389
+ "tooltips"
2390
+ ];
2391
+
2392
+ // Only change options that we're actually passed to update.
2393
+ updateAble.forEach(function(name) {
2394
+ // Check for undefined. null removes the value.
2395
+ if (optionsToUpdate[name] !== undefined) {
2396
+ originalOptions[name] = optionsToUpdate[name];
2397
+ }
2398
+ });
2399
+
2400
+ var newOptions = testOptions(originalOptions);
2401
+
2402
+ // Load new options into the slider state
2403
+ updateAble.forEach(function(name) {
2404
+ if (optionsToUpdate[name] !== undefined) {
2405
+ options[name] = newOptions[name];
2406
+ }
2407
+ });
2408
+
2409
+ scope_Spectrum = newOptions.spectrum;
2410
+
2411
+ // Limit, margin and padding depend on the spectrum but are stored outside of it. (#677)
2412
+ options.margin = newOptions.margin;
2413
+ options.limit = newOptions.limit;
2414
+ options.padding = newOptions.padding;
2415
+
2416
+ // Update pips, removes existing.
2417
+ if (options.pips) {
2418
+ pips(options.pips);
2419
+ } else {
2420
+ removePips();
2421
+ }
2422
+
2423
+ // Update tooltips, removes existing.
2424
+ if (options.tooltips) {
2425
+ tooltips();
2426
+ } else {
2427
+ removeTooltips();
2428
+ }
2429
+
2430
+ // Invalidate the current positioning so valueSet forces an update.
2431
+ scope_Locations = [];
2432
+ valueSet(optionsToUpdate.start || v, fireSetEvent);
2433
+ }
2434
+
2435
+ // Initialization steps
2436
+ function setupSlider() {
2437
+ // Create the base element, initialize HTML and set classes.
2438
+ // Add handles and connect elements.
2439
+ scope_Base = addSlider(scope_Target);
2440
+
2441
+ addElements(options.connect, scope_Base);
2442
+
2443
+ // Attach user events.
2444
+ bindSliderEvents(options.events);
2445
+
2446
+ // Use the public value method to set the start values.
2447
+ valueSet(options.start);
2448
+
2449
+ if (options.pips) {
2450
+ pips(options.pips);
2451
+ }
2452
+
2453
+ if (options.tooltips) {
2454
+ tooltips();
2455
+ }
2456
+
2457
+ aria();
2458
+ }
2459
+
2460
+ setupSlider();
2461
+
2462
+ // noinspection JSUnusedGlobalSymbols
2463
+ scope_Self = {
2464
+ destroy: destroy,
2465
+ steps: getNextSteps,
2466
+ on: bindEvent,
2467
+ off: removeEvent,
2468
+ get: valueGet,
2469
+ set: valueSet,
2470
+ setHandle: valueSetHandle,
2471
+ reset: valueReset,
2472
+ // Exposed for unit testing, don't use this in your application.
2473
+ __moveHandles: function(a, b, c) {
2474
+ moveHandles(a, b, scope_Locations, c);
2475
+ },
2476
+ options: originalOptions, // Issue #600, #678
2477
+ updateOptions: updateOptions,
2478
+ target: scope_Target, // Issue #597
2479
+ removePips: removePips,
2480
+ removeTooltips: removeTooltips,
2481
+ pips: pips // Issue #594
2482
+ };
2483
+
2484
+ return scope_Self;
2485
+ }
2486
+
2487
+ // Run the standard initializer
2488
+ function initialize(target, originalOptions) {
2489
+ if (!target || !target.nodeName) {
2490
+ throw new Error("noUiSlider (" + VERSION + "): create requires a single element, got: " + target);
2491
+ }
2492
+
2493
+ // Throw an error if the slider was already initialized.
2494
+ if (target.noUiSlider) {
2495
+ throw new Error("noUiSlider (" + VERSION + "): Slider was already initialized.");
2496
+ }
2497
+
2498
+ // Test the options and create the slider environment;
2499
+ var options = testOptions(originalOptions, target);
2500
+ var api = scope(target, options, originalOptions);
2501
+
2502
+ target.noUiSlider = api;
2503
+
2504
+ return api;
2505
+ }
2506
+
2507
+ // Use an object instead of a function for future expandability;
2508
+ return {
2509
+ // Exposed for unit testing, don't use this in your application.
2510
+ __spectrum: Spectrum,
2511
+ version: VERSION,
2512
+ create: initialize
2513
+ };
2514
+ });