PageSourceSearch

https://musclefuel-kw.com/js/roundslider.js

js musclefuel-kw.com collected 2026-10-02 16:03:19 UTC 55,300 bytes, 1,224 lines download raw bytes

1/*!
2 * roundSlider v1.3 | (c) 2015-2016, Soundar
3 * MIT license | http://roundsliderui.com/licence.html
4 */
5
6(function ($, window, undefined) {
7    "use strict";
8    /*jslint nomen: true */
9
10    var pluginName = "roundSlider";
11
12    // The plugin initialization
13    $.fn[pluginName] = function (options) {
14        return CreateRoundSlider.call(this, options, arguments);
15    };
16
17    RoundSlider.prototype = {
18
19        pluginName: pluginName,
20        version: "1.3",
21
22        // after the control initialization the updated default values
23        // are merged into the options
24        options: {},
25
26        // default properties of the plugin. while add a new property,
27        // that type should be included in the "_props:" for validation
28        defaults: {
29            min: 0,
30            max: 100,
31            step: 1,
32            value: null,
33            radius: 85,
34            width: 10,
35            handleSize: "+0",
36            startAngle: 0,
37            endAngle: "+360",
38            animation: true,
39            showTooltip: true,
40            editableTooltip: true,
41            readOnly: false,
42            disabled: false,
43            keyboardAction: true,
44            mouseScrollAction: false,
45            lineCap: "round",
46            sliderType: "default",
47            circleShape: "full",
48            handleShape: "round",
49
50            // events
51            beforeCreate: null,
52            create: null,
53            start: null,
54            drag: null,
55            change: null,
56            stop: null,
57            tooltipFormat: null
58        },
59        _props: function () {
60            return {
61                numberType: ["min", "max", "step", "radius", "width", "startAngle"],
62                booleanType: ["animation", "showTooltip", "editableTooltip", "readOnly", "disabled",
63                    "keyboardAction", "mouseScrollAction"],
64                stringType: ["sliderType", "circleShape", "handleShape", "lineCap"]
65            };
66        },
67        control: null,
68        _init: function () {
69            this._isBrowserSupport = this._isBrowserSupported();
70            this._isKO = false;
71            this._isAngular = false;
72            if (this.control.is("input")) {
73                this._isInputType = true;
74                this._hiddenField = this.control;
75                this.control = createElement("div");
76                this.control.insertAfter(this._hiddenField);
77                this.options.value = this._hiddenField.val() || this.options.value;
78                var that = this;
79                this._checkKO() && setTimeout(function () { that._checkKO(); }, 1);
80                this._checkAngular();
81            }
82            this._bindOnDrag = false;
83            var _updateOn = this._dataElement().attr("data-updateon");
84            if (typeof _updateOn == "string") { if (_updateOn == "drag") this._bindOnDrag = true; }
85            else if (this._isAngular) this._bindOnDrag = true;
86
87            this._onInit();
88        },
89        _onInit: function () {
90            this._initialize();
91            this._update();
92            this._render();
93        },
94        _initialize: function () {
95            if (!this._isBrowserSupport) return;
96            this._isReadOnly = false;
97            this._checkDataType();
98            this._refreshCircleShape();
99        },
100        _render: function () {
101            this.container = createElement("div.rs-container");
102            this.innerContainer = createElement("div.rs-inner-container");
103            this.block = createElement("div.rs-block rs-outer rs-border");
104            this.container.append(this.innerContainer.append(this.block));
105            this.control.addClass("rs-control").empty().append(this.container);
106
107            this._setRadius();
108            if (this._isBrowserSupport) {
109                this._createLayers();
110                this._setProperties();
111                this._setValue();
112                this._updateTooltipPos();
113                this._bindControlEvents("_bind");
114                this._checkIE();
115            }
116            else {
117                var msg = createElement("div.rs-msg");
118                msg.html(typeof this._throwError === "function" ? this._throwError() : this._throwError);
119                this.control.empty().addClass("rs-error").append(msg);
120                if (this._isInputType) this.control.append(this._dataElement());
121            }
122        },
123        _update: function () {
124            this._validateSliderType();
125            this._updateStartEnd();
126            this._validateStartEnd();
127            this._handle1 = this._handle2 = this._handleDefaults();
128            this._analyzeModelValue();
129            this._validateModelValue();
130        },
131        _createLayers: function () {
132            var padd = this.options.width, start = this._start, path;
133            path = createElement("div.rs-path rs-transition");
134
135            if (this._rangeSlider || this._showRange) {
136                this.block1 = path.clone().addClass("rs-range-color").rsRotate(start);
137                this.block2 = path.clone().addClass("rs-range-color").css("opacity", "0").rsRotate(start);
138                this.block3 = path.clone().addClass("rs-path-color").rsRotate(start);
139                this.block4 = path.addClass("rs-path-color").css({ "opacity": "1", "z-index": "1" }).rsRotate(start - 180);
140
141                this.block.append(this.block1, this.block2, this.block3, this.block4).addClass("rs-split");
142            }
143            else this.block.append(path.addClass("rs-path-color"));
144
145            this.lastBlock = createElement("span.rs-block").css({ "padding": padd });
146            this.innerBlock = createElement("div.rs-inner rs-bg-color rs-border");
147            this.lastBlock.append(this.innerBlock);
148            this.block.append(this.lastBlock);
149            this._appendHandle();
150            this._appendOverlay();
151            this._appendHiddenField();
152        },
153        _setProperties: function () {
154            this._updatePre();
155            this._setHandleShape();
156            this._addAnimation();
157            this._appendTooltip();
158            if (!this.options.showTooltip) this._removeTooltip();
159            if (this.options.disabled) this.disable();
160            else if (this.options.readOnly) this._readOnly(true);
161            if (this.options.mouseScrollAction) this._bindScrollEvents("_bind");
162        },
163        _updatePre: function () {
164            this._prechange = this._predrag = this.options.value;
165        },
166        _setValue: function () {
167            if (this._rangeSlider) {
168                this._setHandleValue(1);
169                this._setHandleValue(2);
170            }
171            else {
172                if (this._showRange) this._setHandleValue(1);
173                var index = (this.options.sliderType == "default") ? (this._active || 1) : parseFloat(this.bar.children().attr("index"));
174                this._setHandleValue(index);
175            }
176        },
177        _appendTooltip: function () {
178            if (this.container.children(".rs-tooltip").length !== 0) return;
179            this.tooltip = createElement("span.rs-tooltip rs-tooltip-text");
180            this.container.append(this.tooltip);
181            this._tooltipEditable();
182            this._updateTooltip();
183        },
184        _removeTooltip: function () {
185            if (this.container.children(".rs-tooltip").length == 0) return;
186            this.tooltip && this.tooltip.remove();
187        },
188        _tooltipEditable: function () {
189            if (!this.tooltip || !this.options.showTooltip) return;
190            var hook;
191            if (this.options.editableTooltip) {
192                this.tooltip.addClass("edit");
193                hook = "_bind";
194            }
195            else {
196                this.tooltip.removeClass("edit");
197                hook = "_unbind";
198            }
199            this[hook](this.tooltip, "click", this._editTooltip);
200        },
201        _editTooltip: function (e) {
202            if (!this.tooltip.hasClass("edit") || this._isReadOnly) return;
203            var border = parseFloat(this.tooltip.css("border-left-width")) * 2;
204            this.input = createElement("input.rs-input rs-tooltip-text").css({
205                height: this.tooltip.outerHeight() - border,
206                width: this.tooltip.outerWidth() - border
207            });
208            this.tooltip.html(this.input).removeClass("edit").addClass("hover");
209
210            this.input.focus().val(this._getTooltipValue(true));
211
212            this._bind(this.input, "blur", this._focusOut);
213            this._bind(this.input, "change", this._focusOut);
214        },
215        _focusOut: function (e) {
216            if (e.type == "change") {
217                this.options.value = this.input.val().replace("-", ",");
218                this._analyzeModelValue();
219                this._validateModelValue();
220                this._setValue();
221                this.input.val(this._getTooltipValue(true));
222            }
223            else {
224                this.tooltip.addClass("edit").removeClass("hover");
225                this._updateTooltip();
226            }
227            this._raiseEvent("change");
228        },
229        _setHandleShape: function () {
230            var type = this.options.handleShape;
231            this._handles().removeClass("rs-handle-dot rs-handle-square");
232            if (type == "dot") this._handles().addClass("rs-handle-dot");
233            else if (type == "square") this._handles().addClass("rs-handle-square");
234            else this.options.handleShape = this.defaults.handleShape;
235        },
236        _setHandleValue: function (index) {
237            this._active = index;
238            var handle = this["_handle" + index];
239            if (this.options.sliderType != "min-range") this.bar = this._activeHandleBar();
240            this._changeSliderValue(handle.value, handle.angle);
241        },
242        _setAnimation: function () {
243            if (this.options.animation) this._addAnimation();
244            else this._removeAnimation();
245        },
246        _addAnimation: function () {
247            if (this.options.animation) this.control.addClass("rs-animation");
248        },
249        _removeAnimation: function () {
250            this.control.removeClass("rs-animation");
251        },
252        _setRadius: function () {
253            var r = this.options.radius, d = r * 2;
254            var circleShape = this.options.circleShape, height = d, width = d;
255            this.container.removeClass().addClass("rs-container");
256
257            if (circleShape.indexOf("half") === 0) {
258                switch (circleShape) {
259                    case "half-top":
260                    case "half-bottom":
261                        height = r; width = d; break;
262                    case "half-left":
263                    case "half-right":
264                        height = d; width = r; break;
265                }
266                this.container.addClass(circleShape.replace("half-", "") + " half");
267            }
268            else if (circleShape.indexOf("quarter") === 0) {
269                height = width = r;
270                var s = circleShape.split("-");
271                this.container.addClass(s[0] + " " + s[1] + " " + s[2]);
272            }
273            else this.container.addClass("full " + circleShape);
274
275            var style = { "height": height, "width": width };
276            this.control.css(style);
277            this.container.css(style);
278        },
279        _border: function (seperator) {
280            if (seperator) return parseFloat(this._startLine.children().css("border-bottom-width"));
281            return parseFloat(this.block.css("border-top-width")) * 2;
282        },
283        _appendHandle: function () {
284            if (this._rangeSlider || !this._showRange) this._createHandle(1);
285            if (this._rangeSlider || this._showRange) this._createHandle(2);
286            this._startLine = this._addSeperator(this._start, "rs-start");
287            this._endLine = this._addSeperator(this._start + this._end, "rs-end");
288            this._refreshSeperator();
289        },
290        _addSeperator: function (pos, cls) {
291            var line = createElement("span.rs-seperator rs-border"), width = this.options.width, _border = this._border();
292            var lineWrap = createElement("span.rs-bar rs-transition " + cls).append(line).rsRotate(pos);
293            this.container.append(lineWrap);
294            return lineWrap;
295        },
296        _refreshSeperator: function () {
297            var bars = this._startLine.add(this._endLine), seperators = bars.children().removeAttr("style");
298            var opt = this.options, width = opt.width, _border = this._border(), size = width + _border;
299            if (opt.lineCap == "round" && opt.circleShape != "full") {
300                bars.addClass("rs-rounded");
301                seperators.css({ width: size, height: (size / 2) + 1 });
302                this._startLine.children().css("margin-top", -1).addClass(opt.sliderType == "min-range" ? "rs-range-color" : "rs-path-color");
303                this._endLine.children().css("margin-top", size / -2).addClass("rs-path-color");
304            }
305            else {
306                bars.removeClass("rs-rounded");
307                seperators.css({ "width": size, "margin-top": this._border(true) / -2 }).removeClass("rs-range-color rs-path-color");
308            }
309        },
310        _updateSeperator: function () {
311            this._startLine.rsRotate(this._start);
312            this._endLine.rsRotate(this._start + this._end);
313        },
314        _createHandle: function (index) {
315            var handle = createElement("div.rs-handle rs-move"), o = this.options, hs;
316            if ((hs = o.handleShape) != "round") handle.addClass("rs-handle-" + hs);
317            handle.attr({ "index": index, "tabIndex": "0" });
318
319            var id = this._dataElement()[0].id, id = id ? id + "_" : "";
320            var label = id + "handle" + (o.sliderType == "range" ? "_" + (index == 1 ? "start" : "end") : "");
321            handle.attr({ "role": "slider", "aria-label": label });     // WAI-ARIA support
322
323            var bar = createElement("div.rs-bar rs-transition").css("z-index", "7").append(handle).rsRotate(this._start);
324            bar.addClass(o.sliderType == "range" && index == 2 ? "rs-second" : "rs-first");
325            this.container.append(bar);
326            this._refreshHandle();
327
328            this.bar = bar;
329            this._active = index;
330            if (index != 1 && index != 2) this["_handle" + index] = this._handleDefaults();
331            this._bind(handle, "focus", this._handleFocus);
332            this._bind(handle, "blur", this._handleBlur);
333            return handle;
334        },
335        _refreshHandle: function () {
336            var hSize = this.options.handleSize, h, w, isSquare = true;
337            if (typeof hSize === "string" && isNumber(hSize)) {
338                if (hSize.charAt(0) === "+" || hSize.charAt(0) === "-") {
339                    try { hSize = eval(this.options.width + hSize.charAt(0) + Math.abs(parseFloat(hSize))); }
340                    catch (e) { console.warn(e); }
341                }
342                else if (hSize.indexOf(",")) {
343                    var s = hSize.split(",");
344                    if (isNumber(s[0]) && isNumber(s[1])) w = parseFloat(s[0]), h = parseFloat(s[1]), isSquare = false;
345                }
346            }
347            if (isSquare) h = w = isNumber(hSize) ? parseFloat(hSize) : this.options.width;
348            var diff = (this.options.width + this._border() - w) / 2;
349            this._handles().css({ height: h, width: w, "margin": -h / 2 + "px 0 0 " + diff + "px" });
350        },
351        _handleDefaults: function () {
352            return { angle: this._valueToAngle(this.options.min), value: this.options.min };
353        },
354        _handles: function () {
355            return this.container.children("div.rs-bar").find(".rs-handle");
356        },
357        _activeHandleBar: function (index) {
358            index = (index != undefined) ? index : this._active;
359            return $(this.container.children("div.rs-bar")[index - 1]);
360        },
361        _handleArgs: function (index) {
362            index = (index != undefined) ? index : this._active;
363            var _handle = this["_handle" + index];
364            return {
365                element: this._activeHandleBar(index).children(),
366                index: index,
367                isActive: index == this._active,
368                value: _handle ? _handle.value : null,
369                angle: _handle ? _handle.angle : null
370            };
371        },
372        _dataElement: function () {
373            return this._isInputType ? this._hiddenField : this.control;
374        },
375        _raiseEvent: function (event) {
376            var preValue = this["_pre" + event];
377            if (preValue !== this.options.value) {
378                this["_pre" + event] = this.options.value;
379                this._updateTooltip();
380                if ((event == "change") || (this._bindOnDrag && event == "drag")) this._updateHidden();
381                return this._raise(event, { value: this.options.value, preValue: preValue, "handle": this._handleArgs() });
382            }
383        },
384
385        // Events handlers
386        _elementDown: function (e) {
387            if (this._isReadOnly) return;
388            var $target = $(e.target);
389
390            if ($target.hasClass("rs-handle")) {
391                this._handleDown(e);
392            }
393            else {
394                var point = this._getXY(e), center = this._getCenterPoint();
395                var distance = getdistance(point, center);
396                var outerDistance = this.block.outerWidth() / 2;
397                var innerDistance = outerDistance - (this.options.width + this._border());
398
399                if (distance >= innerDistance && distance <= outerDistance) {
400                    e.preventDefault();
401                    var handle = this.control.find(".rs-handle.rs-focus"), angle, value;
402                    //if (handle.length == 0)
403                    this.control.attr("tabindex", "0").focus().removeAttr("tabindex");
404                    if ($target.hasClass("rs-seperator")) {
405                        value = $target.parent().hasClass("rs-start") ? this.options.min : this.options.max;
406                        angle = this._valueToAngle(value);
407                    }
408                    else {
409                        var d = this._getAngleValue(point, center);
410                        angle = d.angle, value = d.value;
411                    }
412                    if (this._rangeSlider) {
413                        handle = this.control.find(".rs-handle.rs-focus");
414                        if (handle.length == 1) this._active = parseFloat(handle.attr("index"));
415                        else this._active = (this._handle2.value - value) < (value - this._handle1.value) ? 2 : 1;
416                        this.bar = this._activeHandleBar();
417                    }
418
419                    this._changeSliderValue(value, angle);
420                    this._raiseEvent("change");
421                }
422            }
423        },
424        _handleDown: function (e) {
425            e.preventDefault();
426            var $target = $(e.target);
427            $target.focus();
428            this._removeAnimation();
429            this._bindMouseEvents("_bind");
430            this.bar = $target.parent();
431            this._active = parseFloat($target.attr("index"));
432            this._handles().removeClass("rs-move");
433            this._raise("start", { value: this.options.value, "handle": this._handleArgs() });
434        },
435        _handleMove: function (e) {
436            e.preventDefault();
437            var point = this._getXY(e), center = this._getCenterPoint();
438            var d = this._getAngleValue(point, center, true), angle, value;
439            angle = d.angle, value = d.value;
440
441            this._changeSliderValue(value, angle);
442            this._raiseEvent("drag");
443        },
444        _handleUp: function (e) {
445            this._handles().addClass("rs-move");
446            this._bindMouseEvents("_unbind");
447            this._addAnimation();
448            this._raiseEvent("change");
449            this._raise("stop", { value: this.options.value, "handle": this._handleArgs() });
450        },
451        _handleFocus: function (e) {
452            if (this._isReadOnly) return;
453            var $target = $(e.target);
454            this._handles().removeClass("rs-focus");
455            $target.addClass("rs-focus");
456            this.bar = $target.parent();
457            this._active = parseFloat($target.attr("index"));
458            if (this.options.keyboardAction) {
459                this._bindKeyboardEvents("_unbind");
460                this._bindKeyboardEvents("_bind");
461            }
462
463            // updates the class for change z-index
464            this.control.find("div.rs-bar").css("z-index", "7");
465            this.bar.css("z-index", "8");
466        },
467        _handleBlur: function (e) {
468            this._handles().removeClass("rs-focus");
469            if (this.options.keyboardAction) this._bindKeyboardEvents("_unbind");
470        },
471        _handleKeyDown: function (e) {
472            if (this._isReadOnly) return;
473            var key = e.keyCode;
474            if (key == 27) this._handles().blur();
475            if (!(key >= 35 && key <= 40)) return;
476            if (key >= 37 && key <= 40) this._removeAnimation();
477            var h = this["_handle" + this._active], val, ang;
478
479            e.preventDefault();
480            if (key == 38 || key == 37) val = this._round(this._limitValue(h.value + this.options.step));  // Up || Left Key
481            else if (key == 39 || key == 40) val = this._round(this._limitValue(h.value - this._getMinusStep(h.value))); // Right || Down Key
482            else if (key == 36) val = this._getKeyValue("Home"); // Home Key
483            else if (key == 35) val = this._getKeyValue("End"); // End Key
484
485            ang = this._valueToAngle(val);
486            this._changeSliderValue(val, ang);
487            this._raiseEvent("change");
488        },
489        _handleKeyUp: function (e) {
490            this._addAnimation();
491        },
492        _getMinusStep: function (val) {
493            if (val == this.options.max) {
494                var step = (this.options.max - this.options.min) % this.options.step;
495                return step == 0 ? this.options.step : step;
496            }
497            return this.options.step;
498        },
499        _getKeyValue: function (key) {
500            if (this._rangeSlider) {
501                if (key == "Home") return (this._active == 1) ? this.options.min : this._handle1.value;
502                else return (this._active == 1) ? this._handle2.value : this.options.max;
503            }
504            return (key == "Home") ? this.options.min : this.options.max;
505        },
506        _elementScroll: function (event) {
507            if (this._isReadOnly) return;
508            event.preventDefault();
509            var e = event.originalEvent || event, h, val, ang, delta;
510            delta = e.wheelDelta ? e.wheelDelta / 60 : (e.detail ? -e.detail / 2 : 0);
511            if (delta == 0) return;
512
513            this._updateActiveHandle(event);
514            h = this["_handle" + this._active];
515            val = h.value + (delta > 0 ? this.options.step : -this._getMinusStep(h.value));
516            val = this._limitValue(val);
517            ang = this._valueToAngle(val);
518
519            this._removeAnimation();
520            this._changeSliderValue(val, ang);
521            this._raiseEvent("change");
522            this._addAnimation();
523        },
524        _updateActiveHandle: function (e) {
525            var $target = $(e.target);
526            if ($target.hasClass("rs-handle") && $target.parent().parent()[0] == this.control[0]) {
527                this.bar = $target.parent();
528                this._active = parseFloat($target.attr("index"));
529            }
530            if (!this.bar.find(".rs-handle").hasClass("rs-focus")) this.bar.find(".rs-handle").focus();
531        },
532
533        // Events binding
534        _bindControlEvents: function (hook) {
535            this[hook](this.control, "mousedown", this._elementDown);
536            this[hook](this.control, "touchstart", this._elementDown);
537        },
538        _bindScrollEvents: function (hook) {
539            this[hook](this.control, "mousewheel", this._elementScroll);
540            this[hook](this.control, "DOMMouseScroll", this._elementScroll);
541        },
542        _bindMouseEvents: function (hook) {
543            this[hook]($(document), "mousemove", this._handleMove);
544            this[hook]($(document), "mouseup", this._handleUp);
545            this[hook]($(document), "mouseleave", this._handleUp);
546
547            // *** for Touch support *** //
548            this[hook]($(document), "touchmove", this._handleMove);
549            this[hook]($(document), "touchend", this._handleUp);
550            this[hook]($(document), "touchcancel", this._handleUp);
551        },
552        _bindKeyboardEvents: function (hook) {
553            this[hook]($(document), "keydown", this._handleKeyDown);
554            this[hook]($(document), "keyup", this._handleKeyUp);
555        },
556
557        // internal methods
558        _changeSliderValue: function (value, angle) {
559            var oAngle = this._oriAngle(angle), lAngle = this._limitAngle(angle);
560            if (!this._rangeSlider && !this._showRange) {
561
562                this["_handle" + this._active] = { angle: angle, value: value };
563                this.options.value = value;
564                this.bar.rsRotate(lAngle);
565                this._updateARIA(value);
566            }
567            else if ((this._active == 1 && oAngle <= this._oriAngle(this._handle2.angle)) ||
568                    (this._active == 2 && oAngle >= this._oriAngle(this._handle1.angle)) || this._invertRange) {
569
570                this["_handle" + this._active] = { angle: angle, value: value };
571                this.options.value = this._rangeSlider ? this._handle1.value + "," + this._handle2.value : value;
572                this.bar.rsRotate(lAngle);
573                this._updateARIA(value);
574
575                var dAngle = this._oriAngle(this._handle2.angle) - this._oriAngle(this._handle1.angle), o2 = "1", o3 = "0";
576                if (dAngle <= 180 && !(dAngle < 0 && dAngle > -180)) o2 = "0", o3 = "1";
577                this.block2.css("opacity", o2);
578                this.block3.css("opacity", o3);
579
580                (this._active == 1 ? this.block4 : this.block2).rsRotate(lAngle - 180);
581                (this._active == 1 ? this.block1 : this.block3).rsRotate(lAngle);
582            }
583        },
584        // WAI-ARIA support
585        _updateARIA: function (value) {
586            var min = this.options.min, max = this.options.max;
587            this.bar.children().attr({ "aria-valuenow": value });
588            if (this.options.sliderType == "range") {
589                var handles = this._handles();
590                handles.eq(0).attr({ "aria-valuemin": min });
591                handles.eq(1).attr({ "aria-valuemax": max });
592
593                if (this._active == 1) handles.eq(1).attr({ "aria-valuemin": value });
594                else handles.eq(0).attr({ "aria-valuemax": value });
595            }
596            else this.bar.children().attr({ "aria-valuemin": min, "aria-valuemax": max });
597        },
598        // Listener for KO binding
599        _checkKO: function () {
600            var _data = this._dataElement().data("bind");
601            if (typeof _data == "string" && typeof ko == "object") {
602                var _vm = ko.dataFor(this._dataElement()[0]);
603                if (typeof _vm == "undefined") return true;
604                var _all = _data.split(","), _handler;
605                for (var i = 0; i < _all.length; i++) {
606                    var d = _all[i].split(":");
607                    if ($.trim(d[0]) == "value") {
608                        _handler = $.trim(d[1]);
609                        break;
610                    }
611                }
612                if (_handler) {
613                    this._isKO = true;
614                    ko.computed(function () { this.option("value", _vm[_handler]()); }, this);
615                }
616            }
617        },
618        // Listener for Angular binding
619        _checkAngular: function () {
620            if (typeof angular == "object" && typeof angular.element == "function") {
621                this._ngName = this._dataElement().attr("ng-model");
622                if (typeof this._ngName == "string") {
623                    this._isAngular = true; var that = this;
624                    this._scope().$watch(this._ngName, function (newValue, oldValue) { that.option("value", newValue); });
625                }
626            }
627        },
628        _scope: function () {
629            return angular.element(this._dataElement()).scope();
630        },
631        _getXY: function (e) {
632            if (e.type.indexOf("mouse") == -1) e = (e.originalEvent || e).changedTouches[0];
633            return { x: e.pageX, y: e.pageY };
634        },
635        _getCenterPoint: function () {
636            var offset = this.block.offset(), center;
637            center = {
638                x: offset.left + (this.block.outerWidth() / 2),
639                y: offset.top + (this.block.outerHeight() / 2)
640            };
641            return center;
642        },
643        _getAngleValue: function (point, center, isDrag) {
644            var deg = Math.atan2(point.y - center.y, center.x - point.x);
645            var angle = (-deg / (Math.PI / 180));
646            if (angle < this._start) angle += 360;
647            angle = this._checkAngle(angle, isDrag);
648            return this._processStepByAngle(angle);;
649        },
650        _checkAngle: function (angle, isDrag) {
651            var o_angle = this._oriAngle(angle),
652                preAngle = this["_handle" + this._active].angle,
653                o_preAngle = this._oriAngle(preAngle);
654
655            if (o_angle > this._end) {
656                if (!isDrag) return preAngle;
657                angle = this._start + (o_preAngle <= this._end - o_preAngle ? 0 : this._end);
658            }
659            else if (isDrag) {
660                var d = this._handleDragDistance;
661                if (isNumber(d)) if (Math.abs(o_angle - o_preAngle) > d) return preAngle;
662            }
663            return angle;
664        },
665        _processStepByAngle: function (angle) {
666            var value = this._angleToValue(angle);
667            return this._processStepByValue(value);
668        },
669        _processStepByValue: function (value) {
670            var step = this.options.step, remain, currVal, nextVal, preVal, val, ang;
671            remain = (value - this.options.min) % step;
672            currVal = value - remain;
673            nextVal = this._limitValue(currVal + step);
674            preVal = this._limitValue(currVal - step);
675
676            if (value >= currVal) val = (value - currVal < nextVal - value) ? currVal : nextVal;
677            else val = (currVal - value > value - preVal) ? currVal : preVal;
678
679            val = this._round(val), ang = this._valueToAngle(val);
680            return { value: val, angle: ang };
681        },
682        _round: function (val) {
683            var s = this.options.step.toString().split(".");
684            return s[1] ? parseFloat(val.toFixed(s[1].length)) : Math.round(val);
685        },
686        _oriAngle: function (angle) {
687            var ang = angle - this._start;
688            if (ang < 0) ang += 360;
689            return ang;
690        },
691        _limitAngle: function (angle) {
692            if (angle > 360 + this._start) angle -= 360;
693            if (angle < this._start) angle += 360;
694            return angle;
695        },
696        _limitValue: function (value) {
697            if (value < this.options.min) value = this.options.min;
698            if (value > this.options.max) value = this.options.max;
699            return value;
700        },
701        _angleToValue: function (angle) {
702            var m = this.options, value;
703            value = (this._oriAngle(angle) / this._end) * (m.max - m.min) + m.min;
704            return value;
705        },
706        _valueToAngle: function (value) {
707            var m = this.options, angle;
708            angle = (((value - m.min) / (m.max - m.min)) * this._end) + this._start;
709            return angle;
710        },
711        _appendHiddenField: function () {
712            this._hiddenField = this._hiddenField || createElement("input");
713            this._hiddenField.attr({
714                "type": "hidden", "name": this._dataElement()[0].id || ""
715            });
716            this.control.append(this._hiddenField);
717            this._updateHidden();
718        },
719        _updateHidden: function () {
720            var val = this.options.value;
721            this._hiddenField.val(val);
722            if (this._isKO || this._isAngular) this._hiddenField.trigger("change");
723            if (this._isAngular) this._scope()[this._ngName] = val;
724        },
725        _updateTooltip: function () {
726            if (this.tooltip && !this.tooltip.hasClass("hover"))
727                this.tooltip.html(this._getTooltipValue());
728            this._updateTooltipPos();
729        },
730        _updateTooltipPos: function () {
731            this.tooltip && this.tooltip.css(this._getTooltipPos());
732        },
733        _getTooltipPos: function () {
734            var circleShape = this.options.circleShape, pos;
735            if (circleShape == "full" || circleShape == "pie" || circleShape.indexOf("custom") === 0)
736                return {
737                    "margin-top": -this.tooltip.outerHeight() / 2,
738                    "margin-left": -this.tooltip.outerWidth() / 2
739                };
740            else if (circleShape.indexOf("half") != -1) {
741                switch (circleShape) {
742                    case "half-top":
743                    case "half-bottom":
744                        pos = { "margin-left": -this.tooltip.outerWidth() / 2 }; break;
745                    case "half-left":
746                    case "half-right":
747                        pos = { "margin-top": -this.tooltip.outerHeight() / 2 }; break;
748                }
749                return pos;
750            }
751            return {};
752        },
753        _getTooltipValue: function (isNormal) {
754            if (this._rangeSlider) {
755                var p = this.options.value.split(",");
756                if (isNormal) return p[0] + " - " + p[1];
757                return this._tooltipValue(p[0], 1) + " - " + this._tooltipValue(p[1], 2);
758            }
759            if (isNormal) return this.options.value;
760            return this._tooltipValue(this.options.value);
761        },
762        _tooltipValue: function (value, index) {
763            var val = this._raise("tooltipFormat", { value: value, "handle": this._handleArgs(index) });
764            return (val != null && typeof val !== "boolean") ? val : value;
765        },
766        _validateStartAngle: function () {
767            var start = this.options.startAngle;
768            start = (isNumber(start) ? parseFloat(start) : 0) % 360;
769            if (start < 0) start += 360;
770            this.options.startAngle = start;
771            return start;
772        },
773        _validateEndAngle: function () {
774            var end = this.options.endAngle;
775            if (typeof end === "string" && isNumber(end) && (end.charAt(0) === "+" || end.charAt(0) === "-")) {
776                try { end = eval(this.options.startAngle + end.charAt(0) + Math.abs(parseFloat(end))); }
777                catch (e) { console.warn(e); }
778            }
779            end = (isNumber(end) ? parseFloat(end) : 360) % 360;
780            if (end <= this.options.startAngle) end += 360;
781            return end;
782        },
783        _refreshCircleShape: function () {
784            var circleShape = this.options.circleShape;
785            var circel_shapes = ["half-top", "half-bottom", "half-left", "half-right",
786                "quarter-top-left", "quarter-top-right", "quarter-bottom-right", "quarter-bottom-left",
787                "pie", "custom-half", "custom-quarter"];
788            var shape_codes = ["h1", "h2", "h3", "h4", "q1", "q2", "q3", "q4", "3/4", "ch", "cq"];
789
790            if (circel_shapes.indexOf(circleShape) == -1) {
791                var index = shape_codes.indexOf(circleShape);
792                if (index != -1) circleShape = circel_shapes[index];
793                else if (circleShape == "half") circleShape = "half-top";
794                else if (circleShape == "quarter") circleShape = "quarter-top-left";
795                else circleShape = "full";
796            }
797            this.options.circleShape = circleShape;
798        },
799        _appendOverlay: function () {
800            var shape = this.options.circleShape;
801            if (shape == "pie")
802                this._checkOverlay(".rs-overlay", 270);
803            else if (shape == "custom-half" || shape == "custom-quarter") {
804                this._checkOverlay(".rs-overlay1", 180);
805                if (shape == "custom-quarter")
806                    this._checkOverlay(".rs-overlay2", this._end);
807            }
808        },
809        _checkOverlay: function (cls, angle) {
810            var overlay = this.container.children(cls);
811            if (overlay.length == 0) {
812                overlay = createElement("div" + cls + " rs-transition rs-bg-color");
813                this.container.append(overlay);
814            }
815            overlay.rsRotate(this._start + angle);
816        },
817        _checkDataType: function () {
818            var m = this.options, i, prop, value, props = this._props();
819            // to check number datatype
820            for (i in props.numberType) {
821                prop = props.numberType[i], value = m[prop];
822                if (!isNumber(value)) m[prop] = this.defaults[prop];
823                else m[prop] = parseFloat(value);
824            }
825            // to check input string
826            for (i in props.booleanType) {
827                prop = props.booleanType[i], value = m[prop];
828                m[prop] = (value == "false") ? false : !!value;
829            }
830            // to check boolean datatype
831            for (i in props.stringType) {
832                prop = props.stringType[i], value = m[prop];
833                m[prop] = ("" + value).toLowerCase();
834            }
835        },
836        _validateSliderType: function () {
837            var type = this.options.sliderType.toLowerCase();
838            this._rangeSlider = this._showRange = false;
839            if (type == "range") this._rangeSlider = this._showRange = true;
840            else if (type.indexOf("min") != -1) {
841                this._showRange = true;
842                type = "min-range";
843            }
844            else type = "default";
845            this.options.sliderType = type;
846        },
847        _updateStartEnd: function () {
848            var circle = this.options.circleShape;
849            if (circle != "full") {
850                if (circle.indexOf("quarter") != -1) this.options.endAngle = "+90";
851                else if (circle.indexOf("half") != -1) this.options.endAngle = "+180";
852                else if (circle == "pie") this.options.endAngle = "+270";
853
854                if (circle == "quarter-top-left" || circle == "half-top") this.options.startAngle = 0;
855                else if (circle == "quarter-top-right" || circle == "half-right") this.options.startAngle = 90;
856                else if (circle == "quarter-bottom-right" || circle == "half-bottom") this.options.startAngle = 180;
857                else if (circle == "quarter-bottom-left" || circle == "half-left") this.options.startAngle = 270;
858            }
859        },
860        _validateStartEnd: function () {
861            this._start = this._validateStartAngle();
862            this._end = this._validateEndAngle();
863
864            var add = (this._start < this._end) ? 0 : 360;
865            this._end += add - this._start;
866        },
867        _analyzeModelValue: function () {
868            var val = this.options.value, min = this.options.min, max = this.options.max, last, t;
869            if (val instanceof Array) val = val.toString();
870            var parts = (typeof val == "string") ? val.split(",") : [val];
871
872            if (this._rangeSlider) {
873                if (typeof val == "string") {
874                    if (parts.length >= 2) t = (isNumber(parts[0]) ? parts[0] : min) + "," +
875                        (isNumber(parts[1]) ? parts[1] : max);
876                    else t = isNumber(parts[0]) ? min + "," + parts[0] : min + "," + min;
877                }
878                else t = isNumber(val) ? min + "," + val : min + "," + min;
879            }
880            else {
881                if (typeof val == "string") last = parts.pop(), t = isNumber(last) ? parseFloat(last) : min;
882                else t = isNumber(val) ? parseFloat(val) : min;
883            }
884            this.options.value = t;
885        },
886        _validateModelValue: function () {
887            var val = this.options.value;
888            if (this._rangeSlider) {
889                var parts = val.split(","), val1 = parseFloat(parts[0]), val2 = parseFloat(parts[1]);
890                val1 = this._limitValue(val1);
891                val2 = this._limitValue(val2);
892                if (!this._invertRange) if (val1 > val2) val2 = val1;
893
894                this._handle1 = this._processStepByValue(val1);
895                this._handle2 = this._processStepByValue(val2);
896                this.options.value = this._handle1.value + "," + this._handle2.value;
897            }
898            else {
899                var index = this._showRange ? 2 : (this._active || 1);
900                this["_handle" + index] = this._processStepByValue(this._limitValue(val));
901                if (this._showRange) this._handle1 = this._handleDefaults();
902                this.options.value = this["_handle" + index].value;
903            }
904        },
905
906        // common core methods
907        _isBrowserSupported: function () {
908            var properties = ["borderRadius", "WebkitBorderRadius", "MozBorderRadius",
909	            "OBorderRadius", "msBorderRadius", "KhtmlBorderRadius"];
910            for (var i = 0; i < properties.length; i++) {
911                if (document.body.style[properties[i]] !== undefined) return true;
912            }
913        },
914        _throwError: function () {
915            return "This browser doesn't support the border-radious property.";
916        },
917        _checkIE: function () {
918            var ua = window.navigator.userAgent;
919            if (ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0)
920                this.control.css({ "-ms-touch-action": "none", "touch-action": "none" });
921        },
922        _raise: function (event, args) {
923            var o = this.options, fn = o[event], val = true;
924            args = args || { value: o.value };
925            args["options"] = o;
926            if (fn) {
927                args["type"] = event;
928                if (typeof fn === "string") fn = window[fn];
929                if ($.isFunction(fn)) {
930                    val = fn.call(this, args);
931                    val = val === false ? false : val;
932                }
933            }
934            this.control.trigger($.Event ? $.Event(event, args) : event);
935            return val;
936        },
937        _bind: function (element, _event, handler) {
938            $(element).bind(_event, $proxy(handler, this));
939        },
940        _unbind: function (element, _event, handler) {
941            if ($.proxy) $(element).unbind(_event, $.proxy(handler, this));
942            else $(element).unbind(_event);
943        },
944        _getInstance: function () {
945            return $data(this._dataElement()[0], pluginName);
946        },
947        _removeData: function () {
948            var control = this._dataElement()[0];
949            $.removeData && $.removeData(control, pluginName);
950            if (control.id) delete window[control.id];
951        },
952        _destroyControl: function () {
953            if (this._isInputType) this._dataElement().insertAfter(this.control).attr("type", "text");
954            this.control.empty().removeClass("rs-control").height("").width("");
955            this._removeAnimation();
956            this._bindControlEvents("_unbind");
957        },
958
959        // methods to dynamic options updation (through option)
960        _updateWidth: function () {
961            this.lastBlock.css("padding", this.options.width);
962            this._refreshHandle();
963        },
964        _readOnly: function (bool) {
965            this._isReadOnly = bool;
966            this.container.removeClass("rs-readonly");
967            if (bool) this.container.addClass("rs-readonly");
968        },
969
970        // get & set for the properties
971        _get: function (property) {
972            return this.options[property];
973        },
974        _set: function (property, value) {
975            var props = this._props();
976            if ($.inArray(property, props.numberType) != -1) {          // to check number datatype
977                if (!isNumber(value)) return;
978                value = parseFloat(value);
979            }
980            else if ($.inArray(property, props.booleanType) != -1) {    // to check boolean datatype
981                value = (value == "false") ? false : !!value;
982            }
983            else if ($.inArray(property, props.stringType) != -1) {     // to check input string
984                value = value.toLowerCase();
985            }
986
987            if (this.options[property] == value) return;
988            this.options[property] = value;
989            switch (property) {
990                case "startAngle":
991                case "endAngle":
992                    this._validateStartEnd();
993                    this._updateSeperator();
994                    this._appendOverlay();
995                case "min":
996                case "max":
997                case "step":
998                case "value":
999                    this._analyzeModelValue();
1000                    this._validateModelValue();
1001                    this._setValue();
1002                    this._updatePre();
1003                    this._updateHidden();
1004                    this._updateTooltip();
1005                    break;
1006                case "radius":
1007                    this._setRadius();
1008                    this._updateTooltipPos();
1009                    break;
1010                case "width":
1011                    this._removeAnimation();
1012                    this._updateWidth();
1013                    this._updateTooltipPos();
1014                    this._addAnimation();
1015                    this._refreshSeperator();
1016                    break;
1017                case "handleSize":
1018                    this._refreshHandle();
1019                    break;
1020                case "handleShape":
1021                    this._setHandleShape();
1022                    break;
1023                case "animation":
1024                    this._setAnimation();
1025                    break;
1026                case "showTooltip":
1027                    this.options.showTooltip ? this._appendTooltip() : this._removeTooltip();
1028                    break;
1029                case "editableTooltip":
1030                    this._tooltipEditable();
1031                    this._updateTooltipPos();
1032                    break;
1033                case "disabled":
1034                    this.options.disabled ? this.disable() : this.enable();
1035                    break;
1036                case "readOnly":
1037                    this.options.readOnly ? this._readOnly(true) : (!this.options.disabled && this._readOnly(false));
1038                    break;
1039                case "mouseScrollAction":
1040                    this._bindScrollEvents(this.options.mouseScrollAction ? "_bind" : "_unbind");
1041                    break;
1042                case "lineCap":
1043                    this._refreshSeperator();
1044                    break;
1045                case "circleShape":
1046                    this._refreshCircleShape();
1047                    if (this.options.circleShape == "full") {
1048                        this.options.startAngle = 0;
1049                        this.options.endAngle = "+360";
1050                    }
1051                case "sliderType":
1052                    this._destroyControl();
1053                    this._onInit();
1054                    break;
1055            }
1056            return this;
1057        },
1058
1059        // public methods
1060        option: function (property, value) {
1061            if (!this._getInstance() || !this._isBrowserSupport) return;
1062            if ($isPlainObject(property)) {
1063                if (property["min"] !== undefined || property["max"] !== undefined) {
1064                    if (property["min"] !== undefined) {
1065                        this.options.min = property["min"];
1066                        delete property["min"];
1067                    }
1068                    if (property["max"] !== undefined) {
1069                        this.options.max = property["max"];
1070                        delete property["max"];
1071                    }
1072                    if (property["value"] == undefined) {
1073                        this._set("value", this.options.value);
1074                    }
1075                }
1076                for (var prop in property) {
1077                    this._set(prop, property[prop]);
1078                }
1079            }
1080            else if (property && typeof property == "string") {
1081                if (value === undefined) return this._get(property);
1082                this._set(property, value);
1083            }
1084            return this;
1085        },
1086        getValue: function (index) {
1087            if (this.options.sliderType == "range" && isNumber(index)) {
1088                var i = parseFloat(index);
1089                if (i == 1 || i == 2)
1090                    return this["_handle" + i].value;
1091            }
1092            return this._get("value");
1093        },
1094        setValue: function (value, index) {
1095            if (isNumber(value)) {
1096                if (isNumber(index)) {
1097                    if (this.options.sliderType == "range") {
1098                        var i = parseFloat(index), val = parseFloat(value);
1099                        if (i == 1) value = val + "," + this._handle2.value;
1100                        else if (i == 2) value = this._handle1.value + "," + val;
1101                    }
1102                    else if (this.options.sliderType == "default") this._active = index;
1103                }
1104                this._set("value", value);
1105            }
1106        },
1107        disable: function () {
1108            this.options.disabled = true;
1109            this.container.addClass("rs-disabled");
1110            this._readOnly(true);
1111        },
1112        enable: function () {
1113            this.options.disabled = false;
1114            this.container.removeClass("rs-disabled");
1115            if (!this.options.readOnly) this._readOnly(false);
1116        },
1117        destroy: function () {
1118            if (!this._getInstance()) return;
1119            this._destroyControl();
1120            this._removeData();
1121            if (this._isInputType) this.control.remove();
1122        }
1123    };
1124
1125    $.fn.rsRotate = function (degree) {
1126        return setTransform(this, degree);
1127    }
1128
1129    if (typeof $.fn.outerHeight == "undefined") {
1130        $.fn.outerHeight = function () { return this[0].offsetHeight; }
1131        $.fn.outerWidth = function () { return this[0].offsetWidth; }
1132    }
1133    if (typeof $.fn.hasClass === "undefined") {
1134        $.fn.hasClass = function (name) {
1135            return this[0].className.split(" ").indexOf(name) !== -1;
1136        }
1137    }
1138    if (typeof $.fn.offset === "undefined") {
1139        $.fn.offset = function () {
1140            return { left: this[0].offsetLeft, top: this[0].offsetTop };
1141        }
1142    }
1143
1144    function $proxy(fn, that) {
1145        if (typeof $.proxy === "function") return $.proxy(fn, that);
1146        return function (e) { fn.call(that, e); };
1147    }
1148    function $data(ele, name, data) {
1149        if (typeof $.data === "function") return $.data(ele, name, data);
1150        else if (!data) return $(ele).hasClass("rs-control");
1151    }
1152    function $isPlainObject(obj) {
1153        if (typeof $.isPlainObject === "function") return $.isPlainObject(obj);
1154        else {
1155            var str = JSON.stringify(obj);
1156            return typeof obj === "object" && obj.length === undefined &&
1157            str.length > 2 && str.substr(0, 1) === "{" && str.substr(str.length - 1) === "}";
1158        }
1159    }
1160
1161    //core functions
1162    function isNumber(number) {
1163        number = parseFloat(number);
1164        return typeof number === "number" && !isNaN(number);
1165    }
1166    function createElement(tag) {
1167        var t = tag.split('.');
1168        return $(document.createElement(t[0])).addClass(t[1] || "");
1169    }
1170    function getdistance(p1, p2) {
1171        return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
1172    }
1173    function setTransform(control, value) {
1174        control.css('-webkit-transform', "rotate(" + value + "deg)");
1175        control.css('-moz-transform', "rotate(" + value + "deg)");
1176        control.css('-ms-transform', "rotate(" + value + "deg)");
1177        control.css('-o-transform', "rotate(" + value + "deg)");
1178        control.css('transform', "rotate(" + value + "deg)");
1179        return control;
1180    }
1181
1182    // The plugin constructor
1183    function RoundSlider(control, options) {
1184        if (control.id) window[control.id] = this;
1185        this.control = $(control);
1186
1187        // the options value holds the updated defaults value
1188        this.options = $.extend({}, this.defaults, options);
1189        if (this._raise("beforeCreate") !== false) {
1190            this._init();
1191            this._raise("create");
1192        }
1193        else this._removeData();
1194    }
1195
1196    // The plugin wrapper, prevents multiple instantiations
1197    function CreateRoundSlider(options, args) {
1198
1199        for (var i = 0; i < this.length; i++) {
1200            var that = this[i], instance = $data(that, pluginName);
1201            if (!instance) {
1202                $data(that, pluginName, new RoundSlider(that, options));
1203            }
1204            else if ($isPlainObject(options)) {
1205                if (typeof instance.option === "function") instance.option(options);
1206                else if (that.id && window[that.id] && typeof window[that.id].option === "function") {
1207                    window[that.id].option(options);
1208                }
1209            }
1210            else if (typeof options === "string") {
1211                if (typeof instance[options] === "function") {
1212                    if ((options === "option" || options.indexOf("get") === 0) && args[2] === undefined) {
1213                        return instance[options](args[1]);
1214                    }
1215                    instance[options](args[1], args[2]);
1216                }
1217            }
1218        }
1219        return this;
1220    }
1221
1222    $.fn[pluginName].prototype = RoundSlider.prototype;
1223
1224})(jQuery, window);

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.