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,234 @@
1
+ /*jslint browser: true */
2
+ /*jslint white: true */
3
+
4
+ (function( $ ){
5
+
6
+ 'use strict';
7
+
8
+ // Removes duplicates from an array.
9
+ function unique(array) {
10
+ return $.grep(array, function(el, index) {
11
+ return index === $.inArray(el, array);
12
+ });
13
+ }
14
+
15
+ // Pips
16
+
17
+ function getGroup ( $Spectrum, mode, values, stepped ) {
18
+
19
+ // Use the range.
20
+ if ( mode === 'range' || mode === 'steps' ) {
21
+ return $Spectrum.xVal;
22
+ }
23
+
24
+ if ( mode === 'count' ) {
25
+
26
+ // Divide 0 - 100 in 'count' parts.
27
+ var spread = ( 100 / (values-1) ), v, i = 0;
28
+ values = [];
29
+
30
+ // List these parts and have them handled as 'positions'.
31
+ while ((v=i++*spread) <= 100 ) {
32
+ values.push(v);
33
+ }
34
+
35
+ mode = 'positions';
36
+ }
37
+
38
+ if ( mode === 'positions' ) {
39
+
40
+ // Map all percentages to on-range values.
41
+ return $.map(values, function( value ){
42
+ return $Spectrum.fromStepping( stepped ? $Spectrum.getStep( value ) : value );
43
+ });
44
+ }
45
+
46
+ if ( mode === 'values' ) {
47
+
48
+ // If the value must be stepped, it needs to be converted to a percentage first.
49
+ if ( stepped ) {
50
+
51
+ return $.map(values, function( value ){
52
+
53
+ // Convert to percentage, apply step, return to value.
54
+ return $Spectrum.fromStepping( $Spectrum.getStep( $Spectrum.toStepping( value ) ) );
55
+ });
56
+
57
+ }
58
+
59
+ // Otherwise, we can simply use the values.
60
+ return values;
61
+ }
62
+ }
63
+
64
+ function generateSpread ( $Spectrum, density, mode, group ) {
65
+
66
+ var originalSpectrumDirection = $Spectrum.direction,
67
+ indexes = {},
68
+ firstInRange = $Spectrum.xVal[0],
69
+ lastInRange = $Spectrum.xVal[$Spectrum.xVal.length-1],
70
+ ignoreFirst = false,
71
+ ignoreLast = false,
72
+ prevPct = 0;
73
+
74
+ // This function loops the spectrum in an ltr linear fashion,
75
+ // while the toStepping method is direction aware. Trick it into
76
+ // believing it is ltr.
77
+ $Spectrum.direction = 0;
78
+
79
+ // Create a copy of the group, sort it and filter away all duplicates.
80
+ group = unique(group.slice().sort(function(a, b){ return a - b; }));
81
+
82
+ // Make sure the range starts with the first element.
83
+ if ( group[0] !== firstInRange ) {
84
+ group.unshift(firstInRange);
85
+ ignoreFirst = true;
86
+ }
87
+
88
+ // Likewise for the last one.
89
+ if ( group[group.length - 1] !== lastInRange ) {
90
+ group.push(lastInRange);
91
+ ignoreLast = true;
92
+ }
93
+
94
+ $.each(group, function ( index ) {
95
+
96
+ // Get the current step and the lower + upper positions.
97
+ var step, i, q,
98
+ low = group[index],
99
+ high = group[index+1],
100
+ newPct, pctDifference, pctPos, type,
101
+ steps, realSteps, stepsize;
102
+
103
+ // When using 'steps' mode, use the provided steps.
104
+ // Otherwise, we'll step on to the next subrange.
105
+ if ( mode === 'steps' ) {
106
+ step = $Spectrum.xNumSteps[ index ];
107
+ }
108
+
109
+ // Default to a 'full' step.
110
+ if ( !step ) {
111
+ step = high-low;
112
+ }
113
+
114
+ // Low can be 0, so test for false. If high is undefined,
115
+ // we are at the last subrange. Index 0 is already handled.
116
+ if ( low === false || high === undefined ) {
117
+ return;
118
+ }
119
+
120
+ // Find all steps in the subrange.
121
+ for ( i = low; i <= high; i += step ) {
122
+
123
+ // Get the percentage value for the current step,
124
+ // calculate the size for the subrange.
125
+ newPct = $Spectrum.toStepping( i );
126
+ pctDifference = newPct - prevPct;
127
+
128
+ steps = pctDifference / density;
129
+ realSteps = Math.round(steps);
130
+
131
+ // This ratio represents the ammount of percentage-space a point indicates.
132
+ // For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-devided.
133
+ // Round the percentage offset to an even number, then divide by two
134
+ // to spread the offset on both sides of the range.
135
+ stepsize = pctDifference/realSteps;
136
+
137
+ // Divide all points evenly, adding the correct number to this subrange.
138
+ // Run up to <= so that 100% gets a point, event if ignoreLast is set.
139
+ for ( q = 1; q <= realSteps; q += 1 ) {
140
+
141
+ // The ratio between the rounded value and the actual size might be ~1% off.
142
+ // Correct the percentage offset by the number of points
143
+ // per subrange. density = 1 will result in 100 points on the
144
+ // full range, 2 for 50, 4 for 25, etc.
145
+ pctPos = prevPct + ( q * stepsize );
146
+ indexes[pctPos.toFixed(5)] = ['x', 0];
147
+ }
148
+
149
+ // Determine the point type.
150
+ type = ($.inArray(i, group) > -1) ? 1 : ( mode === 'steps' ? 2 : 0 );
151
+
152
+ // Enforce the 'ignoreFirst' option by overwriting the type for 0.
153
+ if ( !index && ignoreFirst && !low ) {
154
+ type = 0;
155
+ }
156
+
157
+ if ( !(i === high && ignoreLast)) {
158
+ // Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value.
159
+ indexes[newPct.toFixed(5)] = [i, type];
160
+ }
161
+
162
+ // Update the percentage count.
163
+ prevPct = newPct;
164
+ }
165
+ });
166
+
167
+ // Reset the spectrum.
168
+ $Spectrum.direction = originalSpectrumDirection;
169
+
170
+ return indexes;
171
+ }
172
+
173
+ function addMarking ( CSSstyle, orientation, direction, spread, filterFunc ) {
174
+
175
+ var style = ['horizontal', 'vertical'][orientation],
176
+ element = $('<div/>');
177
+
178
+ element.addClass('noUi-pips noUi-pips-'+style);
179
+
180
+ function getSize( type, value ){
181
+ return [ '-normal', '-large', '-sub' ][(type&&filterFunc) ? filterFunc(value, type) : type];
182
+ }
183
+ function getTags( offset, source, values ) {
184
+ return 'class="' + source + ' ' +
185
+ source + '-' + style + ' ' +
186
+ source + getSize(values[1], values[0]) +
187
+ '" style="' + CSSstyle + ': ' + offset + '%"';
188
+ }
189
+ function addSpread ( offset, values ){
190
+
191
+ if ( direction ) {
192
+ offset = 100 - offset;
193
+ }
194
+
195
+ // Add a marker for every point
196
+ element.append('<div '+getTags(offset, 'noUi-marker', values)+'></div>');
197
+
198
+ // Values are only appended for points marked '1' or '2'.
199
+ if ( values[1] ) {
200
+ element.append('<div '+getTags(offset, 'noUi-value', values)+'>' + Math.round(values[0]) + '</div>');
201
+ }
202
+ }
203
+
204
+ // Append all points.
205
+ $.each(spread, addSpread);
206
+
207
+ return element;
208
+ }
209
+
210
+ $.fn.noUiSlider_pips = function ( grid ) {
211
+
212
+ var mode = grid.mode,
213
+ density = grid.density || 1,
214
+ filter = grid.filter || false,
215
+ values = grid.values || false,
216
+ stepped = grid.stepped || false;
217
+
218
+ return this.each(function(){
219
+
220
+ var info = this.getInfo(),
221
+ group = getGroup( info[0], mode, values, stepped ),
222
+ spread = generateSpread( info[0], density, mode, group );
223
+
224
+ return $(this).append(addMarking(
225
+ info[1],
226
+ info[2],
227
+ info[0].direction,
228
+ spread,
229
+ filter
230
+ ));
231
+ });
232
+ };
233
+
234
+ }( window.jQuery || window.Zepto ));
@@ -0,0 +1,335 @@
1
+ (function(){
2
+
3
+ 'use strict';
4
+
5
+ var
6
+ /** @const */ FormatOptions = [
7
+ 'decimals',
8
+ 'thousand',
9
+ 'mark',
10
+ 'prefix',
11
+ 'postfix',
12
+ 'encoder',
13
+ 'decoder',
14
+ 'negativeBefore',
15
+ 'negative',
16
+ 'edit',
17
+ 'undo'
18
+ ];
19
+
20
+ // General
21
+
22
+ // Reverse a string
23
+ function strReverse ( a ) {
24
+ return a.split('').reverse().join('');
25
+ }
26
+
27
+ // Check if a string starts with a specified prefix.
28
+ function strStartsWith ( input, match ) {
29
+ return input.substring(0, match.length) === match;
30
+ }
31
+
32
+ // Check is a string ends in a specified postfix.
33
+ function strEndsWith ( input, match ) {
34
+ return input.slice(-1 * match.length) === match;
35
+ }
36
+
37
+ // Throw an error if formatting options are incompatible.
38
+ function throwEqualError( F, a, b ) {
39
+ if ( (F[a] || F[b]) && (F[a] === F[b]) ) {
40
+ throw new Error(a);
41
+ }
42
+ }
43
+
44
+ // Check if a number is finite and not NaN
45
+ function isValidNumber ( input ) {
46
+ return typeof input === 'number' && isFinite( input );
47
+ }
48
+
49
+ // Provide rounding-accurate toFixed method.
50
+ function toFixed ( value, decimals ) {
51
+ var scale = Math.pow(10, decimals);
52
+ return ( Math.round(value * scale) / scale).toFixed( decimals );
53
+ }
54
+
55
+
56
+ // Formatting
57
+
58
+ // Accept a number as input, output formatted string.
59
+ function formatTo ( decimals, thousand, mark, prefix, postfix, encoder, decoder, negativeBefore, negative, edit, undo, input ) {
60
+
61
+ var originalInput = input, inputIsNegative, inputPieces, inputBase, inputDecimals = '', output = '';
62
+
63
+ // Apply user encoder to the input.
64
+ // Expected outcome: number.
65
+ if ( encoder ) {
66
+ input = encoder(input);
67
+ }
68
+
69
+ // Stop if no valid number was provided, the number is infinite or NaN.
70
+ if ( !isValidNumber(input) ) {
71
+ return false;
72
+ }
73
+
74
+ // Rounding away decimals might cause a value of -0
75
+ // when using very small ranges. Remove those cases.
76
+ if ( decimals && parseFloat(input.toFixed(decimals)) === 0 ) {
77
+ input = 0;
78
+ }
79
+
80
+ // Formatting is done on absolute numbers,
81
+ // decorated by an optional negative symbol.
82
+ if ( input < 0 ) {
83
+ inputIsNegative = true;
84
+ input = Math.abs(input);
85
+ }
86
+
87
+ // Reduce the number of decimals to the specified option.
88
+ if ( decimals !== false ) {
89
+ input = toFixed( input, decimals );
90
+ }
91
+
92
+ // Transform the number into a string, so it can be split.
93
+ input = input.toString();
94
+
95
+ // Break the number on the decimal separator.
96
+ if ( input.indexOf('.') !== -1 ) {
97
+ inputPieces = input.split('.');
98
+
99
+ inputBase = inputPieces[0];
100
+
101
+ if ( mark ) {
102
+ inputDecimals = mark + inputPieces[1];
103
+ }
104
+
105
+ } else {
106
+
107
+ // If it isn't split, the entire number will do.
108
+ inputBase = input;
109
+ }
110
+
111
+ // Group numbers in sets of three.
112
+ if ( thousand ) {
113
+ inputBase = strReverse(inputBase).match(/.{1,3}/g);
114
+ inputBase = strReverse(inputBase.join( strReverse( thousand ) ));
115
+ }
116
+
117
+ // If the number is negative, prefix with negation symbol.
118
+ if ( inputIsNegative && negativeBefore ) {
119
+ output += negativeBefore;
120
+ }
121
+
122
+ // Prefix the number
123
+ if ( prefix ) {
124
+ output += prefix;
125
+ }
126
+
127
+ // Normal negative option comes after the prefix. Defaults to '-'.
128
+ if ( inputIsNegative && negative ) {
129
+ output += negative;
130
+ }
131
+
132
+ // Append the actual number.
133
+ output += inputBase;
134
+ output += inputDecimals;
135
+
136
+ // Apply the postfix.
137
+ if ( postfix ) {
138
+ output += postfix;
139
+ }
140
+
141
+ // Run the output through a user-specified post-formatter.
142
+ if ( edit ) {
143
+ output = edit ( output, originalInput );
144
+ }
145
+
146
+ // All done.
147
+ return output;
148
+ }
149
+
150
+ // Accept a sting as input, output decoded number.
151
+ function formatFrom ( decimals, thousand, mark, prefix, postfix, encoder, decoder, negativeBefore, negative, edit, undo, input ) {
152
+
153
+ var originalInput = input, inputIsNegative, output = '';
154
+
155
+ // User defined pre-decoder. Result must be a non empty string.
156
+ if ( undo ) {
157
+ input = undo(input);
158
+ }
159
+
160
+ // Test the input. Can't be empty.
161
+ if ( !input || typeof input !== 'string' ) {
162
+ return false;
163
+ }
164
+
165
+ // If the string starts with the negativeBefore value: remove it.
166
+ // Remember is was there, the number is negative.
167
+ if ( negativeBefore && strStartsWith(input, negativeBefore) ) {
168
+ input = input.replace(negativeBefore, '');
169
+ inputIsNegative = true;
170
+ }
171
+
172
+ // Repeat the same procedure for the prefix.
173
+ if ( prefix && strStartsWith(input, prefix) ) {
174
+ input = input.replace(prefix, '');
175
+ }
176
+
177
+ // And again for negative.
178
+ if ( negative && strStartsWith(input, negative) ) {
179
+ input = input.replace(negative, '');
180
+ inputIsNegative = true;
181
+ }
182
+
183
+ // Remove the postfix.
184
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice
185
+ if ( postfix && strEndsWith(input, postfix) ) {
186
+ input = input.slice(0, -1 * postfix.length);
187
+ }
188
+
189
+ // Remove the thousand grouping.
190
+ if ( thousand ) {
191
+ input = input.split(thousand).join('');
192
+ }
193
+
194
+ // Set the decimal separator back to period.
195
+ if ( mark ) {
196
+ input = input.replace(mark, '.');
197
+ }
198
+
199
+ // Prepend the negative symbol.
200
+ if ( inputIsNegative ) {
201
+ output += '-';
202
+ }
203
+
204
+ // Add the number
205
+ output += input;
206
+
207
+ // Trim all non-numeric characters (allow '.' and '-');
208
+ output = output.replace(/[^0-9\.\-.]/g, '');
209
+
210
+ // The value contains no parse-able number.
211
+ if ( output === '' ) {
212
+ return false;
213
+ }
214
+
215
+ // Covert to number.
216
+ output = Number(output);
217
+
218
+ // Run the user-specified post-decoder.
219
+ if ( decoder ) {
220
+ output = decoder(output);
221
+ }
222
+
223
+ // Check is the output is valid, otherwise: return false.
224
+ if ( !isValidNumber(output) ) {
225
+ return false;
226
+ }
227
+
228
+ return output;
229
+ }
230
+
231
+
232
+ // Framework
233
+
234
+ // Validate formatting options
235
+ function validate ( inputOptions ) {
236
+
237
+ var i, optionName, optionValue,
238
+ filteredOptions = {};
239
+
240
+ for ( i = 0; i < FormatOptions.length; i+=1 ) {
241
+
242
+ optionName = FormatOptions[i];
243
+ optionValue = inputOptions[optionName];
244
+
245
+ if ( optionValue === undefined ) {
246
+
247
+ // Only default if negativeBefore isn't set.
248
+ if ( optionName === 'negative' && !filteredOptions['negativeBefore'] ) {
249
+ filteredOptions[optionName] = '-';
250
+ // Don't set a default for mark when 'thousand' is set.
251
+ } else if ( optionName === 'mark' && filteredOptions['thousand'] !== '.' ) {
252
+ filteredOptions[optionName] = '.';
253
+ } else {
254
+ filteredOptions[optionName] = false;
255
+ }
256
+
257
+ // Floating points in JS are stable up to 7 decimals.
258
+ } else if ( optionName === 'decimals' ) {
259
+ if ( optionValue >= 0 && optionValue < 8 ) {
260
+ filteredOptions[optionName] = optionValue;
261
+ } else {
262
+ throw new Error(optionName);
263
+ }
264
+
265
+ // These options, when provided, must be functions.
266
+ } else if ( optionName === 'encoder' || optionName === 'decoder' || optionName === 'edit' || optionName === 'undo' ) {
267
+ if ( typeof optionValue === 'function' ) {
268
+ filteredOptions[optionName] = optionValue;
269
+ } else {
270
+ throw new Error(optionName);
271
+ }
272
+
273
+ // Other options are strings.
274
+ } else {
275
+
276
+ if ( typeof optionValue === 'string' ) {
277
+ filteredOptions[optionName] = optionValue;
278
+ } else {
279
+ throw new Error(optionName);
280
+ }
281
+ }
282
+ }
283
+
284
+ // Some values can't be extracted from a
285
+ // string if certain combinations are present.
286
+ throwEqualError(filteredOptions, 'mark', 'thousand');
287
+ throwEqualError(filteredOptions, 'prefix', 'negative');
288
+ throwEqualError(filteredOptions, 'prefix', 'negativeBefore');
289
+
290
+ return filteredOptions;
291
+ }
292
+
293
+ // Pass all options as function arguments
294
+ function passAll ( options, method, input ) {
295
+ var i, args = [];
296
+
297
+ // Add all options in order of FormatOptions
298
+ for ( i = 0; i < FormatOptions.length; i+=1 ) {
299
+ args.push(options[FormatOptions[i]]);
300
+ }
301
+
302
+ // Append the input, then call the method, presenting all
303
+ // options as arguments.
304
+ args.push(input);
305
+ return method.apply('', args);
306
+ }
307
+
308
+ /** @constructor */
309
+ function wNumb ( options ) {
310
+
311
+ if ( !(this instanceof wNumb) ) {
312
+ return new wNumb ( options );
313
+ }
314
+
315
+ if ( typeof options !== "object" ) {
316
+ return;
317
+ }
318
+
319
+ options = validate(options);
320
+
321
+ // Call 'formatTo' with proper arguments.
322
+ this['to'] = function ( input ) {
323
+ return passAll(options, formatTo, input);
324
+ };
325
+
326
+ // Call 'formatFrom' with proper arguments.
327
+ this['from'] = function ( input ) {
328
+ return passAll(options, formatFrom, input);
329
+ };
330
+ }
331
+
332
+ /** @export */
333
+ window['wNumb'] = wNumb;
334
+
335
+ }());