nouislider-rails 6.2.0 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,311 @@
1
+ /*jslint browser: true */
2
+ /*jslint white: true */
3
+
4
+ (function( $ ){
5
+
6
+ 'use strict';
7
+
8
+ // Helpers
9
+
10
+ // Test in an object is an instance of jQuery or Zepto.
11
+ function isInstance ( a ) {
12
+ return a instanceof $ || ( $.zepto && $.zepto.isZ(a) );
13
+ }
14
+
15
+
16
+ // Link types
17
+
18
+ function fromPrefix ( target, method ) {
19
+
20
+ // If target is a string, a new hidden input will be created.
21
+ if ( typeof target === 'string' && target.indexOf('-inline-') === 0 ) {
22
+
23
+ // By default, use the 'html' method.
24
+ this.method = method || 'html';
25
+
26
+ // Use jQuery to create the element
27
+ this.target = this.el = $( target.replace('-inline-', '') || '<div/>' );
28
+
29
+ return true;
30
+ }
31
+ }
32
+
33
+ function fromString ( target ) {
34
+
35
+ // If the string doesn't begin with '-', which is reserved, add a new hidden input.
36
+ if ( typeof target === 'string' && target.indexOf('-') !== 0 ) {
37
+
38
+ this.method = 'val';
39
+
40
+ var element = document.createElement('input');
41
+ element.name = target;
42
+ element.type = 'hidden';
43
+ this.target = this.el = $(element);
44
+
45
+ return true;
46
+ }
47
+ }
48
+
49
+ function fromFunction ( target ) {
50
+
51
+ // The target can also be a function, which will be called.
52
+ if ( typeof target === 'function' ) {
53
+ this.target = false;
54
+ this.method = target;
55
+
56
+ return true;
57
+ }
58
+ }
59
+
60
+ function fromInstance ( target, method ) {
61
+
62
+ if ( isInstance( target ) && !method ) {
63
+
64
+ // If a jQuery/Zepto input element is provided, but no method is set,
65
+ // the element can assume it needs to respond to 'change'...
66
+ if ( target.is('input, select, textarea') ) {
67
+
68
+ // Default to .val if this is an input element.
69
+ this.method = 'val';
70
+
71
+ // Fire the API changehandler when the target changes.
72
+ this.target = target.on('change.liblink', this.changeHandler);
73
+
74
+ } else {
75
+
76
+ this.target = target;
77
+
78
+ // If no method is set, and we are not auto-binding an input, default to 'html'.
79
+ this.method = 'html';
80
+ }
81
+
82
+ return true;
83
+ }
84
+ }
85
+
86
+ function fromInstanceMethod ( target, method ) {
87
+
88
+ // The method must exist on the element.
89
+ if ( isInstance( target ) &&
90
+ (typeof method === 'function' ||
91
+ (typeof method === 'string' && target[method]))
92
+ ) {
93
+ this.method = method;
94
+ this.target = target;
95
+
96
+ return true;
97
+ }
98
+ }
99
+
100
+ var
101
+ /** @const */
102
+ creationFunctions = [fromPrefix, fromString, fromFunction, fromInstance, fromInstanceMethod];
103
+
104
+
105
+ // Link Instance
106
+
107
+ /** @constructor */
108
+ function Link ( target, method, format ) {
109
+
110
+ var that = this, valid = false;
111
+
112
+ // Forward calls within scope.
113
+ this.changeHandler = function ( changeEvent ) {
114
+ var decodedValue = that.formatInstance.from( $(this).val() );
115
+
116
+ // If the value is invalid, stop this event, as well as it's propagation.
117
+ if ( decodedValue === false || isNaN(decodedValue) ) {
118
+
119
+ // Reset the value.
120
+ $(this).val(that.lastSetValue);
121
+ return false;
122
+ }
123
+
124
+ that.changeHandlerMethod.call( '', changeEvent, decodedValue );
125
+ };
126
+
127
+ // See if this Link needs individual targets based on its usage.
128
+ // If so, return the element that needs to be copied by the
129
+ // implementing interface.
130
+ // Default the element to false.
131
+ this.el = false;
132
+
133
+ // Store the formatter, or use the default.
134
+ this.formatInstance = format;
135
+
136
+ // Try all Link types.
137
+ /*jslint unparam: true*/
138
+ $.each(creationFunctions, function(i, fn){
139
+ valid = fn.call(that, target, method);
140
+ return !valid;
141
+ });
142
+ /*jslint unparam: false*/
143
+
144
+ // Nothing matched, throw error.
145
+ if ( !valid ) {
146
+ throw new RangeError("(Link) Invalid Link.");
147
+ }
148
+ }
149
+
150
+ // Provides external items with the object value.
151
+ Link.prototype.set = function ( value ) {
152
+
153
+ // Ignore the value, so only the passed-on arguments remain.
154
+ var args = Array.prototype.slice.call( arguments ),
155
+ additionalArgs = args.slice(1);
156
+
157
+ // Store some values. The actual, numerical value,
158
+ // the formatted value and the parameters for use in 'resetValue'.
159
+ // Slice additionalArgs to break the relation.
160
+ this.lastSetValue = this.formatInstance.to( value );
161
+
162
+ // Prepend the value to the function arguments.
163
+ additionalArgs.unshift(
164
+ this.lastSetValue
165
+ );
166
+
167
+ // When target is undefined, the target was a function.
168
+ // In that case, provided the object as the calling scope.
169
+ // Branch between writing to a function or an object.
170
+ ( typeof this.method === 'function' ?
171
+ this.method :
172
+ this.target[ this.method ] ).apply( this.target, additionalArgs );
173
+ };
174
+
175
+
176
+ // Developer API
177
+
178
+ /** @constructor */
179
+ function LinkAPI ( origin ) {
180
+ this.items = [];
181
+ this.elements = [];
182
+ this.origin = origin;
183
+ }
184
+
185
+ LinkAPI.prototype.push = function( item, element ) {
186
+ this.items.push(item);
187
+
188
+ // Prevent 'false' elements
189
+ if ( element ) {
190
+ this.elements.push(element);
191
+ }
192
+ };
193
+
194
+ LinkAPI.prototype.reconfirm = function ( flag ) {
195
+ var i;
196
+ for ( i = 0; i < this.elements.length; i += 1 ) {
197
+ this.origin.LinkConfirm(flag, this.elements[i]);
198
+ }
199
+ };
200
+
201
+ LinkAPI.prototype.remove = function ( flag ) {
202
+ var i;
203
+ for ( i = 0; i < this.items.length; i += 1 ) {
204
+ this.items[i].target.off('.liblink');
205
+ }
206
+ for ( i = 0; i < this.elements.length; i += 1 ) {
207
+ this.elements[i].remove();
208
+ }
209
+ };
210
+
211
+ LinkAPI.prototype.change = function ( value ) {
212
+
213
+ if ( this.origin.LinkIsEmitting ) {
214
+ return false;
215
+ }
216
+
217
+ this.origin.LinkIsEmitting = true;
218
+
219
+ var args = Array.prototype.slice.call( arguments, 1 ), i;
220
+ args.unshift( value );
221
+
222
+ // Write values to serialization Links.
223
+ // Convert the value to the correct relative representation.
224
+ for ( i = 0; i < this.items.length; i += 1 ) {
225
+ this.items[i].set.apply(this.items[i], args);
226
+ }
227
+
228
+ this.origin.LinkIsEmitting = false;
229
+ };
230
+
231
+
232
+ // jQuery plugin
233
+
234
+ function binder ( flag, target, method, format ){
235
+
236
+ if ( flag === 0 ) {
237
+ flag = this.LinkDefaultFlag;
238
+ }
239
+
240
+ // Create a list of API's (if it didn't exist yet);
241
+ if ( !this.linkAPI ) {
242
+ this.linkAPI = {};
243
+ }
244
+
245
+ // Add an API point.
246
+ if ( !this.linkAPI[flag] ) {
247
+ this.linkAPI[flag] = new LinkAPI(this);
248
+ }
249
+
250
+ var linkInstance = new Link ( target, method, format || this.LinkDefaultFormatter );
251
+
252
+ // Default the calling scope to the linked object.
253
+ if ( !linkInstance.target ) {
254
+ linkInstance.target = $(this);
255
+ }
256
+
257
+ // If the Link requires creation of a new element,
258
+ // Pass the element and request confirmation to get the changehandler.
259
+ // Set the method to be called when a Link changes.
260
+ linkInstance.changeHandlerMethod = this.LinkConfirm( flag, linkInstance.el );
261
+
262
+ // Store the linkInstance in the flagged list.
263
+ this.linkAPI[flag].push( linkInstance, linkInstance.el );
264
+
265
+ // Now that Link have been connected, request an update.
266
+ this.LinkUpdate( flag );
267
+ }
268
+
269
+ /** @export */
270
+ $.fn.Link = function( flag ){
271
+
272
+ var that = this;
273
+
274
+ // Delete all linkAPI
275
+ if ( flag === false ) {
276
+
277
+ return that.each(function(){
278
+
279
+ // .Link(false) can be called on elements without Links.
280
+ // When that happens, the objects can't be looped.
281
+ if ( !this.linkAPI ) {
282
+ return;
283
+ }
284
+
285
+ $.map(this.linkAPI, function(api){
286
+ api.remove();
287
+ });
288
+
289
+ delete this.linkAPI;
290
+ });
291
+ }
292
+
293
+ if ( flag === undefined ) {
294
+
295
+ flag = 0;
296
+
297
+ } else if ( typeof flag !== 'string') {
298
+
299
+ throw new Error("Flag must be string.");
300
+ }
301
+
302
+ return {
303
+ to: function( a, b, c ){
304
+ return that.each(function(){
305
+ binder.call(this, flag, a, b, c);
306
+ });
307
+ }
308
+ };
309
+ };
310
+
311
+ }( window.jQuery || window.Zepto ));
@@ -0,0 +1,872 @@
1
+ /*jslint browser: true */
2
+ /*jslint white: true */
3
+
4
+ (function( $ ){
5
+
6
+ 'use strict';
7
+
8
+ var
9
+ // Cache the document selector;
10
+ /** @const */
11
+ doc = $(document),
12
+ // Make a backup of the original jQuery/Zepto .val() method.
13
+ /** @const */
14
+ $val = $.fn.val,
15
+ // Namespace for binding and unbinding slider events;
16
+ /** @const */
17
+ namespace = '.nui',
18
+ // Determine the events to bind. IE11 implements pointerEvents without
19
+ // a prefix, which breaks compatibility with the IE10 implementation.
20
+ /** @const */
21
+ actions = window.navigator.pointerEnabled ? {
22
+ start: 'pointerdown',
23
+ move: 'pointermove',
24
+ end: 'pointerup'
25
+ } : window.navigator.msPointerEnabled ? {
26
+ start: 'MSPointerDown',
27
+ move: 'MSPointerMove',
28
+ end: 'MSPointerUp'
29
+ } : {
30
+ start: 'mousedown touchstart',
31
+ move: 'mousemove touchmove',
32
+ end: 'mouseup touchend'
33
+ },
34
+ // Re-usable list of classes;
35
+ /** @const */
36
+ Classes = [
37
+ /* 0 */ 'noUi-target'
38
+ /* 1 */ ,'noUi-base'
39
+ /* 2 */ ,'noUi-origin'
40
+ /* 3 */ ,'noUi-handle'
41
+ /* 4 */ ,'noUi-horizontal'
42
+ /* 5 */ ,'noUi-vertical'
43
+ /* 6 */ ,'noUi-background'
44
+ /* 7 */ ,'noUi-connect'
45
+ /* 8 */ ,'noUi-ltr'
46
+ /* 9 */ ,'noUi-rtl'
47
+ /* 10 */ ,'noUi-dragable'
48
+ /* 11 */ ,''
49
+ /* 12 */ ,'noUi-state-drag'
50
+ /* 13 */ ,''
51
+ /* 14 */ ,'noUi-state-tap'
52
+ /* 15 */ ,'noUi-active'
53
+ /* 16 */ ,''
54
+ /* 17 */ ,'noUi-stacking'
55
+ ];
56
+
57
+
58
+ // General helpers
59
+
60
+ // Limits a value to 0 - 100
61
+ function limit ( a ) {
62
+ return Math.max(Math.min(a, 100), 0);
63
+ }
64
+
65
+ // Wraps a variable as an array, if it isn't one yet.
66
+ function asArray ( a ) {
67
+ return $.isArray(a) ? a : [a];
68
+ }
69
+
70
+
71
+ // Class handling
72
+
73
+ // Sets a class and removes it after [duration] ms.
74
+ function addClassFor ( element, className, duration ) {
75
+ element.addClass(className);
76
+ setTimeout(function(){
77
+ element.removeClass(className);
78
+ }, duration);
79
+ }
80
+
81
+ // Delimit proposed values for handle positions.
82
+ function getPositions ( a, b, delimit ) {
83
+
84
+ // Add movement to current position.
85
+ var c = a + b[0], d = a + b[1];
86
+
87
+ // Only alter the other position on drag,
88
+ // not on standard sliding.
89
+ if ( delimit ) {
90
+ if ( c < 0 ) {
91
+ d += Math.abs(c);
92
+ }
93
+ if ( d > 100 ) {
94
+ c -= ( d - 100 );
95
+ }
96
+
97
+ // Limit values to 0 and 100.
98
+ return [limit(c), limit(d)];
99
+ }
100
+
101
+ return [c,d];
102
+ }
103
+
104
+
105
+
106
+ // Event handling
107
+
108
+ // Provide a clean event with standardized offset values.
109
+ function fixEvent ( e ) {
110
+
111
+ // Prevent scrolling and panning on touch events, while
112
+ // attempting to slide. The tap event also depends on this.
113
+ e.preventDefault();
114
+
115
+ // Filter the event to register the type, which can be
116
+ // touch, mouse or pointer. Offset changes need to be
117
+ // made on an event specific basis.
118
+ var touch = e.type.indexOf('touch') === 0
119
+ ,mouse = e.type.indexOf('mouse') === 0
120
+ ,pointer = e.type.indexOf('pointer') === 0
121
+ ,x,y, event = e;
122
+
123
+ // IE10 implemented pointer events with a prefix;
124
+ if ( e.type.indexOf('MSPointer') === 0 ) {
125
+ pointer = true;
126
+ }
127
+
128
+ // Get the originalEvent, if the event has been wrapped
129
+ // by jQuery. Zepto doesn't wrap the event.
130
+ if ( e.originalEvent ) {
131
+ e = e.originalEvent;
132
+ }
133
+
134
+ if ( touch ) {
135
+ // noUiSlider supports one movement at a time,
136
+ // so we can select the first 'changedTouch'.
137
+ x = e.changedTouches[0].pageX;
138
+ y = e.changedTouches[0].pageY;
139
+ }
140
+
141
+ if ( mouse || pointer ) {
142
+
143
+ // Polyfill the pageXOffset and pageYOffset
144
+ // variables for IE7 and IE8;
145
+ if( !pointer && window.pageXOffset === undefined ){
146
+ window.pageXOffset = document.documentElement.scrollLeft;
147
+ window.pageYOffset = document.documentElement.scrollTop;
148
+ }
149
+
150
+ x = e.clientX + window.pageXOffset;
151
+ y = e.clientY + window.pageYOffset;
152
+ }
153
+
154
+ event.points = [x, y];
155
+ event.cursor = mouse;
156
+
157
+ return event;
158
+ }
159
+
160
+
161
+ // DOM additions
162
+
163
+ // Append a handle to the base.
164
+ function addHandle ( direction, index ) {
165
+
166
+ var handle = $('<div><div/></div>').addClass( Classes[2] ),
167
+ additions = [ '-lower', '-upper' ];
168
+
169
+ if ( direction ) {
170
+ additions.reverse();
171
+ }
172
+
173
+ handle.children().addClass(
174
+ Classes[3] + " " + Classes[3]+additions[index]
175
+ );
176
+
177
+ return handle;
178
+ }
179
+
180
+ // Add the proper connection classes.
181
+ function addConnection ( connect, target, handles ) {
182
+
183
+ // Apply the required connection classes to the elements
184
+ // that need them. Some classes are made up for several
185
+ // segments listed in the class list, to allow easy
186
+ // renaming and provide a minor compression benefit.
187
+ switch ( connect ) {
188
+ case 1: target.addClass( Classes[7] );
189
+ handles[0].addClass( Classes[6] );
190
+ break;
191
+ case 3: handles[1].addClass( Classes[6] );
192
+ /* falls through */
193
+ case 2: handles[0].addClass( Classes[7] );
194
+ /* falls through */
195
+ case 0: target.addClass(Classes[6]);
196
+ break;
197
+ }
198
+ }
199
+
200
+ // Add handles to the slider base.
201
+ function addHandles ( nrHandles, direction, base ) {
202
+
203
+ var index, handles = [];
204
+
205
+ // Append handles.
206
+ for ( index = 0; index < nrHandles; index += 1 ) {
207
+
208
+ // Keep a list of all added handles.
209
+ handles.push( addHandle( direction, index ).appendTo(base) );
210
+ }
211
+
212
+ return handles;
213
+ }
214
+
215
+ // Initialize a single slider.
216
+ function addSlider ( direction, orientation, target ) {
217
+
218
+ // Apply classes and data to the target.
219
+ target.addClass([
220
+ Classes[0],
221
+ Classes[8 + direction],
222
+ Classes[4 + orientation]
223
+ ].join(' '));
224
+
225
+ return $('<div/>').appendTo(target).addClass( Classes[1] );
226
+ }
227
+
228
+
229
+ // Slider scope
230
+
231
+ function closure ( target, options, originalOptions ){
232
+
233
+ // Internal variables
234
+
235
+ // All variables local to 'closure' are marked $.
236
+ var $Target = $(target),
237
+ $Locations = [-1, -1],
238
+ $Base,
239
+ $Handles,
240
+ $Spectrum = options.spectrum,
241
+ $Values = [],
242
+ // libLink. For rtl sliders, 'lower' and 'upper' should not be inverted
243
+ // for one-handle sliders, so trim 'upper' it that case.
244
+ triggerPos = ['lower', 'upper'].slice(0, options.handles);
245
+
246
+ // Invert the libLink connection for rtl sliders.
247
+ if ( options.dir ) {
248
+ triggerPos.reverse();
249
+ }
250
+
251
+
252
+ // Helpers
253
+
254
+ // Shorthand for base dimensions.
255
+ function baseSize ( ) {
256
+ return $Base[['width', 'height'][options.ort]]();
257
+ }
258
+
259
+ // External event handling
260
+ function fireEvents ( events ) {
261
+
262
+ // Use the external api to get the values.
263
+ // Wrap the values in an array, as .trigger takes
264
+ // only one additional argument.
265
+ var index, values = [ $Target.val() ];
266
+
267
+ for ( index = 0; index < events.length; index += 1 ){
268
+ $Target.trigger(events[index], values);
269
+ }
270
+ }
271
+
272
+ // Returns the input array, respecting the slider direction configuration.
273
+ function inSliderOrder ( values ) {
274
+
275
+ // If only one handle is used, return a single value.
276
+ if ( values.length === 1 ){
277
+ return values[0];
278
+ }
279
+
280
+ if ( options.dir ) {
281
+ return values.reverse();
282
+ }
283
+
284
+ return values;
285
+ }
286
+
287
+
288
+ // libLink integration
289
+
290
+ // Create a new function which calls .val on input change.
291
+ function createChangeHandler ( trigger ) {
292
+ return function ( ignore, value ){
293
+ // Determine which array position to 'null' based on 'trigger'.
294
+ $Target.val( [ trigger ? null : value, trigger ? value : null ], true );
295
+ };
296
+ }
297
+
298
+ // Called by libLink when it wants a set of links updated.
299
+ function linkUpdate ( flag ) {
300
+
301
+ var trigger = $.inArray(flag, triggerPos);
302
+
303
+ // The API might not have been set yet.
304
+ if ( $Target[0].linkAPI && $Target[0].linkAPI[flag] ) {
305
+ $Target[0].linkAPI[flag].change(
306
+ $Values[trigger],
307
+ $Handles[trigger].children(),
308
+ $Target
309
+ );
310
+ }
311
+ }
312
+
313
+ // Called by libLink to append an element to the slider.
314
+ function linkConfirm ( flag, element ) {
315
+
316
+ // Find the trigger for the passed flag.
317
+ var trigger = $.inArray(flag, triggerPos);
318
+
319
+ // If set, append the element to the handle it belongs to.
320
+ if ( element ) {
321
+ element.appendTo( $Handles[trigger].children() );
322
+ }
323
+
324
+ // The public API is reversed for rtl sliders, so the changeHandler
325
+ // should not be aware of the inverted trigger positions.
326
+ if ( options.dir ) {
327
+ trigger = trigger === 1 ? 0 : 1;
328
+ }
329
+
330
+ return createChangeHandler( trigger );
331
+ }
332
+
333
+ // Place elements back on the slider.
334
+ function reAppendLink ( ) {
335
+
336
+ var i, flag;
337
+
338
+ // The API keeps a list of elements: we can re-append them on rebuild.
339
+ for ( i = 0; i < triggerPos.length; i += 1 ) {
340
+ if ( this.linkAPI && this.linkAPI[(flag = triggerPos[i])] ) {
341
+ this.linkAPI[flag].reconfirm(flag);
342
+ }
343
+ }
344
+ }
345
+
346
+ target.LinkUpdate = linkUpdate;
347
+ target.LinkConfirm = linkConfirm;
348
+ target.LinkDefaultFormatter = options.format;
349
+ target.LinkDefaultFlag = 'lower';
350
+
351
+ target.reappend = reAppendLink;
352
+
353
+
354
+ // Test suggested values and apply margin, step.
355
+ function setHandle ( handle, to, noLimitOption ) {
356
+
357
+ var trigger = handle[0] !== $Handles[0][0] ? 1 : 0,
358
+ lowerMargin = $Locations[0] + options.margin,
359
+ upperMargin = $Locations[1] - options.margin,
360
+ lowerLimit = $Locations[0] + options.limit,
361
+ upperLimit = $Locations[1] - options.limit;
362
+
363
+ // For sliders with multiple handles,
364
+ // limit movement to the other handle.
365
+ // Apply the margin option by adding it to the handle positions.
366
+ if ( $Handles.length > 1 ) {
367
+ to = trigger ? Math.max( to, lowerMargin ) : Math.min( to, upperMargin );
368
+ }
369
+
370
+ // The limit option has the opposite effect, limiting handles to a
371
+ // maximum distance from another. Limit must be > 0, as otherwise
372
+ // handles would be unmoveable. 'noLimitOption' is set to 'false'
373
+ // for the .val() method, except for pass 4/4.
374
+ if ( noLimitOption !== false && options.limit && $Handles.length > 1 ) {
375
+ to = trigger ? Math.min ( to, lowerLimit ) : Math.max( to, upperLimit );
376
+ }
377
+
378
+ // Handle the step option.
379
+ to = $Spectrum.getStep( to );
380
+
381
+ // Limit to 0/100 for .val input, trim anything beyond 7 digits, as
382
+ // JavaScript has some issues in its floating point implementation.
383
+ to = limit(parseFloat(to.toFixed(7)));
384
+
385
+ // Return false if handle can't move.
386
+ if ( to === $Locations[trigger] ) {
387
+ return false;
388
+ }
389
+
390
+ // Set the handle to the new position.
391
+ handle.css( options.style, to + '%' );
392
+
393
+ // Force proper handle stacking
394
+ if ( handle.is(':first-child') ) {
395
+ handle.toggleClass(Classes[17], to > 50 );
396
+ }
397
+
398
+ // Update locations.
399
+ $Locations[trigger] = to;
400
+
401
+ // Convert the value to the slider stepping/range.
402
+ $Values[trigger] = $Spectrum.fromStepping( to );
403
+
404
+ linkUpdate(triggerPos[trigger]);
405
+
406
+ return true;
407
+ }
408
+
409
+ // Loop values from value method and apply them.
410
+ function setValues ( count, values ) {
411
+
412
+ var i, trigger, to;
413
+
414
+ // With the limit option, we'll need another limiting pass.
415
+ if ( options.limit ) {
416
+ count += 1;
417
+ }
418
+
419
+ // If there are multiple handles to be set run the setting
420
+ // mechanism twice for the first handle, to make sure it
421
+ // can be bounced of the second one properly.
422
+ for ( i = 0; i < count; i += 1 ) {
423
+
424
+ trigger = i%2;
425
+
426
+ // Get the current argument from the array.
427
+ to = values[trigger];
428
+
429
+ // Setting with null indicates an 'ignore'.
430
+ // Inputting 'false' is invalid.
431
+ if ( to !== null && to !== false ) {
432
+
433
+ // If a formatted number was passed, attemt to decode it.
434
+ if ( typeof to === 'number' ) {
435
+ to = String(to);
436
+ }
437
+
438
+ to = options.format.from( to );
439
+
440
+ // Request an update for all links if the value was invalid.
441
+ // Do so too if setting the handle fails.
442
+ if ( to === false || isNaN(to) || setHandle( $Handles[trigger], $Spectrum.toStepping( to ), i === (3 - options.dir) ) === false ) {
443
+
444
+ linkUpdate(triggerPos[trigger]);
445
+ }
446
+ }
447
+ }
448
+ }
449
+
450
+
451
+
452
+ // Handler for attaching events trough a proxy.
453
+ function attach ( events, element, callback, data ) {
454
+
455
+ // This function can be used to 'filter' events to the slider.
456
+
457
+ // Add the noUiSlider namespace to all events.
458
+ events = events.replace( /\s/g, namespace + ' ' ) + namespace;
459
+
460
+ // Bind a closure on the target.
461
+ return element.on( events, function( e ){
462
+
463
+ // jQuery and Zepto (1) handle unset attributes differently,
464
+ // but always falsy; #208
465
+ if ( !!$Target.attr('disabled') ) {
466
+ return false;
467
+ }
468
+
469
+ // Stop if an active 'tap' transition is taking place.
470
+ if ( $Target.hasClass( Classes[14] ) ) {
471
+ return false;
472
+ }
473
+
474
+ e = fixEvent(e);
475
+ e.calcPoint = e.points[ options.ort ];
476
+
477
+ // Call the event handler with the event [ and additional data ].
478
+ callback ( e, data );
479
+ });
480
+ }
481
+
482
+ // Handle movement on document for handle and range drag.
483
+ function move ( event, data ) {
484
+
485
+ var handles = data.handles || $Handles, positions, state = false,
486
+ proposal = ((event.calcPoint - data.start) * 100) / baseSize(),
487
+ h = handles[0][0] !== $Handles[0][0] ? 1 : 0;
488
+
489
+ // Calculate relative positions for the handles.
490
+ positions = getPositions( proposal, data.positions, handles.length > 1);
491
+
492
+ state = setHandle ( handles[0], positions[h], handles.length === 1 );
493
+
494
+ if ( handles.length > 1 ) {
495
+ state = setHandle ( handles[1], positions[h?0:1], false ) || state;
496
+ }
497
+
498
+ // Fire the 'slide' event if any handle moved.
499
+ if ( state ) {
500
+ fireEvents(['slide']);
501
+ }
502
+ }
503
+
504
+ // Unbind move events on document, call callbacks.
505
+ function end ( event ) {
506
+
507
+ // The handle is no longer active, so remove the class.
508
+ $('.' + Classes[15]).removeClass(Classes[15]);
509
+
510
+ // Remove cursor styles and text-selection events bound to the body.
511
+ if ( event.cursor ) {
512
+ $('body').css('cursor', '').off( namespace );
513
+ }
514
+
515
+ // Unbind the move and end events, which are added on 'start'.
516
+ doc.off( namespace );
517
+
518
+ // Remove dragging class.
519
+ $Target.removeClass(Classes[12]);
520
+
521
+ // Fire the change and set events.
522
+ fireEvents(['set', 'change']);
523
+ }
524
+
525
+ // Bind move events on document.
526
+ function start ( event, data ) {
527
+
528
+ // Mark the handle as 'active' so it can be styled.
529
+ if( data.handles.length === 1 ) {
530
+ data.handles[0].children().addClass(Classes[15]);
531
+ }
532
+
533
+ // A drag should never propagate up to the 'tap' event.
534
+ event.stopPropagation();
535
+
536
+ // Attach the move event.
537
+ attach ( actions.move, doc, move, {
538
+ start: event.calcPoint,
539
+ handles: data.handles,
540
+ positions: [
541
+ $Locations[0],
542
+ $Locations[$Handles.length - 1]
543
+ ]
544
+ });
545
+
546
+ // Unbind all movement when the drag ends.
547
+ attach ( actions.end, doc, end, null );
548
+
549
+ // Text selection isn't an issue on touch devices,
550
+ // so adding cursor styles can be skipped.
551
+ if ( event.cursor ) {
552
+
553
+ // Prevent the 'I' cursor and extend the range-drag cursor.
554
+ $('body').css('cursor', $(event.target).css('cursor'));
555
+
556
+ // Mark the target with a dragging state.
557
+ if ( $Handles.length > 1 ) {
558
+ $Target.addClass(Classes[12]);
559
+ }
560
+
561
+ // Prevent text selection when dragging the handles.
562
+ $('body').on('selectstart' + namespace, false);
563
+ }
564
+ }
565
+
566
+ // Move closest handle to tapped location.
567
+ function tap ( event ) {
568
+
569
+ var location = event.calcPoint, total = 0, to;
570
+
571
+ // The tap event shouldn't propagate up and cause 'edge' to run.
572
+ event.stopPropagation();
573
+
574
+ // Add up the handle offsets.
575
+ $.each( $Handles, function(){
576
+ total += this.offset()[ options.style ];
577
+ });
578
+
579
+ // Find the handle closest to the tapped position.
580
+ total = ( location < total/2 || $Handles.length === 1 ) ? 0 : 1;
581
+
582
+ location -= $Base.offset()[ options.style ];
583
+
584
+ // Calculate the new position.
585
+ to = ( location * 100 ) / baseSize();
586
+
587
+ if ( !options.events.snap ) {
588
+ // Flag the slider as it is now in a transitional state.
589
+ // Transition takes 300 ms, so re-enable the slider afterwards.
590
+ addClassFor( $Target, Classes[14], 300 );
591
+ }
592
+
593
+ // Find the closest handle and calculate the tapped point.
594
+ // The set handle to the new position.
595
+ setHandle( $Handles[total], to );
596
+
597
+ fireEvents(['slide', 'set', 'change']);
598
+
599
+ if ( options.events.snap ) {
600
+ start(event, { handles: [$Handles[total]] });
601
+ }
602
+ }
603
+
604
+ // Attach events to several slider parts.
605
+ function events ( behaviour ) {
606
+
607
+ var i, drag;
608
+
609
+ // Attach the standard drag event to the handles.
610
+ if ( !behaviour.fixed ) {
611
+
612
+ for ( i = 0; i < $Handles.length; i += 1 ) {
613
+
614
+ // These events are only bound to the visual handle
615
+ // element, not the 'real' origin element.
616
+ attach ( actions.start, $Handles[i].children(), start, {
617
+ handles: [ $Handles[i] ]
618
+ });
619
+ }
620
+ }
621
+
622
+ // Attach the tap event to the slider base.
623
+ if ( behaviour.tap ) {
624
+
625
+ attach ( actions.start, $Base, tap, {
626
+ handles: $Handles
627
+ });
628
+ }
629
+
630
+ // Make the range dragable.
631
+ if ( behaviour.drag ){
632
+
633
+ drag = $Base.find( '.' + Classes[7] ).addClass( Classes[10] );
634
+
635
+ // When the range is fixed, the entire range can
636
+ // be dragged by the handles. The handle in the first
637
+ // origin will propagate the start event upward,
638
+ // but it needs to be bound manually on the other.
639
+ if ( behaviour.fixed ) {
640
+ drag = drag.add($Base.children().not( drag ).children());
641
+ }
642
+
643
+ attach ( actions.start, drag, start, {
644
+ handles: $Handles
645
+ });
646
+ }
647
+ }
648
+
649
+
650
+
651
+ // Set the slider value.
652
+ function valueSet ( input ) {
653
+
654
+ // LibLink: don't accept new values when currently emitting changes.
655
+ if ( $Target[0].LinkIsEmitting ) {
656
+ return this;
657
+ }
658
+
659
+ var count, values = asArray( input );
660
+
661
+ // The RTL settings is implemented by reversing the front-end,
662
+ // internal mechanisms are the same.
663
+ if ( options.dir && options.handles > 1 ) {
664
+ values.reverse();
665
+ }
666
+
667
+ // Animation is optional.
668
+ // Make sure the initial values where set before using animated
669
+ // placement. (no report, unit testing);
670
+ if ( options.animate && $Locations[0] !== -1 ) {
671
+ addClassFor( $Target, Classes[14], 300 );
672
+ }
673
+
674
+ // Determine how often to set the handles.
675
+ count = $Handles.length > 1 ? 3 : 1;
676
+
677
+ if ( values.length === 1 ) {
678
+ count = 1;
679
+ }
680
+
681
+ setValues ( count, values );
682
+
683
+ // Fire the 'set' event. As of noUiSlider 7,
684
+ // this is no longer optional.
685
+ fireEvents(['set']);
686
+
687
+ return this;
688
+ }
689
+
690
+ // Get the slider value.
691
+ function valueGet ( ) {
692
+
693
+ var i, retour = [];
694
+
695
+ // Get the value from all handles.
696
+ for ( i = 0; i < options.handles; i += 1 ){
697
+ retour[i] = options.format.to( $Values[i] );
698
+ }
699
+
700
+ return inSliderOrder( retour );
701
+ }
702
+
703
+
704
+
705
+ // Destroy the slider and unbind all events.
706
+ function destroyTarget ( ) {
707
+
708
+ // Unbind events on the slider, remove all classes and child elements.
709
+ $(this).off(namespace)
710
+ .removeClass(Classes.join(' '))
711
+ .empty();
712
+
713
+ delete this.LinkUpdate;
714
+ delete this.LinkConfirm;
715
+ delete this.LinkDefaultFormatter;
716
+ delete this.LinkDefaultFlag;
717
+ delete this.reappend;
718
+ delete this.vGet;
719
+ delete this.vSet;
720
+ delete this.getCurrentStep;
721
+ delete this.getInfo;
722
+ delete this.destroy;
723
+
724
+ // Return the original options from the closure.
725
+ return originalOptions;
726
+ }
727
+
728
+ // Get the current step size for the slider.
729
+ function getCurrentStep ( ) {
730
+
731
+ // Check all locations, map them to their stepping point.
732
+ // Get the step point, then find it in the input list.
733
+ var retour = $.map($Locations, function( location, index ){
734
+
735
+ var step = $Spectrum.getApplicableStep( location ),
736
+ value = $Values[index],
737
+ increment = step[2],
738
+ decrement = (value - step[2]) >= step[1] ? step[2] : step[0];
739
+
740
+ return [[decrement, increment]];
741
+ });
742
+
743
+ // Return values in the proper order.
744
+ return inSliderOrder( retour );
745
+ }
746
+
747
+
748
+
749
+ // Initialize slider
750
+
751
+ // Throw an error if the slider was already initialized.
752
+ if ( $Target.hasClass(Classes[0]) ) {
753
+ throw new Error('Slider was already initialized.');
754
+ }
755
+
756
+ // Create the base element, initialise HTML and set classes.
757
+ // Add handles and links.
758
+ $Base = addSlider( options.dir, options.ort, $Target );
759
+ $Handles = addHandles( options.handles, options.dir, $Base );
760
+
761
+ // Set the connect classes.
762
+ addConnection ( options.connect, $Target, $Handles );
763
+
764
+ // Attach user events.
765
+ events( options.events );
766
+
767
+ // Methods
768
+
769
+ target.vSet = valueSet;
770
+ target.vGet = valueGet;
771
+ target.destroy = destroyTarget;
772
+ target.getCurrentStep = getCurrentStep;
773
+ target.getInfo = function(){
774
+ return [
775
+ $Spectrum,
776
+ options.style,
777
+ options.ort
778
+ ];
779
+ };
780
+
781
+ // Use the public value method to set the start values.
782
+ $Target.val( options.start );
783
+ }
784
+
785
+
786
+ // Access points
787
+
788
+ // Run the standard initializer
789
+ function initialize ( originalOptions ) {
790
+
791
+ // Throw error if group is empty.
792
+ if ( !this.length ){
793
+ throw new Error("noUiSlider: Can't initialize slider on empty selection.");
794
+ }
795
+
796
+ // Test the options once, not for every slider.
797
+ var options = $.noUiSlider.testOptions( originalOptions, this );
798
+
799
+ // Loop all items, and provide a new closed-scope environment.
800
+ return this.each(function(){
801
+ closure(this, options, originalOptions);
802
+ });
803
+ }
804
+
805
+ // Destroy the slider, then re-enter initialization.
806
+ function rebuild ( options ) {
807
+
808
+ return this.each(function(){
809
+
810
+ // The rebuild flag can be used if the slider wasn't initialized yet.
811
+ if ( !this.destroy ) {
812
+ $(this).noUiSlider( options );
813
+ return;
814
+ }
815
+
816
+ // Get the current values from the slider,
817
+ // including the initialization options.
818
+ var values = $(this).val(), originalOptions = this.destroy(),
819
+
820
+ // Extend the previous options with the newly provided ones.
821
+ newOptions = $.extend( {}, originalOptions, options );
822
+
823
+ // Run the standard initializer.
824
+ $(this).noUiSlider( newOptions );
825
+
826
+ // Place Link elements back.
827
+ this.reappend();
828
+
829
+ // If the start option hasn't changed,
830
+ // reset the previous values.
831
+ if ( originalOptions.start === newOptions.start ) {
832
+ $(this).val(values);
833
+ }
834
+ });
835
+ }
836
+
837
+ // Access the internal getting and setting methods based on argument count.
838
+ function value ( ) {
839
+ return this[0][ !arguments.length ? 'vGet' : 'vSet' ].apply(this[0], arguments);
840
+ }
841
+
842
+ // Override the .val() method. Test every element. Is it a slider? Go to
843
+ // the slider value handling. No? Use the standard method.
844
+ // Note how $.fn.val expects 'this' to be an instance of $. For convenience,
845
+ // the above 'value' function does too.
846
+ $.fn.val = function ( ) {
847
+
848
+ // this === instanceof $
849
+
850
+ function valMethod( a ){
851
+ return a.hasClass(Classes[0]) ? value : $val;
852
+ }
853
+
854
+ var args = arguments,
855
+ first = $(this[0]);
856
+
857
+ if ( !arguments.length ) {
858
+ return valMethod(first).call(first);
859
+ }
860
+
861
+ // Return the set so it remains chainable
862
+ return this.each(function(){
863
+ valMethod($(this)).apply($(this), args);
864
+ });
865
+ };
866
+
867
+ // Extend jQuery/Zepto with the noUiSlider method.
868
+ $.fn.noUiSlider = function ( options, rebuildFlag ) {
869
+ return ( rebuildFlag ? rebuild : initialize ).call(this, options);
870
+ };
871
+
872
+ }( window.jQuery || window.Zepto ));