jquery-nouislider-rails 3.2.1 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -18,15 +18,11 @@ And then execute:
18
18
  In your app/assets/javascript manifest file:
19
19
  //=require jquery.nouislider
20
20
 
21
- In your app/assets/stylesheets manifest file, you can include either of the default slider styles:
22
-
23
- //=require 'nouislider.fox.css'
24
-
25
- or
26
-
27
- //=require 'nouislider.space.css'
21
+ In your app/assets/stylesheets manifest file:
22
+ //=require jquery.nouislider
28
23
 
29
- You are encouraged to use your own stylesheet, but these two will give you a good base to start from.
24
+ You are encouraged to use your own stylesheet. The styles for 4.0 have change significantly.
25
+ A reference is here: http://refreshless.com/nouislider/slider-design-styles
30
26
 
31
27
  ## Contributing
32
28
 
@@ -1,7 +1,7 @@
1
1
  module Jquery
2
2
  module Nouislider
3
3
  module Rails
4
- VERSION = "3.2.1"
4
+ VERSION = "4.0.1"
5
5
  end
6
6
  end
7
7
  end
@@ -1,364 +1,826 @@
1
- /* noUiSlider 3.2.1 */
2
- (function ($) {
3
-
4
- $.fn.noUiSlider = function (options, flag) {
5
-
6
- // test for mouse, pointer or touch
7
- var EVENT = window.navigator.msPointerEnabled ? 2 : 'ontouchend' in document ? 3 : 1;
8
- if (window.debug && console) {
9
- console.log(EVENT);
10
- }
11
-
12
- // shorthand for test=function, calling
13
- function call(f, scope, args) {
14
- if (typeof f === "function") {
15
- f.call(scope, args);
1
+ /* noUiSlider 4.0.0 */
2
+ (function($, UNDEF){
3
+
4
+ $.fn.noUiSlider = function( options ){
5
+
6
+ var namespace = '.nui'
7
+ // Create a shorthand for document event binding
8
+ ,all = $(document)
9
+ // Create a map of touch and mouse actions
10
+ ,actions = {
11
+ start: 'mousedown' + namespace + ' touchstart' + namespace
12
+ ,move: 'mousemove' + namespace + ' touchmove' + namespace
13
+ ,end: 'mouseup' + namespace + ' touchend' + namespace
16
14
  }
17
- }
18
-
19
- // function wrapper for calculating to and from range values
20
- var percentage = {
21
- to : function (range, value) {
22
- value = range[0] < 0 ? value + Math.abs(range[0]) : value - range[0];
23
- return (value * 100) / this._length(range);
24
- },
25
- from : function (range, value) {
26
- return (value * 100) / this._length(range);
27
- },
28
- is : function (range, value) {
29
- return ((value * this._length(range)) / 100) + range[0];
30
- },
31
- _length : function (range) {
32
- return (range[0] > range[1] ? range[0] - range[1] : range[1] - range[0]);
15
+ // Make a copy of the current val function.
16
+ ,$VAL = $.fn.val
17
+ // Define a set of standard HTML classes for
18
+ // the various structures noUiSlider uses.
19
+ ,clsList = [
20
+ 'noUi-base' // 0
21
+ ,'noUi-origin' // 1
22
+ ,'noUi-handle' // 2
23
+ ,'noUi-input' // 3
24
+ ,'noUi-active' // 4
25
+ ,'noUi-state-tap' // 5
26
+ ,'noUi-target' // 6
27
+ ,'-lower' // 7
28
+ ,'-upper' // 8
29
+ ,'noUi-connect' // 9
30
+ ,'noUi-vertical' // 10
31
+ ,'noUi-horizontal' // 11
32
+ ,'handles' // 12
33
+ ,'noUi-background' // 13
34
+ ,'noUi-z-index' // 14
35
+ ]
36
+ ,stdCls = {
37
+ base: [clsList[0], clsList[13]]
38
+ ,origin: [clsList[1]]
39
+ ,handle: [clsList[2]]
33
40
  }
41
+ ,percentage = {
42
+ to : function (range, value) {
43
+ value = range[0] < 0 ? value + Math.abs(range[0]) : value - range[0];
44
+ return (value * 100) / this._length(range);
45
+ },
46
+ from : function (range, value) {
47
+ return (value * 100) / this._length(range);
48
+ },
49
+ is : function (range, value) {
50
+ return ((value * this._length(range)) / 100) + range[0];
51
+ },
52
+ _length : function (range) {
53
+ return (range[0] > range[1] ? range[0] - range[1] : range[1] - range[0]);
54
+ }
55
+ };
56
+
57
+ if ( window.navigator.msPointerEnabled ) {
58
+ actions = {
59
+ start: 'MSPointerDown' + namespace
60
+ ,move: 'MSPointerMove' + namespace
61
+ ,end: 'MSPointerUp' + namespace
62
+ };
63
+ }
64
+
65
+ function __sp ( e ) {
66
+ e.stopPropagation();
34
67
  }
35
68
 
36
- // bounce handles of eachother, the edges of the slider
37
- function correct(proposal, slider, handle) {
38
-
39
- var
40
- setup = slider.data('setup'),
41
- handles = setup.handles,
42
- settings = setup.settings,
43
- pos = setup.pos;
44
-
45
- proposal = proposal < 0 ? 0 : proposal > 100 ? 100 : proposal;
46
-
47
- if (settings.handles == 2) {
48
- if (handle.is(':first-child')) {
49
- var other = parseFloat(handles[1][0].style[pos]) - settings.margin;
50
- proposal = proposal > other ? other : proposal;
51
- } else {
52
- var other = parseFloat(handles[0][0].style[pos]) + settings.margin;
53
- proposal = proposal < other ? other : proposal;
69
+ function call ( f, scope, args ) {
70
+ $.each(f,function(i,q){
71
+ if (typeof q === "function") {
72
+ q.call(scope, args);
54
73
  }
74
+ });
75
+ }
76
+
77
+ function blocked ( e ) {
78
+ return ( e.data.base.data('target').is('[class*="noUi-state-"], [disabled]') );
79
+ }
80
+
81
+ function fixEvent ( e, preventDefault ) {
82
+
83
+ // Required (in at the very least Chrome) to prevent
84
+ // scrolling and panning while attempting to slide.
85
+ // The tap event also depends on this.
86
+ if( preventDefault ) {
87
+ e.preventDefault();
55
88
  }
56
-
57
- if (settings.step) {
58
- var per = percentage.from(settings.range, settings.step);
59
- proposal = Math.round(proposal / per) * per;
89
+
90
+ var jQueryEvent = e
91
+ ,touch = e.type.indexOf('touch') === 0
92
+ ,mouse = e.type.indexOf('mouse') === 0
93
+ ,pointer = e.type.indexOf('MSPointer') === 0
94
+ ,x,y;
95
+
96
+ e = e.originalEvent;
97
+
98
+ if (touch) {
99
+ x = e.changedTouches[0].pageX;
100
+ y = e.changedTouches[0].pageY;
60
101
  }
61
-
62
- return proposal;
63
-
64
- }
65
-
66
- // get standarised clientX and clientY
67
- function client(f) {
68
- try {
69
- return [(f.clientX || f.originalEvent.clientX || f.originalEvent.touches[0].clientX), (f.clientY || f.originalEvent.clientY || f.originalEvent.touches[0].clientY)];
70
- } catch (e) {
71
- return ['x', 'y'];
102
+ if (mouse) {
103
+
104
+ // Polyfill the pageXOffset and pageYOffset
105
+ // variables for IE7 and IE8;
106
+ if(window.pageXOffset === UNDEF){
107
+ window.pageXOffset = document.documentElement.scrollLeft;
108
+ window.pageYOffset = document.documentElement.scrollTop;
109
+ }
110
+
111
+ x = e.clientX + window.pageXOffset;
112
+ y = e.clientY + window.pageYOffset;
72
113
  }
114
+ if (pointer) {
115
+ x = e.pageX;
116
+ y = e.pageY;
117
+ }
118
+
119
+ return { pass: jQueryEvent.data, e:e, x:x, y:y, t: [touch, mouse, pointer] };
120
+
73
121
  }
74
122
 
75
- // get native inline style value in %
76
- function place(handle, pos) {
77
- return parseFloat(handle[0].style[pos]);
123
+ function getPercentage( a ){
124
+ return parseFloat(this.style[a]);
78
125
  }
126
+
127
+ function test ( o, set ){
79
128
 
80
- // simplified defaults
81
- var defaults = {
82
- handles : 2,
83
- serialization : {
84
- to : ['', ''],
85
- resolution : 0.01
129
+ // checks is number is numerical
130
+ function num(e){
131
+ return !isNaN(e) && isFinite(e);
132
+ }
133
+ function ser(r){
134
+ return ( r instanceof $ || typeof r === 'string' || r === false );
86
135
  }
87
- };
88
-
89
- // contains all methods
90
- methods = {
91
- create : function () {
92
-
93
- return this.each(function () {
94
136
 
95
- // set handle to position
96
- function setHandle(handle, to, slider) {
97
- handle.css(pos, to + '%').data('input').val(percentage.is(settings.range, to).toFixed(res));
137
+
138
+ /**
139
+ These tests are structured with an item for every option available.
140
+ Every item contains an 'r' flag, which marks a required option, and
141
+ a 't' function, which in turn takes some arguments:
142
+ - a reference to options object
143
+ - the value for the option
144
+ - the option name (optional);
145
+ The testing function returns false when an error is detected,
146
+ or true when everything is OK. Every test also has an 'init'
147
+ method which appends the parent object to all children.
148
+ **/
149
+ var TESTS = {
150
+ "handles": {
151
+ r: true // has default
152
+ ,t: function(o,q){
153
+ q = parseInt(q, 10);
154
+ return ( q === 1 || q === 2 );
98
155
  }
99
-
100
- var
101
- settings = $.extend(defaults, options),
102
- // handles
103
- handlehtml = '<a><div></div></a>',
104
- // save this to variable, // allows identification
105
- slider = $(this).data('_isnS_', true),
106
- // array of handles
107
- handles = [],
108
- // the way the handles are positioned for this slider, top/left
109
- pos,
110
- // for quick orientation testing and array matching
111
- orientation,
112
- // append classes
113
- classes = "",
114
- // tests numerical
115
- num = function (e) {
116
- return !isNaN(parseFloat(e)) && isFinite(e);
117
- },
118
- // counts decimals in serialization, sets default
119
- split = (settings.serialization.resolution = settings.serialization.resolution || 0.01).toString().split('.'),
120
- res = split[0] == 1 ? 0 : split[1].length;
121
-
122
- settings.start = num(settings.start) ? [settings.start, 0] : settings.start;
123
-
124
- // logs bad input values, if possible
125
- $.each(settings, function (a, b) {
126
-
127
- if (num(b)) {
128
- settings[a] = parseFloat(b);
129
- } else if (typeof b == "object" && num(b[0])) {
130
- b[0] = parseFloat(b[0]);
131
- if (num(b[1])) {
132
- b[1] = parseFloat(b[1]);
156
+ }
157
+ ,"range": {
158
+ r: true
159
+ ,t: function(o,q,w){
160
+ if(q.length!==2){
161
+ return false;
162
+ }
163
+ q = [parseFloat(q[0]),parseFloat(q[1])];
164
+ if(!num(q[0])||!num(q[1])){
165
+ return false;
166
+ }
167
+ o[w]=q;
168
+ return true;
169
+ }
170
+ }
171
+ ,"start": {
172
+ r: true
173
+ ,t: function(o,q,w){
174
+ if(o.handles === 1){
175
+ if($.isArray(q)){
176
+ q=q[0];
133
177
  }
178
+ q = parseFloat(q);
179
+ o.start = [q];
180
+ return num(q);
134
181
  }
182
+ return this.parent.range.t(o,q,w);
183
+ }
184
+ }
185
+ ,"connect": {
186
+ t: function(o,q){
187
+ return ( q === true
188
+ || q === false
189
+ || ( q === 'lower' && o.handles === 1)
190
+ || ( q === 'upper' && o.handles === 1));
191
+ }
192
+ }
193
+ ,"orientation": {
194
+ t: function(o,q){
195
+ return ( q === "horizontal" || q === "vertical" );
196
+ }
197
+ }
198
+ ,"margin": {
199
+ r: true // has default
200
+ ,t: function(o,q,w){
201
+ q = parseFloat(q);
202
+ o[w]=q;
203
+ return num(q);
204
+ }
205
+ }
206
+ ,"serialization": {
207
+ r: true // has default
208
+ ,t: function(o,q){
135
209
 
136
- var e = false;
137
- b = typeof b == "undefined" ? "x" : b;
138
-
139
- switch (a) {
140
- case 'range':
141
- case 'start':
142
- e = b.length != 2 || !num(b[0]) || !num(b[1]);
143
- break;
144
- case 'handles':
145
- e = (b < 1 || b > 2 || !num(b));
146
- break;
147
- case 'connect':
148
- e = b != "lower" && b != "upper" && typeof b != "boolean";
149
- break;
150
- case 'orientation':
151
- e = (b != "vertical" && b != "horizontal");
152
- break;
153
- case 'margin':
154
- case 'step':
155
- e = typeof b != "undefined" && !num(b);
156
- break;
157
- case 'serialization':
158
- e = typeof b != "object" || !num(b.resolution) || (typeof b.to == 'object' && b.to.length < settings.handles);
159
- break;
160
- case 'slide':
161
- e = typeof b != "function";
162
- break;
210
+ if(!q.resolution){
211
+ o.serialization.resolution = 0.01;
212
+ } else {
213
+ switch(q.resolution){
214
+ case 1:
215
+ case 0.1:
216
+ case 0.01:
217
+ case 0.001:
218
+ case 0.0001:
219
+ case 0.00001:
220
+ break;
221
+ default:
222
+ return false;
223
+ }
163
224
  }
164
225
 
165
- if (e && console) {
166
- console.error('Bad input for ' + a + ' on slider:', slider);
167
- }
226
+ if(q.to){
227
+
228
+ if(o.handles === 1){
229
+ if(!$.isArray(q.to)){
230
+ q.to = [q.to];
231
+ }
232
+ o.serialization.to = q.to;
233
+ return ser(q.to[0]);
234
+ }
235
+ return (q.to.length === 2 && ser(q.to[0]) && ser(q.to[1]));
168
236
 
237
+ }
238
+
239
+ return false;
240
+
241
+ }
242
+ }
243
+ ,"slide": {
244
+ t: function(o,q){
245
+ return typeof q === "function";
246
+ }
247
+ }
248
+ ,"step": {
249
+ t: function(o,q,w){
250
+ return this.parent.margin.t(o,q,w);
251
+ }
252
+ }
253
+ ,"init": function(){
254
+ var obj = this;
255
+ $.each(obj,function(i,c){
256
+ c.parent = obj;
169
257
  });
258
+ delete this.init;
259
+ return this;
260
+ }
261
+ },
262
+
263
+ // Prepare a set of tests, by adding some internal reference
264
+ // values not available in native Javascript object implementation.
265
+ a = TESTS.init();
266
+
267
+ // Loop all provided tests;
268
+ // v is the option set, i is the index for the current test.
269
+ $.each(a, function( i, v ){
270
+
271
+ // If the value is required but not set,
272
+ // or if the test fails, throw an error.
273
+ if((v.r && (!o[i] && o[i] !== 0)) || ((o[i] || o[i] === 0) && !v.t(o,o[i],i))){
274
+
275
+ // For debugging purposes it might be very useful
276
+ // to know what option caused the trouble.
277
+ if(console&&console.log){
278
+ console.log(
279
+ "Slider:\t\t\t", set,
280
+ "\nOption:\t\t\t", i,
281
+ "\nValue:\t\t\t", o[i]
282
+ );
283
+ }
284
+ $.error("Error on noUiSlider initialisation.");
285
+ return false;
286
+ }
170
287
 
171
- settings.margin = settings.margin ? percentage.from(settings.range, settings.margin) : 0;
288
+ });
172
289
 
173
- // tests serialization to be strings or jQuery objects
174
- if (settings.serialization.to instanceof jQuery || typeof settings.serialization.to == 'string' || settings.serialization.to === false) {
175
- settings.serialization.to = [settings.serialization.to];
290
+ }
291
+
292
+ function closest( value, to ){
293
+ return Math.round(value / to) * to;
294
+ }
295
+
296
+ function setHandle ( handle, to, forgive ) {
297
+
298
+ var nui = handle.data('nui').options
299
+ // Get the array of handles from the base.
300
+ // Will be undefined at initialisation.
301
+ ,handles = handle.data('nui').base.data(clsList[12])
302
+ // Get some settings from the handle
303
+ ,style = handle.data('nui').style
304
+ ,dec = handle.data('nui').decimals
305
+ ,hLimit;
306
+
307
+ // Ignore the call if the handle won't move anyway.
308
+ if(to === handle[0].getPercentage(style)) {
309
+ return false;
310
+ }
311
+
312
+ // Limit `to` to 0 - 100
313
+ to = to < 0 ? 0 : to > 100 ? 100 : to;
314
+
315
+ // Handle the step option, or ignore it.
316
+ if( nui.step && !forgive ){
317
+ to = closest( to, percentage.from(nui.range, nui.step));
318
+ }
319
+
320
+ // Stop handling this call if the handle won't step to a new value.
321
+ if(to === handle[0].getPercentage(style)) {
322
+ return false;
323
+ }
324
+
325
+ // We're done if this is the only handle,
326
+ // if the handle bounce is trusted to the user
327
+ // or on initialisation when handles isn't defined yet.
328
+ if( handle.siblings('.' + clsList[1]).length && !forgive && handles ){
329
+
330
+ // Otherwise, the handle should bounce,
331
+ // and stop at the other handle.
332
+ if ( handle.data('nui').number ) {
333
+ hLimit = handles[0][0].getPercentage(style) + nui.margin;
334
+ to = to < hLimit ? hLimit : to;
335
+ } else {
336
+ hLimit = handles[1][0].getPercentage(style) - nui.margin;
337
+ to = to > hLimit ? hLimit : to;
338
+ }
339
+
340
+ // Stop handling this call if the handle can't move past another.
341
+ if(to === handle[0].getPercentage(style)) {
342
+ return false;
343
+ }
344
+
345
+ }
346
+
347
+ // Fix for the z-index issue where the lower handle gets stuck
348
+ // below the upper one. Since this function is called for every
349
+ // movement, toggleClass cannot be used.
350
+ if(handle.data('nui').number === 0 && to > 95){
351
+ handle.addClass(clsList[14]);
352
+ } else {
353
+ handle.removeClass(clsList[14]);
354
+ }
355
+
356
+ // Set handle to new location
357
+ handle.css( style , to + '%');
358
+
359
+ // Write the value to the serialization object.
360
+ handle.data('store').val(percentage.is(nui.range, to).toFixed(dec));
361
+
362
+ return true;
363
+
364
+ }
365
+
366
+ function store ( handle, S ) {
367
+
368
+ var i = handle.data('nui').number;
369
+
370
+ if( S.to[i] instanceof $ ) {
371
+
372
+ // Attach a change event to the supplied jQuery object,
373
+ // which will just trigger the val function on the parent.
374
+ // In some cases, the change event will not fire on select elements,
375
+ // so listen to 'blur' too.
376
+ return S.to[i].on('change'+namespace+' blur'+namespace, function(){
377
+ var arr = [null, null];
378
+ arr[i] = $(this).val();
379
+ handle.data('nui').target.val(arr, true);
380
+ });
381
+
382
+ }
383
+
384
+ if ( typeof S.to[i] === "string" ) {
385
+
386
+ // Append a new object to the noUiSlider base,
387
+ // prevent change events flowing upward.
388
+ return $('<input type="hidden" class="'+clsList[3]+'" name="' + S.to[i] + '">')
389
+ .appendTo(handle).change(__sp);
390
+
391
+ }
392
+
393
+ if ( S.to[i] === false ) {
394
+
395
+ // Create an object capable of handling all jQuery calls.
396
+ return {
397
+ // The value will be stored a data on the handle.
398
+ val : function(a) {
399
+ // Value function provides a getter and a setter.
400
+ // Can't just test for !a, as a might be 0.
401
+ if ( a === UNDEF ) {
402
+ // Either set...
403
+ return this._handle.data('nui-val');
404
+ }
405
+ // ... or return;
406
+ this._handle.data('nui-val', a);
176
407
  }
177
-
178
- if (settings.orientation == "vertical") {
179
- classes += "vertical";
180
- pos = 'top';
181
- orientation = 1;
182
- } else {
183
- classes += "horizontal";
184
- pos = 'left';
185
- orientation = 0;
408
+ // The object could be mistaken for a jQuery object,
409
+ // make sure that doesn't trigger any errors.
410
+ ,hasClass: function(){
411
+ return false;
186
412
  }
413
+ // The val function needs access to the handle.
414
+ ,_handle: handle
415
+ };
416
+ }
417
+
418
+ }
187
419
 
188
- classes += settings.connect ? settings.connect == "lower" ? " connect lower" : " connect" : "";
420
+ function move( event ) {
189
421
 
190
- slider.addClass(classes);
422
+ // This function is called often, keep it light.
423
+
424
+ event = fixEvent( event, true );
191
425
 
192
- for (var i = 0; i < settings.handles; i++) {
426
+ if(!event) {
427
+ return;
428
+ }
193
429
 
194
- handles[i] = slider.append(handlehtml).children(':last');
195
- var setTo = percentage.to(settings.range, settings.start[i]);
196
- handles[i].css(pos, setTo + '%');
197
- if (setTo == 100 && handles[i].is(':first-child')) {
198
- handles[i].css('z-index', 2);
199
- }
430
+ var base = event.pass.base
431
+ ,style = base.data('style')
432
+ // Subtract the initial movement from the current event,
433
+ // while taking vertical sliders into account.
434
+ ,proposal = event.x - event.pass.startEvent.x
435
+ ,baseSize = style === 'left' ? base.width() : base.height();
436
+
437
+ if(style === 'top') {
438
+ proposal = event.y - event.pass.startEvent.y;
439
+ }
440
+
441
+ proposal = event.pass.position + ( ( proposal * 100 ) / baseSize );
442
+
443
+ setHandle( event.pass.handle, proposal );
200
444
 
201
- var bind = '.noUiSlider',
202
- onEvent = (EVENT === 1 ? 'mousedown' : EVENT === 2 ? 'MSPointerDown' : 'touchstart') + bind + 'X',
203
- moveEvent = (EVENT === 1 ? 'mousemove' : EVENT === 2 ? 'MSPointerMove' : 'touchmove') + bind,
204
- offEvent = (EVENT === 1 ? 'mouseup' : EVENT === 2 ? 'MSPointerUp' : 'touchend') + bind
445
+ // Trigger the 'slide' event, pass the target so that it is 'this'.
446
+ call(
447
+ [ event.pass.base.data('options').slide ]
448
+ ,event.pass.base.data('target')
449
+ );
450
+
451
+ }
205
452
 
206
- handles[i].find('div').on(onEvent, function (e) {
453
+ function end ( event ) {
207
454
 
208
- $('body').bind('selectstart' + bind, function () {
209
- return false;
210
- });
455
+ if ( blocked( event ) ) {
456
+ return;
457
+ }
458
+
459
+ // Handle is no longer active;
460
+ event.data.handle.children().removeClass(clsList[4]);
461
+
462
+ // Unbind move and end events, to prevent
463
+ // them stacking up over and over;
464
+ all.off(actions.move);
465
+ all.off(actions.end);
466
+ $('body').off(namespace);
467
+
468
+ event.data.base.data('target').change();
469
+
470
+ }
211
471
 
212
- if (!slider.hasClass('disabled')) {
472
+ function start ( event ) {
213
473
 
214
- $('body').addClass('TOUCH');
474
+ // When the slider is in a transitional state, stop.
475
+ // Also prevents interaction with disabled sliders.
476
+ if ( blocked( event ) ) {
477
+ return;
478
+ }
479
+
480
+ event = fixEvent( event );
215
481
 
216
- var handle = $(this).addClass('active').parent(),
217
- unbind = handle.add($(document)).add('body'),
218
- originalPosition = parseFloat(handle[0].style[pos]),
219
- originalClick = client(e),
220
- previousClick = originalClick,
221
- previousProposal = false;
482
+ if(!event) {
483
+ return;
484
+ }
222
485
 
223
- $(document).on(moveEvent, function (f) {
486
+ var handle = event.pass.handle
487
+ ,position = handle[0].getPercentage( handle.data('nui').style );
488
+
489
+ handle.children().addClass('noUi-active');
490
+
491
+ // Attach the move event handler, while
492
+ // passing all relevant information along.
493
+ all.on(actions.move, {
494
+ startEvent: event
495
+ ,position: position
496
+ ,base: event.pass.base
497
+ ,handle: handle
498
+ }, move);
499
+
500
+ all.on(actions.end, { base: event.pass.base, handle: handle }, end);
501
+
502
+ $('body').on('selectstart' + namespace, function(){ return false; });
503
+
504
+ }
505
+
506
+ function selfEnd( event ) {
507
+ // Trigger the end handler. Supply correct data using a
508
+ // fake object that contains all required information;
509
+ end({ data: { base: event.data.base, handle: event.data.handle } });
510
+ // Stop propagation so that the tap handler doesn't interfere;
511
+ event.stopPropagation();
512
+ }
513
+
514
+ function tap ( event ) {
224
515
 
225
- f.preventDefault();
516
+ if ( blocked( event ) || event.data.base.find('.' + clsList[4]).length ) {
517
+ return;
518
+ }
519
+
520
+ event = fixEvent( event );
226
521
 
227
- var currentClick = client(f);
522
+ // The event handler might have rejected this event.
523
+ if(!event) {
524
+ return;
525
+ }
526
+
527
+ // Getting variables from the event is not required, but
528
+ // shortens other expressions and is far more convenient;
529
+ var i, handle, base = event.pass.base
530
+ ,handles = event.pass.handles
531
+ ,style = base.data('style')
532
+ ,eventXY = event[style === 'left' ? 'x' : 'y']
533
+ ,baseSize = style === 'left' ? base.width() : base.height()
534
+
535
+ // Create a standard set off offsets compensated with the
536
+ // scroll distance. When required, correct for scrolling.
537
+ // This is a bug, as far as I can see, in IE(10?).
538
+ ,correction = {
539
+ x: ( event.t[2] ? window.pageXOffset : 0 )
540
+ }
541
+ ,offset = {
542
+ handles: []
543
+ ,base: {
544
+ left: base.offset().left - correction.x
545
+ ,top: base.offset().top
546
+ }
547
+ };
548
+
549
+ // Loop handles and add data to the offset list.
550
+ for (i = 0; i < handles.length; i++ ) {
551
+ offset.handles.push({
552
+ left: handles[i].offset().left - correction.x
553
+ ,top: handles[i].offset().top
554
+ });
555
+ }
556
+
557
+ // Calculate the central point between the handles;
558
+ var handleCenter = handles.length === 1 ? 0 :
559
+ (( offset.handles[0][style] + offset.handles[1][style] ) / 2 );
560
+
561
+ // If there is just one handle,
562
+ // or the lower handles in closest to the event,
563
+ // select the first handle. Otherwise, pick the second.
564
+ if ( handles.length === 1 || eventXY < handleCenter ){
565
+ handle = handles[0];
566
+ } else {
567
+ handle = handles[1];
568
+ }
228
569
 
229
- if (currentClick[0] == "x") {
230
- return;
231
- }
570
+ // Flag the slider as it is now in a transitional state.
571
+ // Transition takes 300 ms, so re-enable the slider afterwards.
572
+ base.addClass(clsList[5]);
573
+ setTimeout(function(){
574
+ base.removeClass(clsList[5]);
575
+ }, 300);
576
+
577
+ // Calculate the new position for the handle and
578
+ // trigger the movement.
579
+ setHandle(
580
+ handle
581
+ ,(((eventXY - offset.base[style]) * 100) / baseSize)
582
+ );
583
+
584
+ // Trigger the 'slide' event, pass the target so that it is 'this'.
585
+ call(
586
+ [ handle.data('nui').options.slide ]
587
+ ,base.data('target')
588
+ );
589
+
590
+ base.data('target').change();
232
591
 
233
- currentClick[0] -= originalClick[0];
234
- currentClick[1] -= originalClick[1];
592
+ }
593
+
594
+ function create ( ) {
595
+
596
+ return this.each(function( index, target ){
597
+
598
+ // Target is the wrapper that will receive all external
599
+ // scripting interaction. It has no styling and serves no
600
+ // other function.
601
+ target = $(target);
602
+ target.addClass(clsList[6]);
603
+
604
+ // Base is the internal main 'bar'.
605
+ var i, style, decimals, handle
606
+ ,base = $('<div/>').appendTo(target)
607
+ ,handles = []
608
+ ,cls = {
609
+ base: stdCls.base
610
+ ,origin: [
611
+ stdCls.origin.concat([clsList[1] + clsList[7]])
612
+ ,stdCls.origin.concat([clsList[1] + clsList[8]])
613
+ ]
614
+ ,handle: [
615
+ stdCls.handle.concat([clsList[2] + clsList[7]])
616
+ ,stdCls.handle.concat([clsList[2] + clsList[8]])
617
+ ]
618
+ };
619
+
620
+ // Set defaults where applicable;
621
+ options = $.extend({
622
+ handles: 2
623
+ ,margin: 0
624
+ ,orientation: "horizontal"
625
+ }, options) || {};
626
+
627
+ // Set a default for serialization;
628
+ if(!options.serialization){
629
+ options.serialization = {
630
+ to : [false, false]
631
+ ,resolution : 0.01
632
+ };
633
+ }
634
+
635
+ // Run all options through a testing mechanism to ensure correct
636
+ // input. The test function will throw errors, so there is
637
+ // no need to capture the result of this call. It should be noted
638
+ // that options might get modified to be handled properly. E.g.
639
+ // wrapping integers in arrays.
640
+ test(options, target);
641
+
642
+ // I can't type serialization any more, and it doesn't compress
643
+ // very well, so shorten it.
644
+ options.S = options.serialization;
645
+
646
+
647
+ // INCOMPLETE
648
+ if( options.connect ) {
649
+ cls.origin[0].push(clsList[9]);
650
+ if( options.connect === "lower" ){
651
+ // Add some styling classes to the base;
652
+ cls.base.push(clsList[9], clsList[9] + clsList[7]);
653
+ // When using the option 'Lower', there is only one
654
+ // handle, and thus only one origin.
655
+ cls.origin[0].push(clsList[13]);
656
+ } else {
657
+ cls.base.push(clsList[9] + clsList[8]);
658
+ }
659
+ }
235
660
 
236
- var movement = [
237
- previousClick[0] != currentClick[0], previousClick[1] != currentClick[1]
238
- ],
239
- proposal = originalPosition + ((currentClick[orientation] * 100) / (orientation ? slider.height() : slider.width()));
240
- proposal = correct(proposal, slider, handle);
661
+ // Parse the syntactic sugar that is the serialization
662
+ // resolution option to a usable integer.
663
+ style = options.orientation === 'vertical' ? 'top' : 'left';
664
+
665
+ decimals = options.S.resolution.toString().split('.');
666
+ // Test ==, not ===
667
+ decimals = decimals[0] == 1 ? 0 : decimals[1].length;
668
+
669
+ // Add classes for horizontal and vertical sliders.
670
+ // The horizontal class is provided for completeness,
671
+ // as it isn't used in the default theme.
672
+ if( options.orientation === "vertical" ){
673
+ cls.base.push(clsList[10]);
674
+ } else {
675
+ cls.base.push(clsList[11]);
676
+ }
677
+
678
+ // Merge base classes with default;
679
+ base.addClass(cls.base.join(" ")).data('target', target);
680
+
681
+ for (i = 0; i < options.handles; i++ ) {
682
+
683
+ handle = $('<div><div/></i>').appendTo(base);
684
+
685
+ // Add all default and option-specific classes to the
686
+ // origins and handles.
687
+ handle.addClass(cls.origin[i].join(" "));
688
+ handle.children().addClass(cls.handle[i].join(" "));
689
+
690
+ // These events are only bound to the visual handle element,
691
+ // not the `real` origin element.
692
+ handle.children()
693
+ .on(actions.start, { base: base, handle: handle }, start)
694
+ .on(actions.end, { base: base, handle: handle }, selfEnd);
695
+
696
+ // Make sure every handle has access to all primary
697
+ // variables. Can't uses jQuery's .data( obj ) structure
698
+ // here, as `store` needs some values from the `nui` object.
699
+ handle.data('nui', {
700
+ target: target
701
+ ,decimals: decimals
702
+ ,options: options
703
+ ,base: base
704
+ ,style: style
705
+ ,number: i
706
+ }).data('store', store (
707
+ handle
708
+ ,options.S
709
+ ));
710
+
711
+ // Attach a function to the native DOM element,
712
+ // since jQuery wont let me get the current value in percentages.
713
+ handle[0].getPercentage = getPercentage;
714
+
715
+ // Make handles loop-able
716
+ handles.push(handle);
717
+
718
+ // Set the handle to its initial position;
719
+ setHandle(handle, percentage.to(options.range, options.start[i]));
241
720
 
242
- if (movement[orientation] && proposal != previousProposal) {
243
- handle.css(pos, proposal + '%').data('input').val(percentage.is(settings.range, proposal).toFixed(res));
244
- call(settings.slide, slider.data('_n', true));
245
- previousProposal = proposal;
246
- handle.css('z-index', handles.length == 2 && proposal == 100 && handle.is(':first-child') ? 2 : 1);
247
- }
721
+ }
722
+
723
+ // The base could use the handles too;
724
+ base.data({
725
+ options: options
726
+ ,handles: handles
727
+ ,style: style
728
+ });
729
+
730
+ target.data({
731
+ base: base
732
+ ,handles: handles
733
+ });
734
+
735
+ // The tap event.
736
+ base.on(actions.end, { base: base, handles: handles }, tap);
248
737
 
249
- previousClick = currentClick;
738
+ });
250
739
 
251
- }).on(offEvent, function () {
740
+ }
252
741
 
253
- unbind.off(bind);
254
- $('body').removeClass('TOUCH');
255
- if (slider.find('.active').removeClass('active').end().data('_n')) {
256
- slider.data('_n', false).change();
257
- }
742
+ function val ( args, ignore ) {
258
743
 
259
- });
744
+ // Setter
745
+ if( args !== UNDEF ){
260
746
 
261
- }
262
- }).on('click', function (e) {
263
- e.stopPropagation();
264
- });
747
+ // If the val is to be set to a number, which is valid
748
+ // when using a one-handle slider, wrap it in an array.
749
+ if(!$.isArray(args)){
750
+ args = [args];
751
+ }
752
+
753
+ // Setting is handled properly for each slider in the data set.
754
+ return this.each(function(){
265
755
 
266
- }
756
+ $.each($(this).data(clsList[12]), function(i, handle){
267
757
 
268
- if (EVENT == 1) {
269
- slider.on('click', function (f) {
270
- if (!slider.hasClass('disabled')) {
271
- var currentClick = client(f),
272
- proposal = ((currentClick[orientation] - slider.offset()[pos]) * 100) / (orientation ? slider.height() : slider.width()),
273
- handle = handles.length > 1 ? (currentClick[orientation] < (handles[0].offset()[pos] + handles[1].offset()[pos]) / 2 ? handles[0] : handles[1]) : handles[0];
274
- setHandle(handle, correct(proposal, slider, handle), slider);
275
- call(settings.slide, slider);
276
- slider.change();
758
+ // The set request might want to ignore this handle.
759
+ if( args[i] === null ) {
760
+ return;
761
+ }
762
+
763
+ // Calculate a new position for the handle.
764
+ var value, current
765
+ ,range = handle.data('nui').options.range
766
+ ,to = percentage.to(
767
+ range
768
+ ,parseFloat(args[i])
769
+ ),
770
+
771
+ // Set handle to new location, and make sure developer
772
+ // input is always accepted. The ignore flag indicates
773
+ // input from user facing elements.
774
+ result = setHandle(handle, to, (ignore === true ? false : true));
775
+
776
+ // If the value of the input doesn't match the slider,
777
+ // reset it.
778
+ if(!result){
779
+
780
+ value = handle.data('store').val();
781
+ current = percentage.is(range,
782
+ handle[0].getPercentage(handle.data('nui').style)
783
+ ).toFixed(handle.data('nui').decimals);
784
+
785
+ if(value !== current){
786
+ handle.data('store').val(current);
277
787
  }
278
- });
279
- }
280
-
281
- for (var i = 0; i < handles.length; i++) {
282
- var val = percentage.is(settings.range, place(handles[i], pos)).toFixed(res);
283
- if (typeof settings.serialization.to[i] == 'string') {
284
- handles[i].data('input',
285
- slider.append('<input type="hidden" name="' + settings.serialization.to[i] + '">').find('input:last')
286
- .val(val)
287
- .change(function (a) {
288
- a.stopPropagation();
289
- }));
290
- } else if (settings.serialization.to[i] == false) {
291
- handles[i].data('input', {
292
- val : function (a) {
293
- if (typeof a != 'undefined') {
294
- this.handle.data('noUiVal', a);
295
- } else {
296
- return this.handle.data('noUiVal');
297
- }
298
- },
299
- handle : handles[i]
300
- });
301
- } else {
302
- handles[i].data('input', settings.serialization.to[i].data('handleNR', i).val(val).change(function () {
303
- var arr = [null, null];
304
- arr[$(this).data('handleNR')] = $(this).val();
305
- slider.val(arr);
306
- }));
307
788
  }
308
- }
309
-
310
- $(this).data('setup', {
311
- settings : settings,
312
- handles : handles,
313
- pos : pos,
314
- res : res
789
+
315
790
  });
316
791
 
317
792
  });
318
- },
319
- val : function () {
320
-
321
- if (typeof arguments[0] !== 'undefined') {
322
-
323
- var val = typeof arguments[0] == 'number' ? [arguments[0]] : arguments[0];
324
-
325
- return this.each(function () {
326
793
 
327
- var setup = $(this).data('setup');
794
+ }
328
795
 
329
- for (var i = 0; i < setup.handles.length; i++) {
330
- if (val[i] != null) {
331
- var proposal = correct(percentage.to(setup.settings.range, val[i]), $(this), setup.handles[i]);
332
- setup.handles[i].css(setup.pos, proposal + '%').data('input').val(percentage.is(setup.settings.range, proposal).toFixed(setup.res));
333
- }
334
- }
335
- });
796
+ // Or, if the function was called without arguments,
797
+ // act as a 'getter';
798
+
799
+ var re = [];
336
800
 
337
- } else {
801
+ // Loop the handles, and get the value from the input
802
+ // for every handle on its' own.
803
+ $.each($(this).data(clsList[12]), function(i, handle){
804
+ re.push( handle.data('store').val() );
805
+ });
338
806
 
339
- var handles = $(this).data('setup').handles,
340
- re = [];
341
- for (var i = 0; i < handles.length; i++) {
342
- re.push(parseFloat(handles[i].data('input').val()));
343
- }
344
- return re.length == 1 ? re[0] : re;
807
+ // If the slider has just one handle, return a single value.
808
+ // Otherwise, return an array.
809
+ return ( re.length === 1 ? re[0] : re) ;
345
810
 
346
- }
347
- },
348
- disabled : function () {
349
- return flag ? $(this).addClass('disabled') : $(this).removeClass('disabled');
350
- }
351
811
  }
352
812
 
353
- // remap the native/current val function to noUiSlider
354
- var $_val = jQuery.fn.val;
355
-
356
- jQuery.fn.val = function () {
357
- return this.data('_isnS_') ? methods.val.apply(this, arguments) : $_val.apply(this, arguments);
358
- }
813
+ // Overwrite the native jQuery val() function
814
+ // with a simple handler. noUiSlider will use the internal
815
+ // value method, anything else will use the standard method.
816
+ $.fn.val = function(){
817
+ return this.hasClass(clsList[6])
818
+ ? val.apply(this, arguments)
819
+ : $VAL.apply(this, arguments);
820
+ };
359
821
 
360
- return options == "disabled" ? methods.disabled.apply(this) : methods.create.apply(this);
822
+ return create.apply(this, arguments);
361
823
 
362
- }
824
+ };
363
825
 
364
- })(jQuery);
826
+ }(jQuery));