PageSourceSearch

https://www.pollithere.com/js/rzslider.js

js pollithere.com collected 2026-10-09 03:54:15 UTC 116,026 bytes, 2,663 lines download raw bytes

vendor: 116,026 bytes, lines 1-2663
1/*! angularjs-slider - v6.5.0 -
2 (c) Rafal Zajac <[email protected]>, Valentin Hervieu <[email protected]>, Jussi Saarivirta <[email protected]>, Angelin Sirbu <[email protected]> -
3 https://github.com/angular-slider/angularjs-slider -
4 2018-02-07 */
5/*jslint unparam: true */
6/*global angular: false, console: false, define, module */
7;(function(root, factory) {
8    'use strict'
9    /* istanbul ignore next */
10    if (typeof define === 'function' && define.amd) {
11        // AMD. Register as an anonymous module.
12        define(['angular'], factory)
13    } else if (typeof module === 'object' && module.exports) {
14        // Node. Does not work with strict CommonJS, but
15        // only CommonJS-like environments that support module.exports,
16        // like Node.
17        // to support bundler like browserify
18        var angularObj = angular || require('angular')
19        if ((!angularObj || !angularObj.module) && typeof angular != 'undefined') {
20            angularObj = angular
21        }
22        module.exports = factory(angularObj)
23    } else {
24        // Browser globals (root is window)
25        factory(root.angular)
26    }
27})(this, function(angular) {
28    'use strict'
29    var module = angular
30        .module('rzModule', [])
31        .factory('RzSliderOptions', function() {
32            var defaultOptions = {
33                floor: 0,
34                ceil: null, //defaults to rz-slider-model
35                step: 1,
36                precision: 0,
37                minRange: null,
38                maxRange: null,
39                pushRange: false,
40                minLimit: null,
41                maxLimit: null,
42                id: null,
43                translate: null,
44                getLegend: null,
45                stepsArray: null,
46                bindIndexForStepsArray: false,
47                draggableRange: false,
48                draggableRangeOnly: false,
49                showSelectionBar: false,
50                showSelectionBarEnd: false,
51                showSelectionBarFromValue: null,
52                showOuterSelectionBars: false,
53                hidePointerLabels: false,
54                hideLimitLabels: false,
55                autoHideLimitLabels: true,
56                readOnly: false,
57                disabled: false,
58                interval: 350,
59                showTicks: false,
60                showTicksValues: false,
61                ticksArray: null,
62                ticksTooltip: null,
63                ticksValuesTooltip: null,
64                vertical: false,
65                getSelectionBarColor: null,
66                getTickColor: null,
67                getPointerColor: null,
68                keyboardSupport: true,
69                scale: 1,
70                enforceStep: true,
71                enforceRange: false,
72                noSwitching: false,
73                onlyBindHandles: false,
74                onStart: null,
75                onChange: null,
76                onEnd: null,
77                rightToLeft: false,
78                reversedControls: false,
79                boundPointerLabels: true,
80                mergeRangeLabelsIfSame: false,
81                labelOverlapSeparator: ' - ',
82                customTemplateScope: null,
83                logScale: false,
84                customValueToPosition: null,
85                customPositionToValue: null,
86                selectionBarGradient: null,
87                ariaLabel: null,
88                ariaLabelledBy: null,
89                ariaLabelHigh: null,
90                ariaLabelledByHigh: null,
91            }
92            var globalOptions = {}
93
94            var factory = {}
95            /**
96             * `options({})` allows global configuration of all sliders in the
97             * application.
98             *
99             *   var app = angular.module( 'App', ['rzModule'], function( RzSliderOptions ) {
100       *     // show ticks for all sliders
101       *     RzSliderOptions.options( { showTicks: true } );
102       *   });
103             */
104            factory.options = function(value) {
105                angular.extend(globalOptions, value)
106            }
107
108            factory.getOptions = function(options) {
109                return angular.extend({}, defaultOptions, globalOptions, options)
110            }
111
112            return factory
113        })
114        .factory('rzThrottle', ['$timeout', function($timeout) {
115            /**
116             * rzThrottle
117             *
118             * Taken from underscore project
119             *
120             * @param {Function} func
121             * @param {number} wait
122             * @param {ThrottleOptions} options
123             * @returns {Function}
124             */
125            return function(func, wait, options) {
126                'use strict'
127                /* istanbul ignore next */
128                var getTime =
129                    Date.now ||
130                    function() {
131                        return new Date().getTime()
132                    }
133                var context, args, result
134                var timeout = null
135                var previous = 0
136                options = options || {}
137                var later = function() {
138                    previous = getTime()
139                    timeout = null
140                    result = func.apply(context, args)
141                    context = args = null
142                }
143                return function() {
144                    var now = getTime()
145                    var remaining = wait - (now - previous)
146                    context = this
147                    args = arguments
148                    if (remaining <= 0) {
149                        $timeout.cancel(timeout)
150                        timeout = null
151                        previous = now
152                        result = func.apply(context, args)
153                        context = args = null
154                    } else if (!timeout && options.trailing !== false) {
155                        timeout = $timeout(later, remaining)
156                    }
157                    return result
158                }
159            }
160        }])
161        .factory('RzSlider', ['$timeout', '$document', '$window', '$compile', 'RzSliderOptions', 'rzThrottle', function(
162            $timeout,
163            $document,
164            $window,
165            $compile,
166            RzSliderOptions,
167            rzThrottle
168        ) {
169            'use strict'
170
171            /**
172             * Slider
173             *
174             * @param {ngScope} scope            The AngularJS scope
175             * @param {Element} sliderElem The slider directive element wrapped in jqLite
176             * @constructor
177             */
178            var Slider = function(scope, sliderElem) {
179                /**
180                 * The slider's scope
181                 *
182                 * @type {ngScope}
183                 */
184                this.scope = scope
185
186                /**
187                 * The slider inner low value (linked to rzSliderModel)
188                 * @type {number}
189                 */
190                this.lowValue = 0
191
192                /**
193                 * The slider inner high value (linked to rzSliderHigh)
194                 * @type {number}
195                 */
196                this.highValue = 0
197
198                /**
199                 * Slider element wrapped in jqLite
200                 *
201                 * @type {jqLite}
202                 */
203                this.sliderElem = sliderElem
204
205                /**
206                 * Slider type
207                 *
208                 * @type {boolean} Set to true for range slider
209                 */
210                this.range =
211                    this.scope.rzSliderModel !== undefined &&
212                    this.scope.rzSliderHigh !== undefined
213
214                /**
215                 * Values recorded when first dragging the bar
216                 *
217                 * @type {Object}
218                 */
219                this.dragging = {
220                    active: false,
221                    value: 0,
222                    difference: 0,
223                    position: 0,
224                    lowLimit: 0,
225                    highLimit: 0,
226                }
227
228                /**
229                 * property that handle position (defaults to left for horizontal)
230                 * @type {string}
231                 */
232                this.positionProperty = 'left'
233
234                /**
235                 * property that handle dimension (defaults to width for horizontal)
236                 * @type {string}
237                 */
238                this.dimensionProperty = 'width'
239
240                /**
241                 * Half of the width or height of the slider handles
242                 *
243                 * @type {number}
244                 */
245                this.handleHalfDim = 0
246
247                /**
248                 * Maximum position the slider handle can have
249                 *
250                 * @type {number}
251                 */
252                this.maxPos = 0
253
254                /**
255                 * Precision
256                 *
257                 * @type {number}
258                 */
259                this.precision = 0
260
261                /**
262                 * Step
263                 *
264                 * @type {number}
265                 */
266                this.step = 1
267
268                /**
269                 * The name of the handle we are currently tracking
270                 *
271                 * @type {string}
272                 */
273                this.tracking = ''
274
275                /**
276                 * Minimum value (floor) of the model
277                 *
278                 * @type {number}
279                 */
280                this.minValue = 0
281
282                /**
283                 * Maximum value (ceiling) of the model
284                 *
285                 * @type {number}
286                 */
287                this.maxValue = 0
288
289                /**
290                 * The delta between min and max value
291                 *
292                 * @type {number}
293                 */
294                this.valueRange = 0
295
296                /**
297                 * If showTicks/showTicksValues options are number.
298                 * In this case, ticks values should be displayed below the slider.
299                 * @type {boolean}
300                 */
301                this.intermediateTicks = false
302
303                /**
304                 * Set to true if init method already executed
305                 *
306                 * @type {boolean}
307                 */
308                this.initHasRun = false
309
310                /**
311                 * Used to call onStart on the first keydown event
312                 *
313                 * @type {boolean}
314                 */
315                this.firstKeyDown = false
316
317                /**
318                 * Internal flag to prevent watchers to be called when the sliders value are modified internally.
319                 * @type {boolean}
320                 */
321                this.internalChange = false
322
323                /**
324                 * Internal flag to keep track of the visibility of combo label
325                 * @type {boolean}
326                 */
327                this.cmbLabelShown = false
328
329                /**
330                 * Internal variable to keep track of the focus element
331                 */
332                this.currentFocusElement = null
333
334                // Slider DOM elements wrapped in jqLite
335                this.fullBar = null // The whole slider bar
336                this.selBar = null // Highlight between two handles
337                this.minH = null // Left slider handle
338                this.maxH = null // Right slider handle
339                this.flrLab = null // Floor label
340                this.ceilLab = null // Ceiling label
341                this.minLab = null // Label above the low value
342                this.maxLab = null // Label above the high value
343                this.cmbLab = null // Combined label
344                this.ticks = null // The ticks
345
346                // Initialize slider
347                this.init()
348            }
349
350            // Add instance methods
351            Slider.prototype = {
352                /**
353                 * Initialize slider
354                 *
355                 * @returns {undefined}
356                 */
357                init: function() {
358                    var thrLow,
359                        thrHigh,
360                        self = this
361
362                    var calcDimFn = function() {
363                        self.calcViewDimensions()
364                    }
365
366                    this.applyOptions()
367                    this.syncLowValue()
368                    if (this.range) this.syncHighValue()
369                    this.initElemHandles()
370                    this.manageElementsStyle()
371                    this.setDisabledState()
372                    this.calcViewDimensions()
373                    this.setMinAndMax()
374                    this.addAccessibility()
375                    this.updateCeilLab()
376                    this.updateFloorLab()
377                    this.initHandles()
378                    this.manageEventsBindings()
379
380                    // Recalculate slider view dimensions
381                    this.scope.$on('reCalcViewDimensions', calcDimFn)
382
383                    // Recalculate stuff if view port dimensions have changed
384                    angular.element($window).on('resize', calcDimFn)
385
386                    this.initHasRun = true
387
388                    // Watch for changes to the model
389                    thrLow = rzThrottle(function() {
390                        self.onLowHandleChange()
391                    }, self.options.interval)
392
393                    thrHigh = rzThrottle(function() {
394                        self.onHighHandleChange()
395                    }, self.options.interval)
396
397                    this.scope.$on('rzSliderForceRender', function() {
398                        self.resetLabelsValue()
399                        thrLow()
400                        if (self.range) {
401                            thrHigh()
402                        }
403                        self.resetSlider()
404                    })
405
406                    // Watchers (order is important because in case of simultaneous change,
407                    // watchers will be called in the same order)
408                    this.scope.$watchCollection('rzSliderOptions()', function(
409                        newValue,
410                        oldValue
411                    ) {
412                        if (newValue === oldValue) return
413                        self.applyOptions() // need to be called before synchronizing the values
414                        self.syncLowValue()
415                        if (self.range) self.syncHighValue()
416                        self.resetSlider()
417                    })
418
419                    this.scope.$watch('rzSliderModel', function(newValue, oldValue) {
420                        if (self.internalChange) return
421                        if (newValue === oldValue) return
422                        thrLow()
423                    })
424
425                    this.scope.$watch('rzSliderHigh', function(newValue, oldValue) {
426                        if (self.internalChange) return
427                        if (newValue === oldValue) return
428                        if (newValue != null) thrHigh()
429                        if (
430                            (self.range && newValue == null) ||
431                            (!self.range && newValue != null)
432                        ) {
433                            self.applyOptions()
434                            self.resetSlider()
435                        }
436                    })
437
438                    this.scope.$on('$destroy', function() {
439                        self.unbindEvents()
440                        angular.element($window).off('resize', calcDimFn)
441                        self.currentFocusElement = null
442                    })
443                },
444
445                findStepIndex: function(modelValue) {
446                    var index = 0
447                    for (var i = 0; i < this.options.stepsArray.length; i++) {
448                        var step = this.options.stepsArray[i]
449                        if (step === modelValue) {
450                            index = i
451                            break
452                        } else if (angular.isDate(step)) {
453                            if (step.getTime() === modelValue.getTime()) {
454                                index = i
455                                break
456                            }
457                        } else if (angular.isObject(step)) {
458                            if (
459                                (angular.isDate(step.value) &&
460                                    step.value.getTime() === modelValue.getTime()) ||
461                                step.value === modelValue
462                            ) {
463                                index = i
464                                break
465                            }
466                        }
467                    }
468                    return index
469                },
470
471                syncLowValue: function() {
472                    if (this.options.stepsArray) {
473                        if (!this.options.bindIndexForStepsArray)
474                            this.lowValue = this.findStepIndex(this.scope.rzSliderModel)
475                        else this.lowValue = this.scope.rzSliderModel
476                    } else this.lowValue = this.scope.rzSliderModel
477                },
478
479                syncHighValue: function() {
480                    if (this.options.stepsArray) {
481                        if (!this.options.bindIndexForStepsArray)
482                            this.highValue = this.findStepIndex(this.scope.rzSliderHigh)
483                        else this.highValue = this.scope.rzSliderHigh
484                    } else this.highValue = this.scope.rzSliderHigh
485                },
486
487                getStepValue: function(sliderValue) {
488                    var step = this.options.stepsArray[sliderValue]
489                    if (angular.isDate(step)) return step
490                    if (angular.isObject(step)) return step.value
491                    return step
492                },
493
494                applyLowValue: function() {
495                    if (this.options.stepsArray) {
496                        if (!this.options.bindIndexForStepsArray)
497                            this.scope.rzSliderModel = this.getStepValue(this.lowValue)
498                        else this.scope.rzSliderModel = this.lowValue
499                    } else this.scope.rzSliderModel = this.lowValue
500                },
501
502                applyHighValue: function() {
503                    if (this.options.stepsArray) {
504                        if (!this.options.bindIndexForStepsArray)
505                            this.scope.rzSliderHigh = this.getStepValue(this.highValue)
506                        else this.scope.rzSliderHigh = this.highValue
507                    } else this.scope.rzSliderHigh = this.highValue
508                },
509
510                /*
511               * Reflow the slider when the low handle changes (called with throttle)
512               */
513                onLowHandleChange: function() {
514                    this.syncLowValue()
515                    if (this.range) this.syncHighValue()
516                    this.setMinAndMax()
517                    this.updateLowHandle(this.valueToPosition(this.lowValue))
518                    this.updateSelectionBar()
519                    this.updateTicksScale()
520                    this.updateAriaAttributes()
521                    if (this.range) {
522                        this.updateCmbLabel()
523                    }
524                },
525
526                /*
527               * Reflow the slider when the high handle changes (called with throttle)
528               */
529                onHighHandleChange: function() {
530                    this.syncLowValue()
531                    this.syncHighValue()
532                    this.setMinAndMax()
533                    this.updateHighHandle(this.valueToPosition(this.highValue))
534                    this.updateSelectionBar()
535                    this.updateTicksScale()
536                    this.updateCmbLabel()
537                    this.updateAriaAttributes()
538                },
539
540                /**
541                 * Read the user options and apply them to the slider model
542                 */
543                applyOptions: function() {
544                    var sliderOptions
545                    if (this.scope.rzSliderOptions)
546                        sliderOptions = this.scope.rzSliderOptions()
547                    else sliderOptions = {}
548
549                    this.options = RzSliderOptions.getOptions(sliderOptions)
550
551                    if (this.options.step <= 0) this.options.step = 1
552
553                    this.range =
554                        this.scope.rzSliderModel !== undefined &&
555                        this.scope.rzSliderHigh !== undefined
556                    this.options.draggableRange =
557                        this.range && this.options.draggableRange
558                    this.options.draggableRangeOnly =
559                        this.range && this.options.draggableRangeOnly
560                    if (this.options.draggableRangeOnly) {
561                        this.options.draggableRange = true
562                    }
563
564                    this.options.showTicks =
565                        this.options.showTicks ||
566                        this.options.showTicksValues ||
567                        !!this.options.ticksArray
568                    this.scope.showTicks = this.options.showTicks //scope is used in the template
569                    if (
570                        angular.isNumber(this.options.showTicks) ||
571                        this.options.ticksArray
572                    )
573                        this.intermediateTicks = true
574
575                    this.options.showSelectionBar =
576                        this.options.showSelectionBar ||
577                        this.options.showSelectionBarEnd ||
578                        this.options.showSelectionBarFromValue !== null
579
580                    if (this.options.stepsArray) {
581                        this.parseStepsArray()
582                    } else {
583                        if (this.options.translate) this.customTrFn = this.options.translate
584                        else
585                            this.customTrFn = function(value) {
586                                return String(value)
587                            }
588
589                        this.getLegend = this.options.getLegend
590                    }
591
592                    if (this.options.vertical) {
593                        this.positionProperty = 'bottom'
594                        this.dimensionProperty = 'height'
595                    }
596
597                    if (this.options.customTemplateScope)
598                        this.scope.custom = this.options.customTemplateScope
599                },
600
601                parseStepsArray: function() {
602                    this.options.floor = 0
603                    this.options.ceil = this.options.stepsArray.length - 1
604                    this.options.step = 1
605
606                    if (this.options.translate) {
607                        this.customTrFn = this.options.translate
608                    } else {
609                        this.customTrFn = function(modelValue) {
610                            if (this.options.bindIndexForStepsArray)
611                                return this.getStepValue(modelValue)
612                            return modelValue
613                        }
614                    }
615
616                    this.getLegend = function(index) {
617                        var step = this.options.stepsArray[index]
618                        if (angular.isObject(step)) return step.legend
619                        return null
620                    }
621                },
622
623                /**
624                 * Resets slider
625                 *
626                 * @returns {undefined}
627                 */
628                resetSlider: function() {
629                    this.manageElementsStyle()
630                    this.addAccessibility()
631                    this.setMinAndMax()
632                    this.updateCeilLab()
633                    this.updateFloorLab()
634                    this.unbindEvents()
635                    this.manageEventsBindings()
636                    this.setDisabledState()
637                    this.calcViewDimensions()
638                    this.refocusPointerIfNeeded()
639                },
640
641                refocusPointerIfNeeded: function() {
642                    if (this.currentFocusElement) {
643                        this.onPointerFocus(
644                            this.currentFocusElement.pointer,
645                            this.currentFocusElement.ref
646                        )
647                        this.focusElement(this.currentFocusElement.pointer)
648                    }
649                },
650
651                /**
652                 * Set the slider children to variables for easy access
653                 *
654                 * Run only once during initialization
655                 *
656                 * @returns {undefined}
657                 */
658                initElemHandles: function() {
659                    // Assign all slider elements to object properties for easy access
660                    angular.forEach(
661                        this.sliderElem.children(),
662                        function(elem, index) {
663                            var jElem = angular.element(elem)
664
665                            switch (index) {
666                                case 0:
667                                    this.leftOutSelBar = jElem
668                                    break
669                                case 1:
670                                    this.rightOutSelBar = jElem
671                                    break
672                                case 2:
673                                    this.fullBar = jElem
674                                    break
675                                case 3:
676                                    this.selBar = jElem
677                                    break
678                                case 4:
679                                    this.minH = jElem
680                                    break
681                                case 5:
682                                    this.maxH = jElem
683                                    break
684                                case 6:
685                                    this.flrLab = jElem
686                                    break
687                                case 7:
688                                    this.ceilLab = jElem
689                                    break
690                                case 8:
691                                    this.minLab = jElem
692                                    break
693                                case 9:
694                                    this.maxLab = jElem
695                                    break
696                                case 10:
697                                    this.cmbLab = jElem
698                                    break
699                                case 11:
700                                    this.ticks = jElem
701                                    break
702                            }
703                        },
704                        this
705                    )
706
707                    // Initialize position cache properties
708                    this.selBar.rzsp = 0
709                    this.minH.rzsp = 0
710                    this.maxH.rzsp = 0
711                    this.flrLab.rzsp = 0
712                    this.ceilLab.rzsp = 0
713                    this.minLab.rzsp = 0
714                    this.maxLab.rzsp = 0
715                    this.cmbLab.rzsp = 0
716                },
717
718                /**
719                 * Update each elements style based on options
720                 */
721                manageElementsStyle: function() {
722                    if (!this.range) this.maxH.css('display', 'none')
723                    else this.maxH.css('display', '')
724
725                    this.alwaysHide(
726                        this.flrLab,
727                        this.options.showTicksValues || this.options.hideLimitLabels
728                    )
729                    this.alwaysHide(
730                        this.ceilLab,
731                        this.options.showTicksValues || this.options.hideLimitLabels
732                    )
733
734                    var hideLabelsForTicks =
735                        this.options.showTicksValues && !this.intermediateTicks
736                    this.alwaysHide(
737                        this.minLab,
738                        hideLabelsForTicks || this.options.hidePointerLabels
739                    )
740                    this.alwaysHide(
741                        this.maxLab,
742                        hideLabelsForTicks || !this.range || this.options.hidePointerLabels
743                    )
744                    this.alwaysHide(
745                        this.cmbLab,
746                        hideLabelsForTicks || !this.range || this.options.hidePointerLabels
747                    )
748                    this.alwaysHide(
749                        this.selBar,
750                        !this.range && !this.options.showSelectionBar
751                    )
752                    this.alwaysHide(
753                        this.leftOutSelBar,
754                        !this.range || !this.options.showOuterSelectionBars
755                    )
756                    this.alwaysHide(
757                        this.rightOutSelBar,
758                        !this.range || !this.options.showOuterSelectionBars
759                    )
760
761                    if (this.range && this.options.showOuterSelectionBars) {
762                        this.fullBar.addClass('rz-transparent')
763                    }
764
765                    if (this.options.vertical) this.sliderElem.addClass('rz-vertical')
766
767                    if (this.options.draggableRange) this.selBar.addClass('rz-draggable')
768                    else this.selBar.removeClass('rz-draggable')
769
770                    if (this.intermediateTicks && this.options.showTicksValues)
771                        this.ticks.addClass('rz-ticks-values-under')
772                },
773
774                alwaysHide: function(el, hide) {
775                    el.rzAlwaysHide = hide
776                    if (hide) this.hideEl(el)
777                    else this.showEl(el)
778                },
779
780                /**
781                 * Manage the events bindings based on readOnly and disabled options
782                 *
783                 * @returns {undefined}
784                 */
785                manageEventsBindings: function() {
786                    if (this.options.disabled || this.options.readOnly)
787                        this.unbindEvents()
788                    else this.bindEvents()
789                },
790
791                /**
792                 * Set the disabled state based on rzSliderDisabled
793                 *
794                 * @returns {undefined}
795                 */
796                setDisabledState: function() {
797                    if (this.options.disabled) {
798                        this.sliderElem.attr('disabled', 'disabled')
799                    } else {
800                        this.sliderElem.attr('disabled', null)
801                    }
802                },
803
804                /**
805                 * Reset label values
806                 *
807                 * @return {undefined}
808                 */
809                resetLabelsValue: function() {
810                    this.minLab.rzsv = undefined
811                    this.maxLab.rzsv = undefined
812                },
813
814                /**
815                 * Initialize slider handles positions and labels
816                 *
817                 * Run only once during initialization and every time view port changes size
818                 *
819                 * @returns {undefined}
820                 */
821                initHandles: function() {
822                    this.updateLowHandle(this.valueToPosition(this.lowValue))
823
824                    /*
825                   the order here is important since the selection bar should be
826                   updated after the high handle but before the combined label
827                   */
828                    if (this.range)
829                        this.updateHighHandle(this.valueToPosition(this.highValue))
830                    this.updateSelectionBar()
831                    if (this.range) this.updateCmbLabel()
832
833                    this.updateTicksScale()
834                },
835
836                /**
837                 * Translate value to human readable format
838                 *
839                 * @param {number|string} value
840                 * @param {jqLite} label
841                 * @param {String} which
842                 * @param {boolean} [useCustomTr]
843                 * @returns {undefined}
844                 */
845                translateFn: function(value, label, which, useCustomTr) {
846                    useCustomTr = useCustomTr === undefined ? true : useCustomTr
847
848                    var valStr = '',
849                        getDimension = false,
850                        noLabelInjection = label.hasClass('no-label-injection')
851
852                    if (useCustomTr) {
853                        if (this.options.stepsArray && !this.options.bindIndexForStepsArray)
854                            value = this.getStepValue(value)
855                        valStr = String(this.customTrFn(value, this.options.id, which))
856                    } else {
857                        valStr = String(value)
858                    }
859
860                    if (
861                        label.rzsv === undefined ||
862                        label.rzsv.length !== valStr.length ||
863                        (label.rzsv.length > 0 && label.rzsd === 0)
864                    ) {
865                        getDimension = true
866                        label.rzsv = valStr
867                    }
868
869                    if (!noLabelInjection) {
870                        label.html(valStr)
871                    }
872                    this.scope[which + 'Label'] = valStr
873
874                    // Update width only when length of the label have changed
875                    if (getDimension) {
876                        this.getDimension(label)
877                    }
878                },
879
880                /**
881                 * Set maximum and minimum values for the slider and ensure the model and high
882                 * value match these limits
883                 * @returns {undefined}
884                 */
885                setMinAndMax: function() {
886                    this.step = +this.options.step
887                    this.precision = +this.options.precision
888
889                    this.minValue = this.options.floor
890                    if (this.options.logScale && this.minValue === 0)
891                        throw Error("Can't use floor=0 with logarithmic scale")
892
893                    if (this.options.enforceStep) {
894                        this.lowValue = this.roundStep(this.lowValue)
895                        if (this.range) this.highValue = this.roundStep(this.highValue)
896                    }
897
898                    if (this.options.ceil != null) this.maxValue = this.options.ceil
899                    else
900                        this.maxValue = this.options.ceil = this.range
901                            ? this.highValue
902                            : this.lowValue
903
904                    if (this.options.enforceRange) {
905                        this.lowValue = this.sanitizeValue(this.lowValue)
906                        if (this.range) this.highValue = this.sanitizeValue(this.highValue)
907                    }
908
909                    this.applyLowValue()
910                    if (this.range) this.applyHighValue()
911
912                    this.valueRange = this.maxValue - this.minValue
913                },
914
915                /**
916                 * Adds accessibility attributes
917                 *
918                 * Run only once during initialization
919                 *
920                 * @returns {undefined}
921                 */
922                addAccessibility: function() {
923                    this.minH.attr('role', 'slider')
924                    this.updateAriaAttributes()
925                    if (
926                        this.options.keyboardSupport &&
927                        !(this.options.readOnly || this.options.disabled)
928                    )
929                        this.minH.attr('tabindex', '0')
930                    else this.minH.attr('tabindex', '')
931                    if (this.options.vertical)
932                        this.minH.attr('aria-orientation', 'vertical')
933                    if (this.options.ariaLabel)
934                        this.minH.attr('aria-label', this.options.ariaLabel)
935                    else if (this.options.ariaLabelledBy)
936                        this.minH.attr('aria-labelledby', this.options.ariaLabelledBy)
937
938                    if (this.range) {
939                        this.maxH.attr('role', 'slider')
940                        if (
941                            this.options.keyboardSupport &&
942                            !(this.options.readOnly || this.options.disabled)
943                        )
944                            this.maxH.attr('tabindex', '0')
945                        else this.maxH.attr('tabindex', '')
946                        if (this.options.vertical)
947                            this.maxH.attr('aria-orientation', 'vertical')
948                        if (this.options.ariaLabelHigh)
949                            this.maxH.attr('aria-label', this.options.ariaLabelHigh)
950                        else if (this.options.ariaLabelledByHigh)
951                            this.maxH.attr('aria-labelledby', this.options.ariaLabelledByHigh)
952                    }
953                },
954
955                /**
956                 * Updates aria attributes according to current values
957                 */
958                updateAriaAttributes: function() {
959                    this.minH.attr({
960                        'aria-valuenow': this.scope.rzSliderModel,
961                        'aria-valuetext': this.customTrFn(
962                            this.scope.rzSliderModel,
963                            this.options.id,
964                            'model'
965                        ),
966                        'aria-valuemin': this.minValue,
967                        'aria-valuemax': this.maxValue,
968                    })
969                    if (this.range) {
970                        this.maxH.attr({
971                            'aria-valuenow': this.scope.rzSliderHigh,
972                            'aria-valuetext': this.customTrFn(
973                                this.scope.rzSliderHigh,
974                                this.options.id,
975                                'high'
976                            ),
977                            'aria-valuemin': this.minValue,
978                            'aria-valuemax': this.maxValue,
979                        })
980                    }
981                },
982
983                /**
984                 * Calculate dimensions that are dependent on view port size
985                 *
986                 * Run once during initialization and every time view port changes size.
987                 *
988                 * @returns {undefined}
989                 */
990                calcViewDimensions: function() {
991                    var handleWidth = this.getDimension(this.minH)
992
993                    this.handleHalfDim = handleWidth / 2
994                    this.barDimension = this.getDimension(this.fullBar)
995
996                    this.maxPos = this.barDimension - handleWidth
997
998                    this.getDimension(this.sliderElem)
999                    this.sliderElem.rzsp = this.sliderElem[0].getBoundingClientRect()[
1000                        this.positionProperty
1001                        ]
1002
1003                    if (this.initHasRun) {
1004                        this.updateFloorLab()
1005                        this.updateCeilLab()
1006                        this.initHandles()
1007                        var self = this
1008                        $timeout(function() {
1009                            self.updateTicksScale()
1010                        })
1011                    }
1012                },
1013
1014                /**
1015                 * Update the ticks position
1016                 *
1017                 * @returns {undefined}
1018                 */
1019                updateTicksScale: function() {
1020                    if (!this.options.showTicks) return
1021
1022                    var ticksArray = this.options.ticksArray || this.getTicksArray(),
1023                        translate = this.options.vertical ? 'translateY' : 'translateX',
1024                        self = this
1025
1026                    if (this.options.rightToLeft) ticksArray.reverse()
1027
1028                    this.scope.ticks = ticksArray.map(function(value) {
1029                        var position = self.valueToPosition(value)
1030
1031                        if (self.options.vertical) position = self.maxPos - position
1032
1033                        var translation = translate + '(' + Math.round(position) + 'px)'
1034                        var tick = {
1035                            selected: self.isTickSelected(value),
1036                            style: {
1037                                '-webkit-transform': translation,
1038                                '-moz-transform': translation,
1039                                '-o-transform': translation,
1040                                '-ms-transform': translation,
1041                                transform: translation,
1042                            },
1043                        }
1044                        if (tick.selected && self.options.getSelectionBarColor) {
1045                            tick.style['background-color'] = self.getSelectionBarColor()
1046                        }
1047                        if (!tick.selected && self.options.getTickColor) {
1048                            tick.style['background-color'] = self.getTickColor(value)
1049                        }
1050                        if (self.options.ticksTooltip) {
1051                            tick.tooltip = self.options.ticksTooltip(value)
1052                            tick.tooltipPlacement = self.options.vertical ? 'right' : 'top'
1053                        }
1054                        if (
1055                            self.options.showTicksValues === true ||
1056                            value % self.options.showTicksValues === 0
1057                        ) {
1058                            tick.value = self.getDisplayValue(value, 'tick-value')
1059                            if (self.options.ticksValuesTooltip) {
1060                                tick.valueTooltip = self.options.ticksValuesTooltip(value)
1061                                tick.valueTooltipPlacement = self.options.vertical
1062                                    ? 'right'
1063                                    : 'top'
1064                            }
1065                        }
1066                        if (self.getLegend) {
1067                            var legend = self.getLegend(value, self.options.id)
1068                            if (legend) tick.legend = legend
1069                        }
1070                        return tick
1071                    })
1072                },
1073
1074                getTicksArray: function() {
1075                    var step = this.step,
1076                        ticksArray = []
1077                    if (this.intermediateTicks) step = this.options.showTicks
1078                    for (
1079                        var value = this.minValue;
1080                        value <= this.maxValue;
1081                        value += step
1082                    ) {
1083                        ticksArray.push(value)
1084                    }
1085                    return ticksArray
1086                },
1087
1088                isTickSelected: function(value) {
1089                    if (!this.range) {
1090                        if (this.options.showSelectionBarFromValue !== null) {
1091                            var center = this.options.showSelectionBarFromValue
1092                            if (
1093                                this.lowValue > center &&
1094                                value >= center &&
1095                                value <= this.lowValue
1096                            )
1097                                return true
1098                            else if (
1099                                this.lowValue < center &&
1100                                value <= center &&
1101                                value >= this.lowValue
1102                            )
1103                                return true
1104                        } else if (this.options.showSelectionBarEnd) {
1105                            if (value >= this.lowValue) return true
1106                        } else if (this.options.showSelectionBar && value <= this.lowValue)
1107                            return true
1108                    }
1109                    if (this.range && value >= this.lowValue && value <= this.highValue)
1110                        return true
1111                    return false
1112                },
1113
1114                /**
1115                 * Update position of the floor label
1116                 *
1117                 * @returns {undefined}
1118                 */
1119                updateFloorLab: function() {
1120                    this.translateFn(this.minValue, this.flrLab, 'floor')
1121                    this.getDimension(this.flrLab)
1122                    var position = this.options.rightToLeft
1123                        ? this.barDimension - this.flrLab.rzsd
1124                        : 0
1125                    this.setPosition(this.flrLab, position)
1126                },
1127
1128                /**
1129                 * Update position of the ceiling label
1130                 *
1131                 * @returns {undefined}
1132                 */
1133                updateCeilLab: function() {
1134                    this.translateFn(this.maxValue, this.ceilLab, 'ceil')
1135                    this.getDimension(this.ceilLab)
1136                    var position = this.options.rightToLeft
1137                        ? 0
1138                        : this.barDimension - this.ceilLab.rzsd
1139                    this.setPosition(this.ceilLab, position)
1140                },
1141
1142                /**
1143                 * Update slider handles and label positions
1144                 *
1145                 * @param {string} which
1146                 * @param {number} newPos
1147                 */
1148                updateHandles: function(which, newPos) {
1149                    if (which === 'lowValue') this.updateLowHandle(newPos)
1150                    else this.updateHighHandle(newPos)
1151
1152                    this.updateSelectionBar()
1153                    this.updateTicksScale()
1154                    if (this.range) this.updateCmbLabel()
1155                },
1156
1157                /**
1158                 * Helper function to work out the position for handle labels depending on RTL or not
1159                 *
1160                 * @param {string} labelName maxLab or minLab
1161                 * @param newPos
1162                 *
1163                 * @returns {number}
1164                 */
1165                getHandleLabelPos: function(labelName, newPos) {
1166                    var labelRzsd = this[labelName].rzsd,
1167                        nearHandlePos = newPos - labelRzsd / 2 + this.handleHalfDim,
1168                        endOfBarPos = this.barDimension - labelRzsd
1169
1170                    if (!this.options.boundPointerLabels) return nearHandlePos
1171
1172                    if (
1173                        (this.options.rightToLeft && labelName === 'minLab') ||
1174                        (!this.options.rightToLeft && labelName === 'maxLab')
1175                    ) {
1176                        return Math.min(nearHandlePos, endOfBarPos)
1177                    } else {
1178                        return Math.min(Math.max(nearHandlePos, 0), endOfBarPos)
1179                    }
1180                },
1181
1182                /**
1183                 * Update low slider handle position and label
1184                 *
1185                 * @param {number} newPos
1186                 * @returns {undefined}
1187                 */
1188                updateLowHandle: function(newPos) {
1189                    this.setPosition(this.minH, newPos)
1190                    this.translateFn(this.lowValue, this.minLab, 'model')
1191                    this.setPosition(
1192                        this.minLab,
1193                        this.getHandleLabelPos('minLab', newPos)
1194                    )
1195
1196                    if (this.options.getPointerColor) {
1197                        var pointercolor = this.getPointerColor('min')
1198                        this.scope.minPointerStyle = {
1199                            backgroundColor: pointercolor,
1200                        }
1201                    }
1202
1203                    if (this.options.autoHideLimitLabels) {
1204                        this.shFloorCeil()
1205                    }
1206                },
1207
1208                /**
1209                 * Update high slider handle position and label
1210                 *
1211                 * @param {number} newPos
1212                 * @returns {undefined}
1213                 */
1214                updateHighHandle: function(newPos) {
1215                    this.setPosition(this.maxH, newPos)
1216                    this.translateFn(this.highValue, this.maxLab, 'high')
1217                    this.setPosition(
1218                        this.maxLab,
1219                        this.getHandleLabelPos('maxLab', newPos)
1220                    )
1221
1222                    if (this.options.getPointerColor) {
1223                        var pointercolor = this.getPointerColor('max')
1224                        this.scope.maxPointerStyle = {
1225                            backgroundColor: pointercolor,
1226                        }
1227                    }
1228                    if (this.options.autoHideLimitLabels) {
1229                        this.shFloorCeil()
1230                    }
1231                },
1232
1233                /**
1234                 * Show/hide floor/ceiling label
1235                 *
1236                 * @returns {undefined}
1237                 */
1238                shFloorCeil: function() {
1239                    // Show based only on hideLimitLabels if pointer labels are hidden
1240                    if (this.options.hidePointerLabels) {
1241                        return
1242                    }
1243                    var flHidden = false,
1244                        clHidden = false,
1245                        isMinLabAtFloor = this.isLabelBelowFloorLab(this.minLab),
1246                        isMinLabAtCeil = this.isLabelAboveCeilLab(this.minLab),
1247                        isMaxLabAtCeil = this.isLabelAboveCeilLab(this.maxLab),
1248                        isCmbLabAtFloor = this.isLabelBelowFloorLab(this.cmbLab),
1249                        isCmbLabAtCeil = this.isLabelAboveCeilLab(this.cmbLab)
1250
1251                    if (isMinLabAtFloor) {
1252                        flHidden = true
1253                        this.hideEl(this.flrLab)
1254                    } else {
1255                        flHidden = false
1256                        this.showEl(this.flrLab)
1257                    }
1258
1259                    if (isMinLabAtCeil) {
1260                        clHidden = true
1261                        this.hideEl(this.ceilLab)
1262                    } else {
1263                        clHidden = false
1264                        this.showEl(this.ceilLab)
1265                    }
1266
1267                    if (this.range) {
1268                        var hideCeil = this.cmbLabelShown ? isCmbLabAtCeil : isMaxLabAtCeil
1269                        var hideFloor = this.cmbLabelShown
1270                            ? isCmbLabAtFloor
1271                            : isMinLabAtFloor
1272
1273                        if (hideCeil) {
1274                            this.hideEl(this.ceilLab)
1275                        } else if (!clHidden) {
1276                            this.showEl(this.ceilLab)
1277                        }
1278
1279                        // Hide or show floor label
1280                        if (hideFloor) {
1281                            this.hideEl(this.flrLab)
1282                        } else if (!flHidden) {
1283                            this.showEl(this.flrLab)
1284                        }
1285                    }
1286                },
1287
1288                isLabelBelowFloorLab: function(label) {
1289                    var isRTL = this.options.rightToLeft,
1290                        pos = label.rzsp,
1291                        dim = label.rzsd,
1292                        floorPos = this.flrLab.rzsp,
1293                        floorDim = this.flrLab.rzsd
1294                    return isRTL
1295                        ? pos + dim >= floorPos - 2
1296                        : pos <= floorPos + floorDim + 2
1297                },
1298
1299                isLabelAboveCeilLab: function(label) {
1300                    var isRTL = this.options.rightToLeft,
1301                        pos = label.rzsp,
1302                        dim = label.rzsd,
1303                        ceilPos = this.ceilLab.rzsp,
1304                        ceilDim = this.ceilLab.rzsd
1305                    return isRTL ? pos <= ceilPos + ceilDim + 2 : pos + dim >= ceilPos - 2
1306                },
1307
1308                /**
1309                 * Update slider selection bar, combined label and range label
1310                 *
1311                 * @returns {undefined}
1312                 */
1313                updateSelectionBar: function() {
1314                    var position = 0,
1315                        dimension = 0,
1316                        isSelectionBarFromRight = this.options.rightToLeft
1317                            ? !this.options.showSelectionBarEnd
1318                            : this.options.showSelectionBarEnd,
1319                        positionForRange = this.options.rightToLeft
1320                            ? this.maxH.rzsp + this.handleHalfDim
1321                            : this.minH.rzsp + this.handleHalfDim
1322
1323                    if (this.range) {
1324                        dimension = Math.abs(this.maxH.rzsp - this.minH.rzsp)
1325                        position = positionForRange
1326                    } else {
1327                        if (this.options.showSelectionBarFromValue !== null) {
1328                            var center = this.options.showSelectionBarFromValue,
1329                                centerPosition = this.valueToPosition(center),
1330                                isModelGreaterThanCenter = this.options.rightToLeft
1331                                    ? this.lowValue <= center
1332                                    : this.lowValue > center
1333                            if (isModelGreaterThanCenter) {
1334                                dimension = this.minH.rzsp - centerPosition
1335                                position = centerPosition + this.handleHalfDim
1336                            } else {
1337                                dimension = centerPosition - this.minH.rzsp
1338                                position = this.minH.rzsp + this.handleHalfDim
1339                            }
1340                        } else if (isSelectionBarFromRight) {
1341                            dimension =
1342                                Math.abs(this.maxPos - this.minH.rzsp) + this.handleHalfDim
1343                            position = this.minH.rzsp + this.handleHalfDim
1344                        } else {
1345                            dimension = this.minH.rzsp + this.handleHalfDim
1346                            position = 0
1347                        }
1348                    }
1349                    this.setDimension(this.selBar, dimension)
1350                    this.setPosition(this.selBar, position)
1351                    if (this.range && this.options.showOuterSelectionBars) {
1352                        if (this.options.rightToLeft) {
1353                            this.setDimension(this.rightOutSelBar, position)
1354                            this.setPosition(this.rightOutSelBar, 0)
1355                            this.setDimension(
1356                                this.leftOutSelBar,
1357                                this.getDimension(this.fullBar) - (position + dimension)
1358                            )
1359                            this.setPosition(this.leftOutSelBar, position + dimension)
1360                        } else {
1361                            this.setDimension(this.leftOutSelBar, position)
1362                            this.setPosition(this.leftOutSelBar, 0)
1363                            this.setDimension(
1364                                this.rightOutSelBar,
1365                                this.getDimension(this.fullBar) - (position + dimension)
1366                            )
1367                            this.setPosition(this.rightOutSelBar, position + dimension)
1368                        }
1369                    }
1370                    if (this.options.getSelectionBarColor) {
1371                        var color = this.getSelectionBarColor()
1372                        this.scope.barStyle = {
1373                            backgroundColor: color,
1374                        }
1375                    } else if (this.options.selectionBarGradient) {
1376                        var offset =
1377                                this.options.showSelectionBarFromValue !== null
1378                                    ? this.valueToPosition(this.options.showSelectionBarFromValue)
1379                                    : 0,
1380                            reversed = (offset - position > 0) ^ isSelectionBarFromRight,
1381                            direction = this.options.vertical
1382                                ? reversed ? 'bottom' : 'top'
1383                                : reversed ? 'left' : 'right'
1384                        this.scope.barStyle = {
1385                            backgroundImage:
1386                            'linear-gradient(to ' +
1387                            direction +
1388                            ', ' +
1389                            this.options.selectionBarGradient.from +
1390                            ' 0%,' +
1391                            this.options.selectionBarGradient.to +
1392                            ' 100%)',
1393                        }
1394                        if (this.options.vertical) {
1395                            this.scope.barStyle.backgroundPosition =
1396                                'center ' +
1397                                (offset +
1398                                    dimension +
1399                                    position +
1400                                    (reversed ? -this.handleHalfDim : 0)) +
1401                                'px'
1402                            this.scope.barStyle.backgroundSize =
1403                                '100% ' + (this.barDimension - this.handleHalfDim) + 'px'
1404                        } else {
1405                            this.scope.barStyle.backgroundPosition =
1406                                offset -
1407                                position +
1408                                (reversed ? this.handleHalfDim : 0) +
1409                                'px center'
1410                            this.scope.barStyle.backgroundSize =
1411                                this.barDimension - this.handleHalfDim + 'px 100%'
1412                        }
1413                    }
1414                },
1415
1416                /**
1417                 * Wrapper around the getSelectionBarColor of the user to pass to
1418                 * correct parameters
1419                 */
1420                getSelectionBarColor: function() {
1421                    if (this.range)
1422                        return this.options.getSelectionBarColor(
1423                            this.scope.rzSliderModel,
1424                            this.scope.rzSliderHigh
1425                        )
1426                    return this.options.getSelectionBarColor(this.scope.rzSliderModel)
1427                },
1428
1429                /**
1430                 * Wrapper around the getPointerColor of the user to pass to
1431                 * correct parameters
1432                 */
1433                getPointerColor: function(pointerType) {
1434                    if (pointerType === 'max') {
1435                        return this.options.getPointerColor(
1436                            this.scope.rzSliderHigh,
1437                            pointerType
1438                        )
1439                    }
1440                    return this.options.getPointerColor(
1441                        this.scope.rzSliderModel,
1442                        pointerType
1443                    )
1444                },
1445
1446                /**
1447                 * Wrapper around the getTickColor of the user to pass to
1448                 * correct parameters
1449                 */
1450                getTickColor: function(value) {
1451                    return this.options.getTickColor(value)
1452                },
1453
1454                /**
1455                 * Update combined label position and value
1456                 *
1457                 * @returns {undefined}
1458                 */
1459                updateCmbLabel: function() {
1460                    var isLabelOverlap = null
1461                    if (this.options.rightToLeft) {
1462                        isLabelOverlap =
1463                            this.minLab.rzsp - this.minLab.rzsd - 10 <= this.maxLab.rzsp
1464                    } else {
1465                        isLabelOverlap =
1466                            this.minLab.rzsp + this.minLab.rzsd + 10 >= this.maxLab.rzsp
1467                    }
1468
1469                    if (isLabelOverlap) {
1470                        var lowTr = this.getDisplayValue(this.lowValue, 'model'),
1471                            highTr = this.getDisplayValue(this.highValue, 'high'),
1472                            labelVal = ''
1473                        if (this.options.mergeRangeLabelsIfSame && lowTr === highTr) {
1474                            labelVal = lowTr
1475                        } else {
1476                            labelVal = this.options.rightToLeft
1477                                ? highTr + this.options.labelOverlapSeparator + lowTr
1478                                : lowTr + this.options.labelOverlapSeparator + highTr
1479                        }
1480
1481                        this.translateFn(labelVal, this.cmbLab, 'cmb', false)
1482                        var pos = this.options.boundPointerLabels
1483                            ? Math.min(
1484                                Math.max(
1485                                    this.selBar.rzsp +
1486                                    this.selBar.rzsd / 2 -
1487                                    this.cmbLab.rzsd / 2,
1488                                    0
1489                                ),
1490                                this.barDimension - this.cmbLab.rzsd
1491                            )
1492                            : this.selBar.rzsp + this.selBar.rzsd / 2 - this.cmbLab.rzsd / 2
1493
1494                        this.setPosition(this.cmbLab, pos)
1495                        this.cmbLabelShown = true
1496                        this.hideEl(this.minLab)
1497                        this.hideEl(this.maxLab)
1498                        this.showEl(this.cmbLab)
1499                    } else {
1500                        this.cmbLabelShown = false
1501                        this.updateHighHandle(this.valueToPosition(this.highValue))
1502                        this.updateLowHandle(this.valueToPosition(this.lowValue))
1503                        this.showEl(this.maxLab)
1504                        this.showEl(this.minLab)
1505                        this.hideEl(this.cmbLab)
1506                    }
1507                    if (this.options.autoHideLimitLabels) {
1508                        this.shFloorCeil()
1509                    }
1510                },
1511
1512                /**
1513                 * Return the translated value if a translate function is provided else the original value
1514                 * @param value
1515                 * @param which if it's min or max handle
1516                 * @returns {*}
1517                 */
1518                getDisplayValue: function(value, which) {
1519                    if (this.options.stepsArray && !this.options.bindIndexForStepsArray) {
1520                        value = this.getStepValue(value)
1521                    }
1522                    return this.customTrFn(value, this.options.id, which)
1523                },
1524
1525                /**
1526                 * Round value to step and precision based on minValue
1527                 *
1528                 * @param {number} value
1529                 * @param {number} customStep a custom step to override the defined step
1530                 * @returns {number}
1531                 */
1532                roundStep: function(value, customStep) {
1533                    var step = customStep ? customStep : this.step,
1534                        steppedDifference = parseFloat(
1535                            (value - this.minValue) / step
1536                        ).toPrecision(12)
1537                    steppedDifference = Math.round(+steppedDifference) * step
1538                    var newValue = (this.minValue + steppedDifference).toFixed(
1539                        this.precision
1540                    )
1541                    return +newValue
1542                },
1543
1544                /**
1545                 * Hide element
1546                 *
1547                 * @param element
1548                 * @returns {jqLite} The jqLite wrapped DOM element
1549                 */
1550                hideEl: function(element) {
1551                    return element.css({
1552                        visibility: 'hidden',
1553                    })
1554                },
1555
1556                /**
1557                 * Show element
1558                 *
1559                 * @param element The jqLite wrapped DOM element
1560                 * @returns {jqLite} The jqLite
1561                 */
1562                showEl: function(element) {
1563                    if (!!element.rzAlwaysHide) {
1564                        return element
1565                    }
1566
1567                    return element.css({
1568                        visibility: 'visible',
1569                    })
1570                },
1571
1572                /**
1573                 * Set element left/top position depending on whether slider is horizontal or vertical
1574                 *
1575                 * @param {jqLite} elem The jqLite wrapped DOM element
1576                 * @param {number} pos
1577                 * @returns {number}
1578                 */
1579                setPosition: function(elem, pos) {
1580                    elem.rzsp = pos
1581                    var css = {}
1582                    css[this.positionProperty] = Math.round(pos) + 'px'
1583                    elem.css(css)
1584                    return pos
1585                },
1586
1587                /**
1588                 * Get element width/height depending on whether slider is horizontal or vertical
1589                 *
1590                 * @param {jqLite} elem The jqLite wrapped DOM element
1591                 * @returns {number}
1592                 */
1593                getDimension: function(elem) {
1594                    var val = elem[0].getBoundingClientRect()
1595                    if (this.options.vertical)
1596                        elem.rzsd = (val.bottom - val.top) * this.options.scale
1597                    else elem.rzsd = (val.right - val.left) * this.options.scale
1598                    return elem.rzsd
1599                },
1600
1601                /**
1602                 * Set element width/height depending on whether slider is horizontal or vertical
1603                 *
1604                 * @param {jqLite} elem  The jqLite wrapped DOM element
1605                 * @param {number} dim
1606                 * @returns {number}
1607                 */
1608                setDimension: function(elem, dim) {
1609                    elem.rzsd = dim
1610                    var css = {}
1611                    css[this.dimensionProperty] = Math.round(dim) + 'px'
1612                    elem.css(css)
1613                    return dim
1614                },
1615
1616                /**
1617                 * Returns a value that is within slider range
1618                 *
1619                 * @param {number} val
1620                 * @returns {number}
1621                 */
1622                sanitizeValue: function(val) {
1623                    return Math.min(Math.max(val, this.minValue), this.maxValue)
1624                },
1625
1626                /**
1627                 * Translate value to pixel position
1628                 *
1629                 * @param {number} val
1630                 * @returns {number}
1631                 */
1632                valueToPosition: function(val) {
1633                    var fn = this.linearValueToPosition
1634                    if (this.options.customValueToPosition)
1635                        fn = this.options.customValueToPosition
1636                    else if (this.options.logScale) fn = this.logValueToPosition
1637
1638                    val = this.sanitizeValue(val)
1639                    var percent = fn(val, this.minValue, this.maxValue) || 0
1640                    if (this.options.rightToLeft) percent = 1 - percent
1641                    return percent * this.maxPos
1642                },
1643
1644                linearValueToPosition: function(val, minVal, maxVal) {
1645                    var range = maxVal - minVal
1646                    return (val - minVal) / range
1647                },
1648
1649                logValueToPosition: function(val, minVal, maxVal) {
1650                    val = Math.log(val)
1651                    minVal = Math.log(minVal)
1652                    maxVal = Math.log(maxVal)
1653                    var range = maxVal - minVal
1654                    return (val - minVal) / range
1655                },
1656
1657                /**
1658                 * Translate position to model value
1659                 *
1660                 * @param {number} position
1661                 * @returns {number}
1662                 */
1663                positionToValue: function(position) {
1664                    var percent = position / this.maxPos
1665                    if (this.options.rightToLeft) percent = 1 - percent
1666                    var fn = this.linearPositionToValue
1667                    if (this.options.customPositionToValue)
1668                        fn = this.options.customPositionToValue
1669                    else if (this.options.logScale) fn = this.logPositionToValue
1670                    return fn(percent, this.minValue, this.maxValue) || 0
1671                },
1672
1673                linearPositionToValue: function(percent, minVal, maxVal) {
1674                    return percent * (maxVal - minVal) + minVal
1675                },
1676
1677                logPositionToValue: function(percent, minVal, maxVal) {
1678                    minVal = Math.log(minVal)
1679                    maxVal = Math.log(maxVal)
1680                    var value = percent * (maxVal - minVal) + minVal
1681                    return Math.exp(value)
1682                },
1683
1684                getEventAttr: function(event, attr) {
1685                    return event.originalEvent === undefined
1686                        ? event[attr]
1687                        : event.originalEvent[attr]
1688                },
1689
1690                // Events
1691                /**
1692                 * Get the X-coordinate or Y-coordinate of an event
1693                 *
1694                 * @param {Object} event  The event
1695                 * @param targetTouchId The identifier of the touch with the X/Y coordinates
1696                 * @returns {number}
1697                 */
1698                getEventXY: function(event, targetTouchId) {
1699                    /* http://stackoverflow.com/a/12336075/282882 */
1700                    //noinspection JSLint
1701                    var clientXY = this.options.vertical ? 'clientY' : 'clientX'
1702                    if (event[clientXY] !== undefined) {
1703                        return event[clientXY]
1704                    }
1705
1706                    var touches = this.getEventAttr(event, 'touches')
1707
1708                    if (targetTouchId !== undefined) {
1709                        for (var i = 0; i < touches.length; i++) {
1710                            if (touches[i].identifier === targetTouchId) {
1711                                return touches[i][clientXY]
1712                            }
1713                        }
1714                    }
1715
1716                    // If no target touch or the target touch was not found in the event
1717                    // returns the coordinates of the first touch
1718                    return touches[0][clientXY]
1719                },
1720
1721                /**
1722                 * Compute the event position depending on whether the slider is horizontal or vertical
1723                 * @param event
1724                 * @param targetTouchId If targetTouchId is provided it will be considered the position of that
1725                 * @returns {number}
1726                 */
1727                getEventPosition: function(event, targetTouchId) {
1728                    var sliderPos = this.sliderElem.rzsp,
1729                        eventPos = 0
1730                    if (this.options.vertical)
1731                        eventPos = -this.getEventXY(event, targetTouchId) + sliderPos
1732                    else eventPos = this.getEventXY(event, targetTouchId) - sliderPos
1733                    return eventPos * this.options.scale - this.handleHalfDim // #346 handleHalfDim is already scaled
1734                },
1735
1736                /**
1737                 * Get event names for move and event end
1738                 *
1739                 * @param {Event}    event    The event
1740                 *
1741                 * @return {{moveEvent: string, endEvent: string}}
1742                 */
1743                getEventNames: function(event) {
1744                    var eventNames = {
1745                        moveEvent: '',
1746                        endEvent: '',
1747                    }
1748
1749                    if (this.getEventAttr(event, 'touches')) {
1750                        eventNames.moveEvent = 'touchmove'
1751                        eventNames.endEvent = 'touchend'
1752                    } else {
1753                        eventNames.moveEvent = 'mousemove'
1754                        eventNames.endEvent = 'mouseup'
1755                    }
1756
1757                    return eventNames
1758                },
1759
1760                /**
1761                 * Get the handle closest to an event.
1762                 *
1763                 * @param event {Event} The event
1764                 * @returns {jqLite} The handle closest to the event.
1765                 */
1766                getNearestHandle: function(event) {
1767                    if (!this.range) {
1768                        return this.minH
1769                    }
1770                    var position = this.getEventPosition(event),
1771                        distanceMin = Math.abs(position - this.minH.rzsp),
1772                        distanceMax = Math.abs(position - this.maxH.rzsp)
1773                    if (distanceMin < distanceMax) return this.minH
1774                    else if (distanceMin > distanceMax) return this.maxH
1775                    else if (!this.options.rightToLeft)
1776                    //if event is at the same distance from min/max then if it's at left of minH, we return minH else maxH
1777                        return position < this.minH.rzsp ? this.minH : this.maxH
1778                    else
1779                    //reverse in rtl
1780                        return position > this.minH.rzsp ? this.minH : this.maxH
1781                },
1782
1783                /**
1784                 * Wrapper function to focus an angular element
1785                 *
1786                 * @param el {AngularElement} the element to focus
1787                 */
1788                focusElement: function(el) {
1789                    var DOM_ELEMENT = 0
1790                    el[DOM_ELEMENT].focus()
1791                },
1792
1793                /**
1794                 * Bind mouse and touch events to slider handles
1795                 *
1796                 * @returns {undefined}
1797                 */
1798                bindEvents: function() {
1799                    var barTracking, barStart, barMove
1800
1801                    if (this.options.draggableRange) {
1802                        barTracking = 'rzSliderDrag'
1803                        barStart = this.onDragStart
1804                        barMove = this.onDragMove
1805                    } else {
1806                        barTracking = 'lowValue'
1807                        barStart = this.onStart
1808                        barMove = this.onMove
1809                    }
1810
1811                    if (!this.options.onlyBindHandles) {
1812                        this.selBar.on(
1813                            'mousedown',
1814                            angular.bind(this, barStart, null, barTracking)
1815                        )
1816                        this.selBar.on(
1817                            'mousedown',
1818                            angular.bind(this, barMove, this.selBar)
1819                        )
1820                    }
1821
1822                    if (this.options.draggableRangeOnly) {
1823                        this.minH.on(
1824                            'mousedown',
1825                            angular.bind(this, barStart, null, barTracking)
1826                        )
1827                        this.maxH.on(
1828                            'mousedown',
1829                            angular.bind(this, barStart, null, barTracking)
1830                        )
1831                    } else {
1832                        this.minH.on(
1833                            'mousedown',
1834                            angular.bind(this, this.onStart, this.minH, 'lowValue')
1835                        )
1836                        if (this.range) {
1837                            this.maxH.on(
1838                                'mousedown',
1839                                angular.bind(this, this.onStart, this.maxH, 'highValue')
1840                            )
1841                        }
1842                        if (!this.options.onlyBindHandles) {
1843                            this.fullBar.on(
1844                                'mousedown',
1845                                angular.bind(this, this.onStart, null, null)
1846                            )
1847                            this.fullBar.on(
1848                                'mousedown',
1849                                angular.bind(this, this.onMove, this.fullBar)
1850                            )
1851                            this.ticks.on(
1852                                'mousedown',
1853                                angular.bind(this, this.onStart, null, null)
1854                            )
1855                            this.ticks.on(
1856                                'mousedown',
1857                                angular.bind(this, this.onTickClick, this.ticks)
1858                            )
1859                        }
1860                    }
1861
1862                    if (!this.options.onlyBindHandles) {
1863                        this.selBar.on(
1864                            'touchstart',
1865                            angular.bind(this, barStart, null, barTracking)
1866                        )
1867                        this.selBar.on(
1868                            'touchstart',
1869                            angular.bind(this, barMove, this.selBar)
1870                        )
1871                    }
1872                    if (this.options.draggableRangeOnly) {
1873                        this.minH.on(
1874                            'touchstart',
1875                            angular.bind(this, barStart, null, barTracking)
1876                        )
1877                        this.maxH.on(
1878                            'touchstart',
1879                            angular.bind(this, barStart, null, barTracking)
1880                        )
1881                    } else {
1882                        this.minH.on(
1883                            'touchstart',
1884                            angular.bind(this, this.onStart, this.minH, 'lowValue')
1885                        )
1886                        if (this.range) {
1887                            this.maxH.on(
1888                                'touchstart',
1889                                angular.bind(this, this.onStart, this.maxH, 'highValue')
1890                            )
1891                        }
1892                        if (!this.options.onlyBindHandles) {
1893                            this.fullBar.on(
1894                                'touchstart',
1895                                angular.bind(this, this.onStart, null, null)
1896                            )
1897                            this.fullBar.on(
1898                                'touchstart',
1899                                angular.bind(this, this.onMove, this.fullBar)
1900                            )
1901                            this.ticks.on(
1902                                'touchstart',
1903                                angular.bind(this, this.onStart, null, null)
1904                            )
1905                            this.ticks.on(
1906                                'touchstart',
1907                                angular.bind(this, this.onTickClick, this.ticks)
1908                            )
1909                        }
1910                    }
1911
1912                    if (this.options.keyboardSupport) {
1913                        this.minH.on(
1914                            'focus',
1915                            angular.bind(this, this.onPointerFocus, this.minH, 'lowValue')
1916                        )
1917                        if (this.range) {
1918                            this.maxH.on(
1919                                'focus',
1920                                angular.bind(this, this.onPointerFocus, this.maxH, 'highValue')
1921                            )
1922                        }
1923                    }
1924                },
1925
1926                /**
1927                 * Unbind mouse and touch events to slider handles
1928                 *
1929                 * @returns {undefined}
1930                 */
1931                unbindEvents: function() {
1932                    this.minH.off()
1933                    this.maxH.off()
1934                    this.fullBar.off()
1935                    this.selBar.off()
1936                    this.ticks.off()
1937                },
1938
1939                /**
1940                 * onStart event handler
1941                 *
1942                 * @param {?Object} pointer The jqLite wrapped DOM element; if null, the closest handle is used
1943                 * @param {?string} ref     The name of the handle being changed; if null, the closest handle's value is modified
1944                 * @param {Event}   event   The event
1945                 * @returns {undefined}
1946                 */
1947                onStart: function(pointer, ref, event) {
1948                    var ehMove,
1949                        ehEnd,
1950                        eventNames = this.getEventNames(event)
1951
1952                    event.preventDefault()
1953
1954                    // We have to do this in case the HTML where the sliders are on
1955                    // have been animated into view.
1956                    this.calcViewDimensions()
1957
1958                    if (pointer) {
1959                        this.tracking = ref
1960                    } else {
1961                        pointer = this.getNearestHandle(event)
1962                        this.tracking = pointer === this.minH ? 'lowValue' : 'highValue'
1963                    }
1964
1965                    pointer.addClass('rz-active')
1966
1967                    if (this.options.keyboardSupport) this.focusElement(pointer)
1968
1969                    ehMove = angular.bind(
1970                        this,
1971                        this.dragging.active ? this.onDragMove : this.onMove,
1972                        pointer
1973                    )
1974                    ehEnd = angular.bind(this, this.onEnd, ehMove)
1975
1976                    $document.on(eventNames.moveEvent, ehMove)
1977                    $document.on(eventNames.endEvent, ehEnd)
1978                    this.endHandlerToBeRemovedOnEnd = ehEnd
1979
1980                    this.callOnStart()
1981
1982                    var changedTouches = this.getEventAttr(event, 'changedTouches')
1983                    if (changedTouches) {
1984                        // Store the touch identifier
1985                        if (!this.touchId) {
1986                            this.isDragging = true
1987                            this.touchId = changedTouches[0].identifier
1988                        }
1989                    }
1990                },
1991
1992                /**
1993                 * onMove event handler
1994                 *
1995                 * @param {jqLite} pointer
1996                 * @param {Event}  event The event
1997                 * @param {boolean}  fromTick if the event occured on a tick or not
1998                 * @returns {undefined}
1999                 */
2000                onMove: function(pointer, event, fromTick) {
2001                    var changedTouches = this.getEventAttr(event, 'changedTouches')
2002                    var touchForThisSlider
2003                    if (changedTouches) {
2004                        for (var i = 0; i < changedTouches.length; i++) {
2005                            if (changedTouches[i].identifier === this.touchId) {
2006                                touchForThisSlider = changedTouches[i]
2007                                break
2008                            }
2009                        }
2010                    }
2011
2012                    if (changedTouches && !touchForThisSlider) {
2013                        return
2014                    }
2015
2016                    var newPos = this.getEventPosition(
2017                        event,
2018                        touchForThisSlider ? touchForThisSlider.identifier : undefined
2019                        ),
2020                        newValue,
2021                        ceilValue = this.options.rightToLeft
2022                            ? this.minValue
2023                            : this.maxValue,
2024                        flrValue = this.options.rightToLeft ? this.maxValue : this.minValue
2025
2026                    if (newPos <= 0) {
2027                        newValue = flrValue
2028                    } else if (newPos >= this.maxPos) {
2029                        newValue = ceilValue
2030                    } else {
2031                        newValue = this.positionToValue(newPos)
2032                        if (fromTick && angular.isNumber(this.options.showTicks))
2033                            newValue = this.roundStep(newValue, this.options.showTicks)
2034                        else newValue = this.roundStep(newValue)
2035                    }
2036                    this.positionTrackingHandle(newValue)
2037                },
2038
2039                /**
2040                 * onEnd event handler
2041                 *
2042                 * @param {Event}    event    The event
2043                 * @param {Function} ehMove   The bound move event handler
2044                 * @returns {undefined}
2045                 */
2046                onEnd: function(ehMove, event) {
2047                    var changedTouches = this.getEventAttr(event, 'changedTouches')
2048                    if (changedTouches && changedTouches[0].identifier !== this.touchId) {
2049                        return
2050                    }
2051                    this.isDragging = false
2052                    this.touchId = null
2053
2054                    if (!this.options.keyboardSupport) {
2055                        this.minH.removeClass('rz-active')
2056                        this.maxH.removeClass('rz-active')
2057                        this.tracking = ''
2058                    }
2059                    this.dragging.active = false
2060
2061                    var eventName = this.getEventNames(event)
2062                    $document.off(eventName.moveEvent, ehMove)
2063                    $document.off(eventName.endEvent, this.endHandlerToBeRemovedOnEnd)
2064                    this.endHandlerToBeRemovedOnEnd = null
2065                    this.callOnEnd()
2066                },
2067
2068                onTickClick: function(pointer, event) {
2069                    this.onMove(pointer, event, true)
2070                },
2071
2072                onPointerFocus: function(pointer, ref) {
2073                    this.tracking = ref
2074                    pointer.one('blur', angular.bind(this, this.onPointerBlur, pointer))
2075                    pointer.on('keydown', angular.bind(this, this.onKeyboardEvent))
2076                    pointer.on('keyup', angular.bind(this, this.onKeyUp))
2077                    this.firstKeyDown = true
2078                    pointer.addClass('rz-active')
2079
2080                    this.currentFocusElement = {
2081                        pointer: pointer,
2082                        ref: ref,
2083                    }
2084                },
2085
2086                onKeyUp: function() {
2087                    this.firstKeyDown = true
2088                    this.callOnEnd()
2089                },
2090
2091                onPointerBlur: function(pointer) {
2092                    pointer.off('keydown')
2093                    pointer.off('keyup')
2094                    pointer.removeClass('rz-active')
2095                    if (!this.isDragging) {
2096                        this.tracking = ''
2097                        this.currentFocusElement = null
2098                    }
2099                },
2100
2101                /**
2102                 * Key actions helper function
2103                 *
2104                 * @param {number} currentValue value of the slider
2105                 *
2106                 * @returns {?Object} action value mappings
2107                 */
2108                getKeyActions: function(currentValue) {
2109                    var increaseStep = currentValue + this.step,
2110                        decreaseStep = currentValue - this.step,
2111                        increasePage = currentValue + this.valueRange / 10,
2112                        decreasePage = currentValue - this.valueRange / 10
2113
2114                    if (this.options.reversedControls) {
2115                        increaseStep = currentValue - this.step
2116                        decreaseStep = currentValue + this.step
2117                        increasePage = currentValue - this.valueRange / 10
2118                        decreasePage = currentValue + this.valueRange / 10
2119                    }
2120
2121                    //Left to right default actions
2122                    var actions = {
2123                        UP: increaseStep,
2124                        DOWN: decreaseStep,
2125                        LEFT: decreaseStep,
2126                        RIGHT: increaseStep,
2127                        PAGEUP: increasePage,
2128                        PAGEDOWN: decreasePage,
2129                        HOME: this.options.reversedControls ? this.maxValue : this.minValue,
2130                        END: this.options.reversedControls ? this.minValue : this.maxValue,
2131                    }
2132                    //right to left means swapping right and left arrows
2133                    if (this.options.rightToLeft) {
2134                        actions.LEFT = increaseStep
2135                        actions.RIGHT = decreaseStep
2136                        // right to left and vertical means we also swap up and down
2137                        if (this.options.vertical) {
2138                            actions.UP = decreaseStep
2139                            actions.DOWN = increaseStep
2140                        }
2141                    }
2142                    return actions
2143                },
2144
2145                onKeyboardEvent: function(event) {
2146                    var currentValue = this[this.tracking],
2147                        keyCode = event.keyCode || event.which,
2148                        keys = {
2149                            38: 'UP',
2150                            40: 'DOWN',
2151                            37: 'LEFT',
2152                            39: 'RIGHT',
2153                            33: 'PAGEUP',
2154                            34: 'PAGEDOWN',
2155                            36: 'HOME',
2156                            35: 'END',
2157                        },
2158                        actions = this.getKeyActions(currentValue),
2159                        key = keys[keyCode],
2160                        action = actions[key]
2161                    if (action == null || this.tracking === '') return
2162                    event.preventDefault()
2163
2164                    if (this.firstKeyDown) {
2165                        this.firstKeyDown = false
2166                        this.callOnStart()
2167                    }
2168
2169                    var self = this
2170                    $timeout(function() {
2171                        var newValue = self.roundStep(self.sanitizeValue(action))
2172                        if (!self.options.draggableRangeOnly) {
2173                            self.positionTrackingHandle(newValue)
2174                        } else {
2175                            var difference = self.highValue - self.lowValue,
2176                                newMinValue,
2177                                newMaxValue
2178                            if (self.tracking === 'lowValue') {
2179                                newMinValue = newValue
2180                                newMaxValue = newValue + difference
2181                                if (newMaxValue > self.maxValue) {
2182                                    newMaxValue = self.maxValue
2183                                    newMinValue = newMaxValue - difference
2184                                }
2185                            } else {
2186                                newMaxValue = newValue
2187                                newMinValue = newValue - difference
2188                                if (newMinValue < self.minValue) {
2189                                    newMinValue = self.minValue
2190                                    newMaxValue = newMinValue + difference
2191                                }
2192                            }
2193                            self.positionTrackingBar(newMinValue, newMaxValue)
2194                        }
2195                    })
2196                },
2197
2198                /**
2199                 * onDragStart event handler
2200                 *
2201                 * Handles dragging of the middle bar.
2202                 *
2203                 * @param {Object} pointer The jqLite wrapped DOM element
2204                 * @param {string} ref     One of the refLow, refHigh values
2205                 * @param {Event}  event   The event
2206                 * @returns {undefined}
2207                 */
2208                onDragStart: function(pointer, ref, event) {
2209                    var position = this.getEventPosition(event)
2210                    this.dragging = {
2211                        active: true,
2212                        value: this.positionToValue(position),
2213                        difference: this.highValue - this.lowValue,
2214                        lowLimit: this.options.rightToLeft
2215                            ? this.minH.rzsp - position
2216                            : position - this.minH.rzsp,
2217                        highLimit: this.options.rightToLeft
2218                            ? position - this.maxH.rzsp
2219                            : this.maxH.rzsp - position,
2220                    }
2221
2222                    this.onStart(pointer, ref, event)
2223                },
2224
2225                /**
2226                 * getValue helper function
2227                 *
2228                 * gets max or min value depending on whether the newPos is outOfBounds above or below the bar and rightToLeft
2229                 *
2230                 * @param {string} type 'max' || 'min' The value we are calculating
2231                 * @param {number} newPos  The new position
2232                 * @param {boolean} outOfBounds Is the new position above or below the max/min?
2233                 * @param {boolean} isAbove Is the new position above the bar if out of bounds?
2234                 *
2235                 * @returns {number}
2236                 */
2237                getValue: function(type, newPos, outOfBounds, isAbove) {
2238                    var isRTL = this.options.rightToLeft,
2239                        value = null
2240
2241                    if (type === 'min') {
2242                        if (outOfBounds) {
2243                            if (isAbove) {
2244                                value = isRTL
2245                                    ? this.minValue
2246                                    : this.maxValue - this.dragging.difference
2247                            } else {
2248                                value = isRTL
2249                                    ? this.maxValue - this.dragging.difference
2250                                    : this.minValue
2251                            }
2252                        } else {
2253                            value = isRTL
2254                                ? this.positionToValue(newPos + this.dragging.lowLimit)
2255                                : this.positionToValue(newPos - this.dragging.lowLimit)
2256                        }
2257                    } else {
2258                        if (outOfBounds) {
2259                            if (isAbove) {
2260                                value = isRTL
2261                                    ? this.minValue + this.dragging.difference
2262                                    : this.maxValue
2263                            } else {
2264                                value = isRTL
2265                                    ? this.maxValue
2266                                    : this.minValue + this.dragging.difference
2267                            }
2268                        } else {
2269                            if (isRTL) {
2270                                value =
2271                                    this.positionToValue(newPos + this.dragging.lowLimit) +
2272                                    this.dragging.difference
2273                            } else {
2274                                value =
2275                                    this.positionToValue(newPos - this.dragging.lowLimit) +
2276                                    this.dragging.difference
2277                            }
2278                        }
2279                    }
2280                    return this.roundStep(value)
2281                },
2282
2283                /**
2284                 * onDragMove event handler
2285                 *
2286                 * Handles dragging of the middle bar.
2287                 *
2288                 * @param {jqLite} pointer
2289                 * @param {Event}  event The event
2290                 * @returns {undefined}
2291                 */
2292                onDragMove: function(pointer, event) {
2293                    var newPos = this.getEventPosition(event),
2294                        newMinValue,
2295                        newMaxValue,
2296                        ceilLimit,
2297                        flrLimit,
2298                        isUnderFlrLimit,
2299                        isOverCeilLimit,
2300                        flrH,
2301                        ceilH
2302
2303                    if (this.options.rightToLeft) {
2304                        ceilLimit = this.dragging.lowLimit
2305                        flrLimit = this.dragging.highLimit
2306                        flrH = this.maxH
2307                        ceilH = this.minH
2308                    } else {
2309                        ceilLimit = this.dragging.highLimit
2310                        flrLimit = this.dragging.lowLimit
2311                        flrH = this.minH
2312                        ceilH = this.maxH
2313                    }
2314                    isUnderFlrLimit = newPos <= flrLimit
2315                    isOverCeilLimit = newPos >= this.maxPos - ceilLimit
2316
2317                    if (isUnderFlrLimit) {
2318                        if (flrH.rzsp === 0) return
2319                        newMinValue = this.getValue('min', newPos, true, false)
2320                        newMaxValue = this.getValue('max', newPos, true, false)
2321                    } else if (isOverCeilLimit) {
2322                        if (ceilH.rzsp === this.maxPos) return
2323                        newMaxValue = this.getValue('max', newPos, true, true)
2324                        newMinValue = this.getValue('min', newPos, true, true)
2325                    } else {
2326                        newMinValue = this.getValue('min', newPos, false)
2327                        newMaxValue = this.getValue('max', newPos, false)
2328                    }
2329                    this.positionTrackingBar(newMinValue, newMaxValue)
2330                },
2331
2332                /**
2333                 * Set the new value and position for the entire bar
2334                 *
2335                 * @param {number} newMinValue   the new minimum value
2336                 * @param {number} newMaxValue   the new maximum value
2337                 */
2338                positionTrackingBar: function(newMinValue, newMaxValue) {
2339                    if (
2340                        this.options.minLimit != null &&
2341                        newMinValue < this.options.minLimit
2342                    ) {
2343                        newMinValue = this.options.minLimit
2344                        newMaxValue = newMinValue + this.dragging.difference
2345                    }
2346                    if (
2347                        this.options.maxLimit != null &&
2348                        newMaxValue > this.options.maxLimit
2349                    ) {
2350                        newMaxValue = this.options.maxLimit
2351                        newMinValue = newMaxValue - this.dragging.difference
2352                    }
2353
2354                    this.lowValue = newMinValue
2355                    this.highValue = newMaxValue
2356                    this.applyLowValue()
2357                    if (this.range) this.applyHighValue()
2358                    this.applyModel(true)
2359                    this.updateHandles('lowValue', this.valueToPosition(newMinValue))
2360                    this.updateHandles('highValue', this.valueToPosition(newMaxValue))
2361                },
2362
2363                /**
2364                 * Set the new value and position to the current tracking handle
2365                 *
2366                 * @param {number} newValue new model value
2367                 */
2368                positionTrackingHandle: function(newValue) {
2369                    var valueChanged = false
2370                    newValue = this.applyMinMaxLimit(newValue)
2371                    if (this.range) {
2372                        if (this.options.pushRange) {
2373                            newValue = this.applyPushRange(newValue)
2374                            valueChanged = true
2375                        } else {
2376                            if (this.options.noSwitching) {
2377                                if (this.tracking === 'lowValue' && newValue > this.highValue)
2378                                    newValue = this.applyMinMaxRange(this.highValue)
2379                                else if (
2380                                    this.tracking === 'highValue' &&
2381                                    newValue < this.lowValue
2382                                )
2383                                    newValue = this.applyMinMaxRange(this.lowValue)
2384                            }
2385                            newValue = this.applyMinMaxRange(newValue)
2386                            /* This is to check if we need to switch the min and max handles */
2387                            if (this.tracking === 'lowValue' && newValue > this.highValue) {
2388                                this.lowValue = this.highValue
2389                                this.applyLowValue()
2390                                this.applyModel()
2391                                this.updateHandles(this.tracking, this.maxH.rzsp)
2392                                this.updateAriaAttributes()
2393                                this.tracking = 'highValue'
2394                                this.minH.removeClass('rz-active')
2395                                this.maxH.addClass('rz-active')
2396                                if (this.options.keyboardSupport) this.focusElement(this.maxH)
2397                                valueChanged = true
2398                            } else if (
2399                                this.tracking === 'highValue' &&
2400                                newValue < this.lowValue
2401                            ) {
2402                                this.highValue = this.lowValue
2403                                this.applyHighValue()
2404                                this.applyModel()
2405                                this.updateHandles(this.tracking, this.minH.rzsp)
2406                                this.updateAriaAttributes()
2407                                this.tracking = 'lowValue'
2408                                this.maxH.removeClass('rz-active')
2409                                this.minH.addClass('rz-active')
2410                                if (this.options.keyboardSupport) this.focusElement(this.minH)
2411                                valueChanged = true
2412                            }
2413                        }
2414                    }
2415
2416                    if (this[this.tracking] !== newValue) {
2417                        this[this.tracking] = newValue
2418                        if (this.tracking === 'lowValue') this.applyLowValue()
2419                        else this.applyHighValue()
2420                        this.applyModel()
2421                        this.updateHandles(this.tracking, this.valueToPosition(newValue))
2422                        this.updateAriaAttributes()
2423                        valueChanged = true
2424                    }
2425
2426                    if (valueChanged) this.applyModel(true)
2427                },
2428
2429                applyMinMaxLimit: function(newValue) {
2430                    if (this.options.minLimit != null && newValue < this.options.minLimit)
2431                        return this.options.minLimit
2432                    if (this.options.maxLimit != null && newValue > this.options.maxLimit)
2433                        return this.options.maxLimit
2434                    return newValue
2435                },
2436
2437                applyMinMaxRange: function(newValue) {
2438                    var oppositeValue =
2439                            this.tracking === 'lowValue' ? this.highValue : this.lowValue,
2440                        difference = Math.abs(newValue - oppositeValue)
2441                    if (this.options.minRange != null) {
2442                        if (difference < this.options.minRange) {
2443                            if (this.tracking === 'lowValue')
2444                                return this.highValue - this.options.minRange
2445                            else return this.lowValue + this.options.minRange
2446                        }
2447                    }
2448                    if (this.options.maxRange != null) {
2449                        if (difference > this.options.maxRange) {
2450                            if (this.tracking === 'lowValue')
2451                                return this.highValue - this.options.maxRange
2452                            else return this.lowValue + this.options.maxRange
2453                        }
2454                    }
2455                    return newValue
2456                },
2457
2458                applyPushRange: function(newValue) {
2459                    var difference =
2460                            this.tracking === 'lowValue'
2461                                ? this.highValue - newValue
2462                                : newValue - this.lowValue,
2463                        minRange =
2464                            this.options.minRange !== null
2465                                ? this.options.minRange
2466                                : this.options.step,
2467                        maxRange = this.options.maxRange
2468                    // if smaller than minRange
2469                    if (difference < minRange) {
2470                        if (this.tracking === 'lowValue') {
2471                            this.highValue = Math.min(newValue + minRange, this.maxValue)
2472                            newValue = this.highValue - minRange
2473                            this.applyHighValue()
2474                            this.updateHandles(
2475                                'highValue',
2476                                this.valueToPosition(this.highValue)
2477                            )
2478                        } else {
2479                            this.lowValue = Math.max(newValue - minRange, this.minValue)
2480                            newValue = this.lowValue + minRange
2481                            this.applyLowValue()
2482                            this.updateHandles(
2483                                'lowValue',
2484                                this.valueToPosition(this.lowValue)
2485                            )
2486                        }
2487                        this.updateAriaAttributes()
2488                    } else if (maxRange !== null && difference > maxRange) {
2489                        // if greater than maxRange
2490                        if (this.tracking === 'lowValue') {
2491                            this.highValue = newValue + maxRange
2492                            this.applyHighValue()
2493                            this.updateHandles(
2494                                'highValue',
2495                                this.valueToPosition(this.highValue)
2496                            )
2497                        } else {
2498                            this.lowValue = newValue - maxRange
2499                            this.applyLowValue()
2500                            this.updateHandles(
2501                                'lowValue',
2502                                this.valueToPosition(this.lowValue)
2503                            )
2504                        }
2505                        this.updateAriaAttributes()
2506                    }
2507                    return newValue
2508                },
2509
2510                /**
2511                 * Apply the model values using scope.$apply.
2512                 * We wrap it with the internalChange flag to avoid the watchers to be called
2513                 */
2514                applyModel: function(callOnChange) {
2515                    this.internalChange = true
2516                    this.scope.$apply()
2517                    callOnChange && this.callOnChange()
2518                    this.internalChange = false
2519                },
2520
2521                /**
2522                 * Call the onStart callback if defined
2523                 * The callback call is wrapped in a $evalAsync to ensure that its result will be applied to the scope.
2524                 *
2525                 * @returns {undefined}
2526                 */
2527                callOnStart: function() {
2528                    if (this.options.onStart) {
2529                        var self = this,
2530                            pointerType = this.tracking === 'lowValue' ? 'min' : 'max'
2531                        this.scope.$evalAsync(function() {
2532                            self.options.onStart(
2533                                self.options.id,
2534                                self.scope.rzSliderModel,
2535                                self.scope.rzSliderHigh,
2536                                pointerType
2537                            )
2538                        })
2539                    }
2540                },
2541
2542                /**
2543                 * Call the onChange callback if defined
2544                 * The callback call is wrapped in a $evalAsync to ensure that its result will be applied to the scope.
2545                 *
2546                 * @returns {undefined}
2547                 */
2548                callOnChange: function() {
2549                    if (this.options.onChange) {
2550                        var self = this,
2551                            pointerType = this.tracking === 'lowValue' ? 'min' : 'max'
2552                        this.scope.$evalAsync(function() {
2553                            self.options.onChange(
2554                                self.options.id,
2555                                self.scope.rzSliderModel,
2556                                self.scope.rzSliderHigh,
2557                                pointerType
2558                            )
2559                        })
2560                    }
2561                },
2562
2563                /**
2564                 * Call the onEnd callback if defined
2565                 * The callback call is wrapped in a $evalAsync to ensure that its result will be applied to the scope.
2566                 *
2567                 * @returns {undefined}
2568                 */
2569                callOnEnd: function() {
2570                    if (this.options.onEnd) {
2571                        var self = this,
2572                            pointerType = this.tracking === 'lowValue' ? 'min' : 'max'
2573                        this.scope.$evalAsync(function() {
2574                            self.options.onEnd(
2575                                self.options.id,
2576                                self.scope.rzSliderModel,
2577                                self.scope.rzSliderHigh,
2578                                pointerType
2579                            )
2580                        })
2581                    }
2582                    this.scope.$emit('slideEnded')
2583                },
2584            }
2585
2586            return Slider
2587        }])
2588        .directive('rzslider', ['RzSlider', function(RzSlider) {
2589            'use strict'
2590
2591            return {
2592                restrict: 'AE',
2593                replace: true,
2594                scope: {
2595                    rzSliderModel: '=?',
2596                    rzSliderHigh: '=?',
2597                    rzSliderOptions: '&?',
2598                    rzSliderTplUrl: '@',
2599                },
2600
2601                /**
2602                 * Return template URL
2603                 *
2604                 * @param {jqLite} elem
2605                 * @param {Object} attrs
2606                 * @return {string}
2607                 */
2608                templateUrl: function(elem, attrs) {
2609                    //noinspection JSUnresolvedVariable
2610                    return attrs.rzSliderTplUrl || 'rzSliderTpl.html'
2611                },
2612
2613                link: function(scope, elem) {
2614                    scope.slider = new RzSlider(scope, elem) //attach on scope so we can test it
2615                },
2616            }
2617        }])
2618
2619    // IDE assist
2620
2621    /**
2622     * @name ngScope
2623     *
2624     * @property {number} rzSliderModel
2625     * @property {number} rzSliderHigh
2626     * @property {Object} rzSliderOptions
2627     */
2628
2629    /**
2630     * @name jqLite
2631     *
2632     * @property {number|undefined} rzsp rzslider label position position
2633     * @property {number|undefined} rzsd rzslider element dimension
2634     * @property {string|undefined} rzsv rzslider label value/text
2635     * @property {Function} css
2636     * @property {Function} text
2637     */
2638
2639    /**
2640     * @name Event
2641     * @property {Array} touches
2642     * @property {Event} originalEvent
2643     */
2644
2645    /**
2646     * @name ThrottleOptions
2647     *
2648     * @property {boolean} leading
2649     * @property {boolean} trailing
2650     */
2651
2652    module.run(['$templateCache', function($templateCache) {
2653        'use strict';
2654
2655        $templateCache.put('rzSliderTpl.html',
2656            "<div class=rzslider><span class=\"rz-bar-wrapper rz-left-out-selection\"><span class=rz-bar></span></span> <span class=\"rz-bar-wrapper rz-right-out-selection\"><span class=rz-bar></span></span> <span class=rz-bar-wrapper><span class=rz-bar></span></span> <span class=rz-bar-wrapper><span class=\"rz-bar rz-selection\" ng-style=barStyle></span></span> <span class=\"rz-pointer rz-pointer-min\" ng-style=minPointerStyle></span> <span class=\"rz-pointer rz-pointer-max\" ng-style=maxPointerStyle></span> <span class=\"rz-bubble rz-limit rz-floor\"></span> <span class=\"rz-bubble rz-limit rz-ceil\"></span> <span class=\"rz-bubble rz-model-value\"></span> <span class=\"rz-bubble rz-model-high\"></span> <span class=rz-bubble></span><ul ng-show=showTicks class=rz-ticks><li ng-repeat=\"t in ticks track by $index\" class=rz-tick ng-class=\"{'rz-selected': t.selected}\" ng-style=t.style ng-attr-uib-tooltip=\"{{ t.tooltip }}\" ng-attr-tooltip-placement={{t.tooltipPlacement}} ng-attr-tooltip-append-to-body=\"{{ t.tooltip ? true : undefined}}\"><span ng-if=\"t.value != null\" class=rz-tick-value ng-attr-uib-tooltip=\"{{ t.valueTooltip }}\" ng-attr-tooltip-placement={{t.valueTooltipPlacement}}>{{ t.value }}</span> <span ng-if=\"t.legend != null\" class=rz-tick-legend>{{ t.legend }}</span></li></ul></div>"
2657        );
2658
2659    }]);
2660
2661    return module.name
2662})
2663;

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.