PageSourceSearch

https://www.studentehr.com/Scripts/ion.rangeSlider.js

js studentehr.com collected 2026-10-01 16:32:13 UTC 66,566 bytes, 1,812 lines download raw bytes

1// Ion.RangeSlider
2// version 2.0.2 Build: 287
3// © Denis Ineshin, 2014    https://github.com/IonDen
4//
5// Project page:    http://ionden.com/a/plugins/ion.rangeSlider/en.html
6// GitHub page:     https://github.com/IonDen/ion.rangeSlider
7//
8// Released under MIT licence:
9// http://ionden.com/a/plugins/licence-en.html
10// =====================================================================================================================
11
12;(function ($, document, window, navigator, undefined) {
13    "use strict";
14
15    // =================================================================================================================
16    // Service
17
18    var plugin_count = 0;
19
20    var is_old_ie = (function () {
21        var n = navigator.userAgent,
22            r = /msie\s\d+/i,
23            v;
24        if (n.search(r) > 0) {
25            v = r.exec(n).toString();
26            v = v.split(" ")[1];
27            if (v < 9) {
28                $("html").addClass("lt-ie9");
29                return true;
30            }
31        }
32        return false;
33    } ());
34
35    var is_touch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));
36
37
38    // IE8 fix
39    if (!Function.prototype.bind) {
40        Function.prototype.bind = function bind(that) {
41
42            var target = this;
43            var slice = [].slice;
44
45            if (typeof target != "function") {
46                throw new TypeError();
47            }
48
49            var args = slice.call(arguments, 1),
50                bound = function () {
51
52                    if (this instanceof bound) {
53
54                        var F = function(){};
55                        F.prototype = target.prototype;
56                        var self = new F();
57
58                        var result = target.apply(
59                            self,
60                            args.concat(slice.call(arguments))
61                        );
62                        if (Object(result) === result) {
63                            return result;
64                        }
65                        return self;
66
67                    } else {
68
69                        return target.apply(
70                            that,
71                            args.concat(slice.call(arguments))
72                        );
73
74                    }
75
76                };
77
78            return bound;
79        };
80    }
81
82
83
84    // =================================================================================================================
85    // Template
86
87    var base_html =
88        '<span class="irs">' +
89        '<span class="irs-line" tabindex="-1"><span class="irs-line-left"></span><span class="irs-line-mid"></span><span class="irs-line-right"></span></span>' +
90        '<span class="irs-min">0</span><span class="irs-max">1</span>' +
91        '<span class="irs-from">0</span><span class="irs-to">0</span><span class="irs-single">0</span>' +
92        '</span>' +
93        '<span class="irs-grid"></span>' +
94        '<span class="irs-bar"></span>';
95
96    var single_html =
97        '<span class="irs-bar-edge"></span>' +
98        '<span class="irs-shadow shadow-single"></span>' +
99        '<span class="irs-slider single"></span>';
100
101    var double_html =
102        '<span class="irs-shadow shadow-from"></span>' +
103        '<span class="irs-shadow shadow-to"></span>' +
104        '<span class="irs-slider from"></span>' +
105        '<span class="irs-slider to"></span>';
106
107    var disable_html =
108        '<span class="irs-disable-mask"></span>';
109
110
111
112    // =================================================================================================================
113    // Core
114
115    var IonRangeSlider = function (input, options, plugin_count) {
116        this.VERSION = "2.0.2";
117        this.input = input;
118        this.plugin_count = plugin_count;
119        this.current_plugin = 0;
120        this.calc_count = 0;
121        this.old_from = 0;
122        this.old_to = 0;
123        this.raf_id = null;
124        this.dragging = false;
125        this.force_redraw = false;
126        this.is_key = false;
127        this.is_update = false;
128        this.is_start = true;
129        this.is_active = false;
130        this.is_resize = false;
131        this.is_click = false;
132
133        this.$cache = {
134            win: $(window),
135            body: $(document.body),
136            input: $(input),
137            cont: null,
138            rs: null,
139            min: null,
140            max: null,
141            from: null,
142            to: null,
143            single: null,
144            bar: null,
145            line: null,
146            s_single: null,
147            s_from: null,
148            s_to: null,
149            shad_single: null,
150            shad_from: null,
151            shad_to: null,
152            grid: null,
153            grid_labels: []
154        };
155
156        // get config data attributes
157        var $inp = this.$cache.input;
158        var data = {
159            type: $inp.data("type"),
160
161            min: $inp.data("min"),
162            max: $inp.data("max"),
163            from: $inp.data("from"),
164            to: $inp.data("to"),
165            step: $inp.data("step"),
166
167            min_interval: $inp.data("minInterval"),
168            max_interval: $inp.data("maxInterval"),
169            drag_interval: $inp.data("dragInterval"),
170
171            values: $inp.data("values"),
172
173            from_fixed: $inp.data("fromFixed"),
174            from_min: $inp.data("fromMin"),
175            from_max: $inp.data("fromMax"),
176            from_shadow: $inp.data("fromShadow"),
177
178            to_fixed: $inp.data("toFixed"),
179            to_min: $inp.data("toMin"),
180            to_max: $inp.data("toMax"),
181            to_shadow: $inp.data("toShadow"),
182
183            prettify_enabled: $inp.data("prettifyEnabled"),
184            prettify_separator: $inp.data("prettifySeparator"),
185
186            force_edges: $inp.data("forceEdges"),
187
188            keyboard: $inp.data("keyboard"),
189            keyboard_step: $inp.data("keyboardStep"),
190
191            grid: $inp.data("grid"),
192            grid_margin: $inp.data("gridMargin"),
193            grid_num: $inp.data("gridNum"),
194            grid_snap: $inp.data("gridSnap"),
195
196            hide_min_max: $inp.data("hideMinMax"),
197            hide_from_to: $inp.data("hideFromTo"),
198
199            prefix: $inp.data("prefix"),
200            postfix: $inp.data("postfix"),
201            max_postfix: $inp.data("maxPostfix"),
202            decorate_both: $inp.data("decorateBoth"),
203            values_separator: $inp.data("valuesSeparator"),
204
205            disable: $inp.data("disable")
206        };
207        data.values = data.values && data.values.split(",");
208        options = $.extend(data, options);
209
210        // get config from options
211        this.options = $.extend({
212            type: "single",
213
214            min: 10,
215            max: 100,
216            from: null,
217            to: null,
218            step: 1,
219
220            min_interval: 0,
221            max_interval: 0,
222            drag_interval: false,
223
224            values: [],
225            p_values: [],
226
227            from_fixed: false,
228            from_min: null,
229            from_max: null,
230            from_shadow: false,
231
232            to_fixed: false,
233            to_min: null,
234            to_max: null,
235            to_shadow: false,
236
237            prettify_enabled: true,
238            prettify_separator: " ",
239            prettify: null,
240
241            force_edges: false,
242
243            keyboard: false,
244            keyboard_step: 5,
245
246            grid: false,
247            grid_margin: true,
248            grid_num: 4,
249            grid_snap: false,
250
251            hide_min_max: false,
252            hide_from_to: false,
253
254            prefix: "",
255            postfix: "",
256            max_postfix: "",
257            decorate_both: true,
258            values_separator: " — ",
259
260            disable: false,
261
262            onStart: null,
263            onChange: null,
264            onFinish: null,
265            onUpdate: null
266        }, options);
267
268        this.validate();
269
270        this.result = {
271            input: this.$cache.input,
272            slider: null,
273
274            min: this.options.min,
275            max: this.options.max,
276
277            from: this.options.from,
278            from_percent: 0,
279            from_value: null,
280
281            to: this.options.to,
282            to_percent: 0,
283            to_value: null
284        };
285
286        this.coords = {
287            // left
288            x_gap: 0,
289            x_pointer: 0,
290
291            // width
292            w_rs: 0,
293            w_rs_old: 0,
294            w_handle: 0,
295
296            // percents
297            p_gap: 0,
298            p_gap_left: 0,
299            p_gap_right: 0,
300            p_step: 0,
301            p_pointer: 0,
302            p_handle: 0,
303            p_single: 0,
304            p_single_real: 0,
305            p_from: 0,
306            p_from_real: 0,
307            p_to: 0,
308            p_to_real: 0,
309            p_bar_x: 0,
310            p_bar_w: 0,
311
312            // grid
313            grid_gap: 0,
314            big_num: 0,
315            big: [],
316            big_w: [],
317            big_p: [],
318            big_x: []
319        };
320
321        this.labels = {
322            // width
323            w_min: 0,
324            w_max: 0,
325            w_from: 0,
326            w_to: 0,
327            w_single: 0,
328
329            // percents
330            p_min: 0,
331            p_max: 0,
332            p_from: 0,
333            p_from_left: 0,
334            p_to: 0,
335            p_to_left: 0,
336            p_single: 0,
337            p_single_left: 0
338        };
339
340        this.init();
341    };
342
343    IonRangeSlider.prototype = {
344        init: function (is_update) {
345            this.coords.p_step = this.options.step / ((this.options.max - this.options.min) / 100);
346            this.target = "base";
347
348            this.toggleInput();
349            this.append();
350            this.setMinMax();
351
352            if (is_update) {
353                this.force_redraw = true;
354                this.calc(true);
355
356                if (this.options.onUpdate && typeof this.options.onUpdate === "function") {
357                    this.options.onUpdate(this.result);
358                }
359            } else {
360                this.force_redraw = true;
361                this.calc(true);
362
363                if (this.options.onStart && typeof this.options.onStart === "function") {
364                    this.options.onStart(this.result);
365                }
366            }
367
368            this.updateScene();
369            this.raf_id = requestAnimationFrame(this.updateScene.bind(this));
370        },
371
372        append: function () {
373            var container_html = '<span class="irs js-irs-' + this.plugin_count + '"></span>';
374            this.$cache.input.before(container_html);
375            this.$cache.input.prop("readonly", true);
376            this.$cache.cont = this.$cache.input.prev();
377            this.result.slider = this.$cache.cont;
378
379            this.$cache.cont.html(base_html);
380            this.$cache.rs = this.$cache.cont.find(".irs");
381            this.$cache.min = this.$cache.cont.find(".irs-min");
382            this.$cache.max = this.$cache.cont.find(".irs-max");
383            this.$cache.from = this.$cache.cont.find(".irs-from");
384            this.$cache.to = this.$cache.cont.find(".irs-to");
385            this.$cache.single = this.$cache.cont.find(".irs-single");
386            this.$cache.bar = this.$cache.cont.find(".irs-bar");
387            this.$cache.line = this.$cache.cont.find(".irs-line");
388            this.$cache.grid = this.$cache.cont.find(".irs-grid");
389
390            if (this.options.type === "single") {
391                this.$cache.cont.append(single_html);
392                this.$cache.s_single = this.$cache.cont.find(".single");
393                this.$cache.from[0].style.visibility = "hidden";
394                this.$cache.to[0].style.visibility = "hidden";
395                this.$cache.shad_single = this.$cache.cont.find(".shadow-single");
396            } else {
397                this.$cache.cont.append(double_html);
398                this.$cache.s_from = this.$cache.cont.find(".from");
399                this.$cache.s_to = this.$cache.cont.find(".to");
400                this.$cache.shad_from = this.$cache.cont.find(".shadow-from");
401                this.$cache.shad_to = this.$cache.cont.find(".shadow-to");
402            }
403
404            if (this.options.hide_from_to) {
405                this.$cache.from[0].style.display = "none";
406                this.$cache.to[0].style.display = "none";
407                this.$cache.single[0].style.display = "none";
408            }
409
410            this.appendGrid();
411
412            if (this.options.disable) {
413                this.appendDisableMask();
414            } else {
415                this.$cache.cont.removeClass("irs-disabled");
416                this.bindEvents();
417            }
418        },
419
420        appendDisableMask: function () {
421            this.$cache.cont.append(disable_html);
422            this.$cache.cont.addClass("irs-disabled");
423        },
424
425        remove: function () {
426            this.$cache.cont.remove();
427            this.$cache.cont = null;
428
429            this.$cache.line.off("keydown.irs_" + this.plugin_count);
430
431            if (is_touch) {
432
433                this.$cache.body.off("touchmove.irs_" + this.plugin_count);
434                this.$cache.win.off("touchend.irs_" + this.plugin_count);
435
436            } else {
437
438                this.$cache.body.off("mousemove.irs_" + this.plugin_count);
439                this.$cache.win.off("mouseup.irs_" + this.plugin_count);
440
441                if (is_old_ie) {
442                    this.$cache.body.off("mouseup.irs_" + this.plugin_count);
443                    this.$cache.body.off("mouseleave.irs_" + this.plugin_count);
444                }
445
446            }
447
448            this.$cache.grid_labels = [];
449            this.coords.big = [];
450            this.coords.big_w = [];
451            this.coords.big_p = [];
452            this.coords.big_x = [];
453
454            cancelAnimationFrame(this.raf_id);
455        },
456
457        bindEvents: function () {
458            if (is_touch) {
459
460                this.$cache.body.on("touchmove.irs_" + this.plugin_count, this.pointerMove.bind(this));
461                this.$cache.win.on("touchend.irs_" + this.plugin_count, this.pointerUp.bind(this));
462
463                this.$cache.line.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
464
465                if (this.options.drag_interval && this.options.type === "double") {
466                    this.$cache.bar.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "both"));
467                } else {
468                    this.$cache.bar.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
469                }
470
471                if (this.options.type === "single") {
472                    this.$cache.s_single.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
473                    this.$cache.shad_single.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
474                } else {
475                    this.$cache.s_from.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
476                    this.$cache.s_to.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
477                    this.$cache.shad_from.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
478                    this.$cache.shad_to.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
479                }
480
481            } else {
482
483                if (this.options.keyboard) {
484                    this.$cache.line.on("keydown.irs_" + this.plugin_count, this.key.bind(this, "keyboard"));
485                }
486
487                this.$cache.body.on("mousemove.irs_" + this.plugin_count, this.pointerMove.bind(this));
488                this.$cache.win.on("mouseup.irs_" + this.plugin_count, this.pointerUp.bind(this));
489
490                if (is_old_ie) {
491                    this.$cache.body.on("mouseup.irs_" + this.plugin_count, this.pointerUp.bind(this));
492                    this.$cache.body.on("mouseleave.irs_" + this.plugin_count, this.pointerUp.bind(this));
493                }
494
495                this.$cache.line.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
496
497                if (this.options.drag_interval && this.options.type === "double") {
498                    this.$cache.bar.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "both"));
499                } else {
500                    this.$cache.bar.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
501                }
502
503
504                if (this.options.type === "single") {
505                    this.$cache.s_single.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
506                    this.$cache.shad_single.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
507                } else {
508                    this.$cache.s_from.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
509                    this.$cache.s_to.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
510                    this.$cache.shad_from.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
511                    this.$cache.shad_to.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
512                }
513
514            }
515        },
516
517        pointerMove: function (e) {
518            if (!this.dragging) {
519                return;
520            }
521            var e_base = is_touch ? e.originalEvent.touches[0] : e;
522            this.coords.x_pointer = e_base.pageX - this.coords.x_gap;
523
524            this.calc();
525        },
526
527        pointerUp: function (e) {
528            if (this.current_plugin !== this.plugin_count) {
529                return;
530            }
531
532            if (this.is_active) {
533                this.is_active = false;
534            } else {
535                return;
536            }
537
538            var is_function = this.options.onFinish && typeof this.options.onFinish === "function",
539                is_original = $.contains(this.$cache.cont[0], e.target) || this.dragging;
540
541            if (is_function && is_original) {
542                this.options.onFinish(this.result);
543            }
544
545            this.force_redraw = true;
546            this.dragging = false;
547
548            if (is_old_ie) {
549                $("*").prop("unselectable", false);
550            }
551        },
552
553        pointerDown: function (target, e) {
554            e.preventDefault();
555            var e_base = is_touch ? e.originalEvent.touches[0] : e;
556            if (e.button === 2) {
557                return;
558            }
559
560            this.current_plugin = this.plugin_count;
561            this.target = target;
562
563            this.is_active = true;
564            this.dragging = true;
565
566            this.coords.x_gap = this.$cache.rs.offset().left;
567            this.coords.x_pointer = e_base.pageX - this.coords.x_gap;
568
569            this.calcPointer();
570
571            switch (target) {
572                case "single":
573                    this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_single);
574                    break;
575                case "from":
576                    this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_from);
577                    this.$cache.s_from.addClass("type_last");
578                    this.$cache.s_to.removeClass("type_last");
579                    break;
580                case "to":
581                    this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_to);
582                    this.$cache.s_to.addClass("type_last");
583                    this.$cache.s_from.removeClass("type_last");
584                    break;
585                case "both":
586                    this.coords.p_gap_left = this.toFixed(this.coords.p_pointer - this.coords.p_from);
587                    this.coords.p_gap_right = this.toFixed(this.coords.p_to - this.coords.p_pointer);
588                    this.$cache.s_to.removeClass("type_last");
589                    this.$cache.s_from.removeClass("type_last");
590                    break;
591            }
592
593            if (is_old_ie) {
594                $("*").prop("unselectable", true);
595            }
596
597            this.$cache.line.trigger("focus");
598        },
599
600        pointerClick: function (target, e) {
601            e.preventDefault();
602            var e_base = is_touch ? e.originalEvent.touches[0] : e;
603            if (e.button === 2) {
604                return;
605            }
606
607            this.current_plugin = this.plugin_count;
608            this.target = target;
609
610            this.is_click = true;
611            this.coords.x_gap = this.$cache.rs.offset().left;
612            this.coords.x_pointer = +(e_base.pageX - this.coords.x_gap).toFixed();
613
614            this.force_redraw = true;
615            this.calc();
616
617            this.$cache.line.trigger("focus");
618        },
619
620        key: function (target, e) {
621            if (this.current_plugin !== this.plugin_count || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
622                return;
623            }
624
625            switch (e.which) {
626                case 83: // W
627                case 65: // A
628                case 40: // DOWN
629                case 37: // LEFT
630                    e.preventDefault();
631                    this.moveByKey(false);
632                    break;
633
634                case 87: // S
635                case 68: // D
636                case 38: // UP
637                case 39: // RIGHT
638                    e.preventDefault();
639                    this.moveByKey(true);
640                    break;
641            }
642
643            return true;
644        },
645
646        // Move by key beta
647        // TODO: refactor than have plenty of time
648        moveByKey: function (right) {
649            var p = this.coords.p_pointer;
650
651            if (right) {
652                p += this.options.keyboard_step;
653            } else {
654                p -= this.options.keyboard_step;
655            }
656
657            this.coords.x_pointer = this.toFixed(this.coords.w_rs / 100 * p);
658            this.is_key = true;
659            this.calc();
660        },
661
662        setMinMax: function () {
663            if (this.options.hide_min_max) {
664                this.$cache.min[0].style.display = "none";
665                this.$cache.max[0].style.display = "none";
666                return;
667            }
668
669            if (this.options.values.length) {
670                this.$cache.min.html(this.decorate(this.options.p_values[this.options.min]));
671                this.$cache.max.html(this.decorate(this.options.p_values[this.options.max]));
672            } else {
673                this.$cache.min.html(this.decorate(this._prettify(this.options.min), this.options.min));
674                this.$cache.max.html(this.decorate(this._prettify(this.options.max), this.options.max));
675            }
676
677            this.labels.w_min = this.$cache.min.outerWidth(false);
678            this.labels.w_max = this.$cache.max.outerWidth(false);
679        },
680
681
682
683        // =============================================================================================================
684        // Calculations
685
686        calc: function (update) {
687            this.calc_count++;
688
689            if (this.calc_count === 10 || update) {
690                this.calc_count = 0;
691                this.coords.w_rs = this.$cache.rs.outerWidth(false);
692                if (this.options.type === "single") {
693                    this.coords.w_handle = this.$cache.s_single.outerWidth(false);
694                } else {
695                    this.coords.w_handle = this.$cache.s_from.outerWidth(false);
696                }
697            }
698
699            if (!this.coords.w_rs) {
700                return;
701            }
702
703            this.calcPointer();
704
705            this.coords.p_handle = this.toFixed(this.coords.w_handle / this.coords.w_rs * 100);
706            var real_width = 100 - this.coords.p_handle,
707                real_x = this.toFixed(this.coords.p_pointer - this.coords.p_gap);
708
709            if (this.target === "click") {
710                real_x = this.toFixed(this.coords.p_pointer - (this.coords.p_handle / 2));
711                this.target = this.chooseHandle(real_x);
712            }
713
714            if (real_x < 0) {
715                real_x = 0;
716            } else if (real_x > real_width) {
717                real_x = real_width;
718            }
719
720            switch (this.target) {
721                case "base":
722                    var w = (this.options.max - this.options.min) / 100,
723                        f = (this.result.from - this.options.min) / w,
724                        t = (this.result.to - this.options.min) / w;
725
726                    this.coords.p_single_real = this.toFixed(f);
727                    this.coords.p_from_real = this.toFixed(f);
728                    this.coords.p_to_real = this.toFixed(t);
729
730                    this.coords.p_single_real = this.checkDiapason(this.coords.p_single_real, this.options.from_min, this.options.from_max);
731                    this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
732                    this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
733
734                    this.coords.p_single = this.toFixed(f - (this.coords.p_handle / 100 * f));
735                    this.coords.p_from = this.toFixed(f - (this.coords.p_handle / 100 * f));
736                    this.coords.p_to = this.toFixed(t - (this.coords.p_handle / 100 * t));
737
738                    this.target = null;
739
740                    break;
741
742                case "single":
743                    if (this.options.from_fixed) {
744                        break;
745                    }
746
747                    this.coords.p_single_real = this.calcWithStep(real_x / real_width * 100);
748                    this.coords.p_single_real = this.checkDiapason(this.coords.p_single_real, this.options.from_min, this.options.from_max);
749                    this.coords.p_single = this.toFixed(this.coords.p_single_real / 100 * real_width);
750
751                    break;
752
753                case "from":
754                    if (this.options.from_fixed) {
755                        break;
756                    }
757
758                    this.coords.p_from_real = this.calcWithStep(real_x / real_width * 100);
759                    if (this.coords.p_from_real > this.coords.p_to_real) {
760                        this.coords.p_from_real = this.coords.p_to_real;
761                    }
762                    this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
763                    this.coords.p_from_real = this.checkMinInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
764                    this.coords.p_from_real = this.checkMaxInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
765                    this.coords.p_from = this.toFixed(this.coords.p_from_real / 100 * real_width);
766
767                    break;
768
769                case "to":
770                    if (this.options.to_fixed) {
771                        break;
772                    }
773
774                    this.coords.p_to_real = this.calcWithStep(real_x / real_width * 100);
775                    if (this.coords.p_to_real < this.coords.p_from_real) {
776                        this.coords.p_to_real = this.coords.p_from_real;
777                    }
778                    this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
779                    this.coords.p_to_real = this.checkMinInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
780                    this.coords.p_to_real = this.checkMaxInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
781                    this.coords.p_to = this.toFixed(this.coords.p_to_real / 100 * real_width);
782
783                    break;
784
785                case "both":
786                    real_x = this.toFixed(real_x + (this.coords.p_handle * 0.1));
787
788                    this.coords.p_from_real = this.calcWithStep((real_x - this.coords.p_gap_left) / real_width * 100);
789                    this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
790                    this.coords.p_from_real = this.checkMinInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
791                    this.coords.p_from = this.toFixed(this.coords.p_from_real / 100 * real_width);
792
793                    this.coords.p_to_real = this.calcWithStep((real_x + this.coords.p_gap_right) / real_width * 100);
794                    this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
795                    this.coords.p_to_real = this.checkMinInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
796                    this.coords.p_to = this.toFixed(this.coords.p_to_real / 100 * real_width);
797
798                    break;
799            }
800
801            if (this.options.type === "single") {
802                this.coords.p_bar_x = (this.coords.p_handle / 2);
803                this.coords.p_bar_w = this.coords.p_single;
804
805                this.result.from_percent = this.coords.p_single_real;
806                this.result.from = this.calcReal(this.coords.p_single_real);
807                if (this.options.values.length) {
808                    this.result.from_value = this.options.values[this.result.from];
809                }
810            } else {
811                this.coords.p_bar_x = this.toFixed(this.coords.p_from + (this.coords.p_handle / 2));
812                this.coords.p_bar_w = this.toFixed(this.coords.p_to - this.coords.p_from);
813
814                this.result.from_percent = this.coords.p_from_real;
815                this.result.from = this.calcReal(this.coords.p_from_real);
816                this.result.to_percent = this.coords.p_to_real;
817                this.result.to = this.calcReal(this.coords.p_to_real);
818                if (this.options.values.length) {
819                    this.result.from_value = this.options.values[this.result.from];
820                    this.result.to_value = this.options.values[this.result.to];
821                }
822            }
823
824            this.calcMinMax();
825            this.calcLabels();
826        },
827
828        calcPointer: function () {
829            if (!this.coords.w_rs) {
830                this.coords.p_pointer = 0;
831                return;
832            }
833
834            if (this.coords.x_pointer < 0) {
835                this.coords.x_pointer = 0;
836            } else if (this.coords.x_pointer > this.coords.w_rs) {
837                this.coords.x_pointer = this.coords.w_rs;
838            }
839
840            this.coords.p_pointer = this.toFixed(this.coords.x_pointer / this.coords.w_rs * 100);
841        },
842
843        chooseHandle: function (real_x) {
844            if (this.options.type === "single") {
845                return "single";
846            } else {
847                var m_point = this.coords.p_from_real + ((this.coords.p_to_real - this.coords.p_from_real) / 2);
848                if (real_x >= m_point) {
849                    return "to";
850                } else {
851                    return "from";
852                }
853            }
854        },
855
856        calcMinMax: function () {
857            if (!this.coords.w_rs) {
858                return;
859            }
860
861            this.labels.p_min = this.labels.w_min / this.coords.w_rs * 100;
862            this.labels.p_max = this.labels.w_max / this.coords.w_rs * 100;
863        },
864
865        calcLabels: function () {
866            if (!this.
866coords.w_rs || this.options.hide_from_to) {
867                return;
868            }
869
870            if (this.options.type === "single") {
871
872                this.labels.w_single = this.$cache.single.outerWidth(false);
873                this.labels.p_single = this.labels.w_single / this.coords.w_rs * 100;
874                this.labels.p_single_left = this.coords.p_single + (this.coords.p_handle / 2) - (this.labels.p_single / 2);
875                this.labels.p_single_left = this.checkEdges(this.labels.p_single_left, this.labels.p_single);
876
877            } else {
878
879                this.labels.w_from = this.$cache.from.outerWidth(false);
880                this.labels.p_from = this.labels.w_from / this.coords.w_rs * 100;
881                this.labels.p_from_left = this.coords.p_from + (this.coords.p_handle / 2) - (this.labels.p_from / 2);
882                this.labels.p_from_left = this.toFixed(this.labels.p_from_left);
883                this.labels.p_from_left = this.checkEdges(this.labels.p_from_left, this.labels.p_from);
884
885                this.labels.w_to = this.$cache.to.outerWidth(false);
886                this.labels.p_to = this.labels.w_to / this.coords.w_rs * 100;
887                this.labels.p_to_left = this.coords.p_to + (this.coords.p_handle / 2) - (this.labels.p_to / 2);
888                this.labels.p_to_left = this.toFixed(this.labels.p_to_left);
889                this.labels.p_to_left = this.checkEdges(this.labels.p_to_left, this.labels.p_to);
890
891                this.labels.w_single = this.$cache.single.outerWidth(false);
892                this.labels.p_single = this.labels.w_single / this.coords.w_rs * 100;
893                this.labels.p_single_left = ((this.labels.p_from_left + this.labels.p_to_left + this.labels.p_to) / 2) - (this.labels.p_single / 2);
894                this.labels.p_single_left = this.toFixed(this.labels.p_single_left);
895                this.labels.p_single_left = this.checkEdges(this.labels.p_single_left, this.labels.p_single);
896
897            }
898        },
899
900
901
902        // =============================================================================================================
903        // Drawings
904
905        updateScene: function () {
906            this.drawHandles();
907
908            this.raf_id = requestAnimationFrame(this.updateScene.bind(this));
909        },
910
911        drawHandles: function () {
912            this.coords.w_rs = this.$cache.rs.outerWidth(false);
913
914            if (this.coords.w_rs !== this.coords.w_rs_old) {
915                this.target = "base";
916                this.is_resize = true;
917            }
918
919            if (this.coords.w_rs !== this.coords.w_rs_old || this.force_redraw) {
920                this.setMinMax();
921                this.calc(true);
922                this.drawLabels();
923                if (this.options.grid) {
924                    this.calcGridMargin();
925                    this.calcGridLabels();
926                }
927                this.force_redraw = true;
928                this.coords.w_rs_old = this.coords.w_rs;
929                this.drawShadow();
930            }
931
932            if (!this.coords.w_rs) {
933                return;
934            }
935
936            if (!this.dragging && !this.force_redraw && !this.is_key) {
937                return;
938            }
939
940            if (this.old_from !== this.result.from || this.old_to !== this.result.to || this.force_redraw || this.is_key) {
941
942                this.drawLabels();
943
944                this.$cache.bar[0].style.left = this.coords.p_bar_x + "%";
945                this.$cache.bar[0].style.width = this.coords.p_bar_w + "%";
946
947                if (this.options.type === "single") {
948                    this.$cache.s_single[0].style.left = this.coords.p_single + "%";
949
950                    this.$cache.single[0].style.left = this.labels.p_single_left + "%";
951
952                    if (this.options.values.length) {
953                        this.$cache.input.prop("value", this.result.from_value);
954                        this.$cache.input.data("from", this.result.from_value);
955                    } else {
956                        this.$cache.input.prop("value", this.result.from);
957                        this.$cache.input.data("from", this.result.from);
958                    }
959                } else {
960                    this.$cache.s_from[0].style.left = this.coords.p_from + "%";
961                    this.$cache.s_to[0].style.left = this.coords.p_to + "%";
962
963                    if (this.old_from !== this.result.from || this.force_redraw) {
964                        this.$cache.from[0].style.left = this.labels.p_from_left + "%";
965                    }
966                    if (this.old_to !== this.result.to || this.force_redraw) {
967                        this.$cache.to[0].style.left = this.labels.p_to_left + "%";
968                    }
969
970                    this.$cache.single[0].style.left = this.labels.p_single_left + "%";
971
972                    if (this.options.values.length) {
973                        this.$cache.input.prop("value", this.result.from_value + ";" + this.result.to_value);
974                        this.$cache.input.data("from", this.result.from_value);
975                        this.$cache.input.data("to", this.result.to_value);
976                    } else {
977                        this.$cache.input.prop("value", this.result.from + ";" + this.result.to);
978                        this.$cache.input.data("from", this.result.from);
979                        this.$cache.input.data("to", this.result.to);
980                    }
981                }
982
983                if ((this.old_from !== this.result.from || this.old_to !== this.result.to) && !this.is_start) {
984                    this.$cache.input.trigger("change");
985                }
986
987                this.old_from = this.result.from;
988                this.old_to = this.result.to;
989
990                var is_function = this.options.onChange && typeof this.options.onChange === "function" && !this.is_resize;
991                if (is_function && !this.is_update && !this.is_start) {
992                    this.options.onChange(this.result);
993                }
994
995                var is_finish = this.options.onFinish && typeof this.options.onFinish === "function";
996                if (is_finish && (this.is_key || this.is_click)) {
997                    this.options.onFinish(this.result);
998                }
999
1000                this.is_update = false;
1001                this.is_resize = false;
1002            }
1003
1004            this.is_start = false;
1005            this.is_key = false;
1006            this.is_click = false;
1007            this.force_redraw = false;
1008        },
1009
1010        drawLabels: function () {
1011            var values_num = this.options.values.length,
1012                p_values = this.options.p_values,
1013                text_single,
1014                text_from,
1015                text_to;
1016
1017            if (this.options.hide_from_to) {
1018                return;
1019            }
1020
1021            if (this.options.type === "single") {
1022
1023                if (values_num) {
1024                    text_single = this.decorate(p_values[this.result.from]);
1025                    this.$cache.single.html(text_single);
1026                } else {
1027                    text_single = this.decorate(this._prettify(this.result.from), this.result.from);
1028                    this.$cache.single.html(text_single);
1029                }
1030
1031                this.calcLabels();
1032
1033                if (this.labels.p_single_left < this.labels.p_min + 1) {
1034                    this.$cache.min[0].style.visibility = "hidden";
1035                } else {
1036                    this.$cache.min[0].style.visibility = "visible";
1037                }
1038
1039                if (this.labels.p_single_left + this.labels.p_single > 100 - this.labels.p_max - 1) {
1040                    this.$cache.max[0].style.visibility = "hidden";
1041                } else {
1042                    this.$cache.max[0].style.visibility = "visible";
1043                }
1044
1045            } else {
1046
1047                if (values_num) {
1048
1049                    if (this.options.decorate_both) {
1050                        text_single = this.decorate(p_values[this.result.from]);
1051                        text_single += this.options.values_separator;
1052                        text_single += this.decorate(p_values[this.result.to]);
1053                    } else {
1054                        text_single = this.decorate(p_values[this.result.from] + this.options.values_separator + p_values[this.result.to]);
1055                    }
1056                    text_from = this.decorate(p_values[this.result.from]);
1057                    text_to = this.decorate(p_values[this.result.to]);
1058
1059                    this.$cache.single.html(text_single);
1060                    this.$cache.from.html(text_from);
1061                    this.$cache.to.html(text_to);
1062
1063                } else {
1064
1065                    if (this.options.decorate_both) {
1066                        text_single = this.decorate(this._prettify(this.result.from));
1067                        text_single += this.options.values_separator;
1068                        text_single += this.decorate(this._prettify(this.result.to));
1069                    } else {
1070                        text_single = this.decorate(this._prettify(this.result.from) + this.options.values_separator + this._prettify(this.result.to), this.result.from);
1071                    }
1072                    text_from = this.decorate(this._prettify(this.result.from), this.result.from);
1073                    text_to = this.decorate(this._prettify(this.result.to), this.result.to);
1074
1075                    this.$cache.single.html(text_single);
1076                    this.$cache.from.html(text_from);
1077                    this.$cache.to.html(text_to);
1078
1079                }
1080
1081                this.calcLabels();
1082
1083                var min = Math.min(this.labels.p_single_left, this.labels.p_from_left),
1084                    single_left = this.labels.p_single_left + this.labels.p_single,
1085                    to_left = this.labels.p_to_left + this.labels.p_to,
1086                    max = Math.max(single_left, to_left);
1087
1088                if (this.labels.p_from_left + this.labels.p_from >= this.labels.p_to_left) {
1089                    this.$cache.from[0].style.visibility = "hidden";
1090                    this.$cache.to[0].style.visibility = "hidden";
1091                    this.$cache.single[0].style.visibility = "visible";
1092
1093                    if (this.result.from === this.result.to) {
1094                        this.$cache.from[0].style.visibility = "visible";
1095                        this.$cache.single[0].style.visibility = "hidden";
1096                        max = to_left;
1097                    } else {
1098                        this.$cache.from[0].style.visibility = "hidden";
1099                        this.$cache.single[0].style.visibility = "visible";
1100                        max = Math.max(single_left, to_left);
1101                    }
1102                } else {
1103                    this.$cache.from[0].style.visibility = "visible";
1104                    this.$cache.to[0].style.visibility = "visible";
1105                    this.$cache.single[0].style.visibility = "hidden";
1106                }
1107
1108                if (min < this.labels.p_min + 1) {
1109                    this.$cache.min[0].style.visibility = "hidden";
1110                } else {
1111                    this.$cache.min[0].style.visibility = "visible";
1112                }
1113
1114                if (max > 100 - this.labels.p_max - 1) {
1115                    this.$cache.max[0].style.visibility = "hidden";
1116                } else {
1117                    this.$cache.max[0].style.visibility = "visible";
1118                }
1119
1120            }
1121        },
1122
1123        drawShadow: function () {
1124            var o = this.options,
1125                c = this.$cache,
1126                from_min,
1127                from_max,
1128                to_min,
1129                to_max;
1130
1131            if (o.type === "single") {
1132                if (o.from_shadow && (o.from_min || o.from_max)) {
1133                    from_min = this.calcPercent(o.from_min || o.min);
1134                    from_max = this.calcPercent(o.from_max || o.max) - from_min;
1135                    from_min = this.toFixed(from_min - (this.coords.p_handle / 100 * from_min));
1136                    from_max = this.toFixed(from_max - (this.coords.p_handle / 100 * from_max));
1137                    from_min = from_min + (this.coords.p_handle / 2);
1138
1139                    c.shad_single[0].style.display = "block";
1140                    c.shad_single[0].style.left = from_min + "%";
1141                    c.shad_single[0].style.width = from_max + "%";
1142                } else {
1143                    c.shad_single[0].style.display = "none";
1144                }
1145            } else {
1146                if (o.from_shadow && (o.from_min || o.from_max)) {
1147                    from_min = this.calcPercent(o.from_min || o.min);
1148                    from_max = this.calcPercent(o.from_max || o.max) - from_min;
1149                    from_min = this.toFixed(from_min - (this.coords.p_handle / 100 * from_min));
1150                    from_max = this.toFixed(from_max - (this.coords.p_handle / 100 * from_max));
1151                    from_min = from_min + (this.coords.p_handle / 2);
1152
1153                    c.shad_from[0].style.display = "block";
1154                    c.shad_from[0].style.left = from_min + "%";
1155                    c.shad_from[0].style.width = from_max + "%";
1156                } else {
1157                    c.shad_from[0].style.display = "none";
1158                }
1159
1160                if (o.to_shadow && (o.to_min || o.to_max)) {
1161                    to_min = this.calcPercent(o.to_min || o.min);
1162                    to_max = this.calcPercent(o.to_max || o.max) - to_min;
1163                    to_min = this.toFixed(to_min - (this.coords.p_handle / 100 * to_min));
1164                    to_max = this.toFixed(to_max - (this.coords.p_handle / 100 * to_max));
1165                    to_min = to_min + (this.coords.p_handle / 2);
1166
1167                    c.shad_to[0].style.display = "block";
1168                    c.shad_to[0].style.left = to_min + "%";
1169                    c.shad_to[0].style.width = to_max + "%";
1170                } else {
1171                    c.shad_to[0].style.display = "none";
1172                }
1173            }
1174        },
1175
1176
1177
1178        // =============================================================================================================
1179        // Service methods
1180
1181        toggleInput: function () {
1182            this.$cache.input.toggleClass("irs-hidden-input");
1183        },
1184
1185        calcPercent: function (num) {
1186            var w = (this.options.max - this.options.min) / 100,
1187                percent = (num - this.options.min) / w;
1188
1189            return this.toFixed(percent);
1190        },
1191
1192        calcReal: function (percent) {
1193            var min = this.options.min,
1194                max = this.options.max,
1195                abs = 0;
1196
1197            if (min < 0) {
1198                abs = Math.abs(min);
1199                min = min + abs;
1200                max = max + abs;
1201            }
1202
1203            var number = ((max - min) / 100 * percent) + min,
1204                string = this.options.step.toString().split(".")[1];
1205
1206            if (string) {
1207                number = +number.toFixed(string.length);
1208            } else {
1209                number = number / this.options.step;
1210                number = number * this.options.step;
1211                number = +number.toFixed(0);
1212            }
1213
1214            if (abs) {
1215                number -= abs;
1216            }
1217
1218            if (number < this.options.min) {
1219                number = this.options.min;
1220            } else if (number > this.options.max) {
1221                number = this.options.max;
1222            }
1223
1224            if (string) {
1225                return +number.toFixed(string.length);
1226            } else {
1227                return this.toFixed(number);
1228            }
1229        },
1230
1231        calcWithStep: function (percent) {
1232            var rounded = Math.round(percent / this.coords.p_step) * this.coords.p_step;
1233
1234            if (rounded > 100) {
1235                rounded = 100;
1236            }
1237            if (percent === 100) {
1238                rounded = 100;
1239            }
1240
1241            return this.toFixed(rounded);
1242        },
1243
1244        checkMinInterval: function (p_current, p_next, type) {
1245            var o = this.options,
1246                current,
1247                next;
1248
1249            if (!o.min_interval) {
1250                return p_current;
1251            }
1252
1253            current = this.calcReal(p_current);
1254            next = this.calcReal(p_next);
1255
1256            if (type === "from") {
1257
1258                if (next - current < o.min_interval) {
1259                    current = next - o.min_interval;
1260                }
1261
1262            } else {
1263
1264                if (current - next < o.min_interval) {
1265                    current = next + o.min_interval;
1266                }
1267
1268            }
1269
1270            return this.calcPercent(current);
1271        },
1272
1273        checkMaxInterval: function (p_current, p_next, type) {
1274            var o = this.options,
1275                current,
1276                next;
1277
1278            if (!o.max_interval) {
1279                return p_current;
1280            }
1281
1282            current = this.calcReal(p_current);
1283            next = this.calcReal(p_next);
1284
1285            if (type === "from") {
1286
1287                if (next - current > o.max_interval) {
1288                    current = next - o.max_interval;
1289                }
1290
1291            } else {
1292
1293                if (current - next > o.max_interval) {
1294                    current = next + o.max_interval;
1295                }
1296
1297            }
1298
1299            return this.calcPercent(current);
1300        },
1301
1302        checkDiapason: function (p_num, min, max) {
1303            var num = this.calcReal(p_num),
1304                o = this.options;
1305
1306            if (!min || typeof min !== "number") {
1307                min = o.min;
1308            }
1309
1310            if (!max || typeof max !== "number") {
1311                max = o.max;
1312            }
1313
1314            if (num < min) {
1315                num = min;
1316            }
1317
1318            if (num > max) {
1319                num = max;
1320            }
1321
1322            return this.calcPercent(num);
1323        },
1324
1325        toFixed: function (num) {
1326            num = num.toFixed(5);
1327            return +num;
1328        },
1329
1330        _prettify: function (num) {
1331            if (!this.options.prettify_enabled) {
1332                return num;
1333            }
1334
1335            if (this.options.prettify && typeof this.options.prettify === "function") {
1336                return this.options.prettify(num);
1337            } else {
1338                return this.prettify(num);
1339            }
1340        },
1341
1342        prettify: function (num) {
1343            var n = num.toString();
1344            return n.replace(/(\d{1,3}(?=(?:\d\d\d)+(?!\d)))/g, "$1" + this.options.prettify_separator);
1345        },
1346
1347        checkEdges: function (left, width) {
1348            if (!this.options.force_edges) {
1349                return this.toFixed(left);
1350            }
1351
1352            if (left < 0) {
1353                left = 0;
1354            } else if (left > 100 - width) {
1355                left = 100 - width;
1356            }
1357
1358            return this.toFixed(left);
1359        },
1360
1361        validate: function () {
1362            var o = this.options,
1363                r = this.result,
1364                v = o.values,
1365                vl = v.length,
1366                value,
1367                i;
1368
1369            if (typeof o.min === "string") o.min = +o.min;
1370            if (typeof o.max === "string") o.max = +o.max;
1371            if (typeof o.from === "string") o.from = +o.from;
1372            if (typeof o.to === "string") o.to = +o.to;
1373            if (typeof o.step === "string") o.step = +o.step;
1374
1375            if (typeof o.from_min === "string") o.from_min = +o.from_min;
1376            if (typeof o.from_max === "string") o.from_max = +o.from_max;
1377            if (typeof o.to_min === "string") o.to_min = +o.to_min;
1378            if (typeof o.to_max === "string") o.to_max = +o.to_max;
1379
1380            if (typeof o.keyboard_step === "string") o.keyboard_step = +o.keyboard_step;
1381            if (typeof o.grid_num === "string") o.grid_num = +o.grid_num;
1382
1383            if (o.max <= o.min) {
1384                if (o.min) {
1385                    o.max = o.min * 2;
1386                } else {
1387                    o.max = o.min + 1;
1388                }
1389                o.step = 1;
1390            }
1391
1392            if (vl) {
1393                o.p_values = [];
1394                o.min = 0;
1395                o.max = vl - 1;
1396                o.step = 1;
1397                o.grid_num = o.max;
1398                o.grid_snap = true;
1399
1400
1401                for (i = 0; i < vl; i++) {
1402                    value = +v[i];
1403
1404                    if (!isNaN(value)) {
1405                        v[i] = value;
1406                        value = this._prettify(value);
1407                    } else {
1408                        value = v[i];
1409                    }
1410
1411                    o.p_values.push(value);
1412                }
1413            }
1414
1415            if (typeof o.from !== "number" || isNaN(o.from)) {
1416                o.from = o.min;
1417            }
1418
1419            if (typeof o.to !== "number" || isNaN(o.from)) {
1420                o.to = o.max;
1421            }
1422
1423            if (o.from < o.min || o.from > o.max) {
1424                o.from = o.min;
1425            }
1426
1427            if (o.to > o.max || o.to < o.min) {
1428                o.to = o.max;
1429            }
1430
1431            if (o.type === "double" && o.from > o.to) {
1432                o.from = o.to;
1433            }
1434
1435            if (typeof o.step !== "number" || isNaN(o.step) || !o.step || o.step < 0) {
1436                o.step = 1;
1437            }
1438
1439            if (typeof o.keyboard_step !== "number" || isNaN(o.keyboard_step) || !o.keyboard_step || o.keyboard_step < 0) {
1440                o.keyboard_step = 5;
1441            }
1442
1443            if (o.from_min && o.from < o.from_min) {
1444                o.from = o.from_min;
1445            }
1446
1447            if (o.from_max && o.from > o.from_max) {
1448                o.from = o.from_max;
1449            }
1450
1451            if (o.to_min && o.to < o.to_min) {
1452                o.to = o.to_min;
1453            }
1454
1455            if (o.to_max && o.from > o.to_max) {
1456                o.to = o.to_max;
1457            }
1458
1459            if (r) {
1460                if (r.min !== o.min) {
1461                    r.min = o.min;
1462                }
1463
1464                if (r.max !== o.max) {
1465                    r.max = o.max;
1466                }
1467
1468                if (r.from < r.min || r.from > r.max) {
1469                    r.from = o.from;
1470                }
1471
1472                if (r.to < r.min || r.to > r.max) {
1473                    r.to = o.to;
1474                }
1475            }
1476
1477            if (typeof o.min_interval !== "number" || isNaN(o.min_interval) || !o.min_interval || o.min_interval < 0) {
1478                o.min_interval = 0;
1479            }
1480
1481            if (typeof o.max_interval !== "number" || isNaN(o.max_interval) || !o.max_interval || o.max_interval < 0) {
1482                o.max_interval = 0;
1483            }
1484
1485            if (o.min_interval && o.min_interval > o.max - o.min) {
1486                o.min_interval = o.max - o.min;
1487            }
1488
1489            if (o.max_interval && o.max_interval > o.max - o.min) {
1490                o.max_interval = o.max - o.min;
1491            }
1492        },
1493
1494        decorate: function (num, original) {
1495            var decorated = "",
1496                o = this.options;
1497
1498            if (o.prefix) {
1499                decorated += o.prefix;
1500            }
1501
1502            decorated += num;
1503
1504            if (o.max_postfix) {
1505                if (o.values.length && num === o.p_values[o.max]) {
1506                    decorated += o.max_postfix;
1507                    if (o.postfix) {
1508                        decorated += " ";
1509                    }
1510                } else if (original === o.max) {
1511                    decorated += o.max_postfix;
1512                    if (o.postfix) {
1513                        decorated += " ";
1514                    }
1515                }
1516            }
1517
1518            if (o.postfix) {
1519                decorated += o.postfix;
1520            }
1521
1522            return decorated;
1523        },
1524
1525        updateFrom: function () {
1526            this.result.from = this.options.from;
1527            this.result.from_percent = this.calcPercent(this.result.from);
1528            if (this.options.values) {
1529                this.result.from_value = this.options.values[this.result.from];
1530            }
1531        },
1532
1533        updateTo: function () {
1534            this.result.to = this.options.to;
1535            this.result.to_percent = this.calcPercent(this.result.to);
1536            if (this.options.values) {
1537                this.result.to_value = this.options.values[this.result.to];
1538            }
1539        },
1540
1541        updateResult: function () {
1542            this.result.min = this.options.min;
1543            this.result.max = this.options.max;
1544            this.updateFrom();
1545            this.updateTo();
1546        },
1547
1548
1549        // =============================================================================================================
1550        // Grid
1551
1552        appendGrid: function () {
1553            if (!this.options.grid) {
1554                return;
1555            }
1556
1557            var o = this.options,
1558                i, z,
1559
1560                total = o.max - o.min,
1561                big_num = o.grid_num,
1562                big_p = 0,
1563                big_w = 0,
1564
1565                small_max = 4,
1566                local_small_max,
1567                small_p,
1568                small_w = 0,
1569
1570                result,
1571                html = '';
1572
1573
1574
1575            this.calcGridMargin();
1576
1577            if (o.grid_snap) {
1578                big_num = total / o.step;
1579                big_p = this.toFixed(o.step / (total / 100));
1580            } else {
1581                big_p = this.toFixed(100 / big_num);
1582            }
1583
1584            if (big_num > 4) {
1585                small_max = 3;
1586            }
1587            if (big_num > 7) {
1588                small_max = 2;
1589            }
1590            if (big_num > 14) {
1591                small_max = 1;
1592            }
1593            if (big_num > 28) {
1594                small_max = 0;
1595            }
1596
1597            for (i = 0; i < big_num + 1; i++) {
1598                local_small_max = small_max;
1599
1600                big_w = this.toFixed(big_p * i);
1601                if (big_w > 100) {
1602                    big_w = 100;
1603
1604                    local_small_max -= 2;
1605                    if (local_small_max < 0) {
1606                        local_small_max = 0;
1607                    }
1608                }
1609                this.coords.big[i] = big_w;
1610
1611                small_p = (big_w - (big_p * (i - 1))) / (local_small_max + 1);
1612
1613                for (z = 1; z <= local_small_max; z++) {
1614                    if (big_w === 0) {
1615                        break;
1616                    }
1617
1618                    small_w = this.toFixed(big_w - (small_p * z));
1619
1620                    html += '<span class="irs-grid-pol small" style="left: ' + small_w + '%"></span>';
1621                }
1622
1623                html += '<span class="irs-grid-pol" style="left: ' + big_w + '%"></span>';
1624
1625                result = this.calcReal(big_w);
1626                if (o.values.length) {
1627                    result = o.p_values[result];
1628                } else {
1629                    result = this._prettify(result);
1630                }
1631
1632                html += '<span class="irs-grid-text js-grid-text-' + i + '" style="left: ' + big_w + '%">' + result + '</span>';
1633            }
1634            this.coords.big_num = Math.ceil(big_num + 1);
1635
1636
1637
1638            this.$cache.cont.addClass("irs-with-grid");
1639            this.$cache.grid.html(html);
1640            this.cacheGridLabels();
1641        },
1642
1643        cacheGridLabels: function () {
1644            var $label, i,
1645                num = this.coords.big_num;
1646
1647            for (i = 0; i < num; i++) {
1648                $label = this.$cache.grid.find(".js-grid-text-" + i);
1649                this.$cache.grid_labels.push($label);
1650            }
1651
1652            this.calcGridLabels();
1653        },
1654
1655        calcGridLabels: function () {
1656            var i, label, start = [], finish = [],
1657                num = this.coords.big_num;
1658
1659            for (i = 0; i < num; i++) {
1660                this.coords.big_w[i] = this.$cache.grid_labels[i].outerWidth(false);
1661                this.coords.big_p[i] = this.toFixed(this.coords.big_w[i] / this.coords.w_rs * 100);
1662                this.coords.big_x[i] = this.toFixed(this.coords.big_p[i] / 2);
1663
1664                start[i] = this.toFixed(this.coords.big[i] - this.coords.big_x[i]);
1665                finish[i] = this.toFixed(start[i] + this.coords.big_p[i]);
1666            }
1667
1668            if (this.options.force_edges) {
1669                if (start[0] < this.coords.grid_gap) {
1670                    start[0] = this.coords.grid_gap;
1671                    finish[0] = this.toFixed(start[0] + this.coords.big_p[0]);
1672
1673                    this.coords.big_x[0] = this.coords.grid_gap;
1674                }
1675
1676                if (finish[num - 1] > 100 - this.coords.grid_gap) {
1677                    finish[num - 1] = 100 - this.coords.grid_gap;
1678                    start[num - 1] = this.toFixed(finish[num - 1] - this.coords.big_p[num - 1]);
1679
1680                    this.coords.big_x[num - 1] = this.toFixed(this.coords.big_p[num - 1] - this.coords.grid_gap);
1681                }
1682            }
1683
1684            this.calcGridCollision(2, start, finish);
1685            this.calcGridCollision(4, start, finish);
1686
1687            for (i = 0; i < num; i++) {
1688                label = this.$cache.grid_labels[i][0];
1689                label.style.marginLeft = -this.coords.big_x[i] + "%";
1690            }
1691        },
1692
1693        // Collisions Calc Beta
1694        // TODO: Refactor then have plenty of time
1695        calcGridCollision: function (step, start, finish) {
1696            var i, next_i, label,
1697                num = this.coords.big_num;
1698
1699            for (i = 0; i < num; i += step) {
1700                next_i = i + (step / 2);
1701                if (next_i >= num) {
1702                    break;
1703                }
1704
1705                label = this.$cache.grid_labels[next_i][0];
1706
1707                if (finish[i] <= start[next_i]) {
1708                    label.style.visibility = "visible";
1709                } else {
1710                    label.style.visibility = "hidden";
1711                }
1712            }
1713        },
1714
1715        calcGridMargin: function () {
1716            if (!this.options.grid_margin) {
1717                return;
1718            }
1719
1720            this.coords.w_rs = this.$cache.rs.outerWidth(false);
1721            if (!this.coords.w_rs) {
1722                return;
1723            }
1724
1725            if (this.options.type === "single") {
1726                this.coords.w_handle = this.$cache.s_single.outerWidth(false);
1727            } else {
1728                this.coords.w_handle = this.$cache.s_from.outerWidth(false);
1729            }
1730            this.coords.p_handle = this.toFixed(this.coords.w_handle  / this.coords.w_rs * 100);
1731            this.coords.grid_gap = this.toFixed((this.coords.p_handle / 2) - 0.1);
1732
1733            this.$cache.grid[0].style.width = this.toFixed(100 - this.coords.p_handle) + "%";
1734            this.$cache.grid[0].style.left = this.coords.grid_gap + "%";
1735        },
1736
1737
1738
1739        // =============================================================================================================
1740        // Public methods
1741
1742        update: function (options) {
1743            this.is_update = true;
1744            this.options = $.extend(this.options, options);
1745            this.validate();
1746            this.updateResult(options);
1747
1748            this.toggleInput();
1749            this.remove();
1750            this.init(true);
1751        },
1752
1753        reset: function () {
1754            this.updateResult();
1755            this.update();
1756        },
1757
1758        destroy: function () {
1759            this.toggleInput();
1760            this.$cache.input.prop("readonly", false);
1761            $.data(this.input, "ionRangeSlider", null);
1762
1763            this.remove();
1764            this.input = null;
1765            this.options = null;
1766        }
1767    };
1768
1769    $.fn.ionRangeSlider = function (options) {
1770        return this.each(function() {
1771            if (!$.data(this, "ionRangeSlider")) {
1772                $.data(this, "ionRangeSlider", new IonRangeSlider(this, options, plugin_count++));
1773            }
1774        });
1775    };
1776
1777
1778
1779    // =================================================================================================================
1780    // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
1781    // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
1782
1783    // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
1784
1785    // MIT license
1786
1787    (function() {
1788        var lastTime = 0;
1789        var vendors = ['ms', 'moz', 'webkit', 'o'];
1790        for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
1791            window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
1792            window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
1793                || window[vendors[x]+'CancelRequestAnimationFrame'];
1794        }
1795
1796        if (!window.requestAnimationFrame)
1797            window.requestAnimationFrame = function(callback, element) {
1798                var currTime = new Date().getTime();
1799                var timeToCall = Math.max(0, 16 - (currTime - lastTime));
1800                var id = window.setTimeout(function() { callback(currTime + timeToCall); },
1801                    timeToCall);
1802                lastTime = currTime + timeToCall;
1803                return id;
1804            };
1805
1806        if (!window.cancelAnimationFrame)
1807            window.cancelAnimationFrame = function(id) {
1808                clearTimeout(id);
1809            };
1810    }());
1811
1812} (jQuery, document, window, navigator));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.