nouislider-rails 6.2.0 → 7.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.
@@ -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
+ }());