# Source: ui/slider.reel/slider.js

    /*global require, exports, console, MontageElement */

    /**
        @module "montage/ui/native/input-range.reel"
    */

    var Control = require("ui/control").Control,
        TranslateComposer = require("../../composer/translate-composer").TranslateComposer,
        KeyComposer = require("../../composer/key-composer").KeyComposer,
        Map = require("collections/map"),
        WeakMap = require("collections/weak-map"),
        MONTAGE_SLIDER_THUMB_CLASS = "montage-Slider--thumb";

    /**
     * Wraps the a &lt;input type="range"> element with binding support for the element's standard attributes.
       @class module:"montage/ui/native/input-range.reel".InputRange
       @extends module:montage/ui/text-input.TextInput
     */
    var Slider = exports.Slider = Control.specialize({
        /**
         * @private
         */
        constructor: {
            value: function Slider() {
                Control.constructor.call(this); // super
                //this is so that when we read properties from the dom they are not overwritten
                this._propertyNamesUsed = {};
                this._values = [50];

                this._isThumbElementTranslating = new WeakMap();
                this._percentageValues = [];
                this._previousPercentageValues = [];

                this.addOwnPropertyChangeListener("_sliderMagnitude", this);
                this.addOwnPropertyChangeListener("_min", this);
                this.addOwnPropertyChangeListener("_max", this);
                this.addOwnPropertyChangeListener("_value", this);
                this.addOwnPropertyChangeListener("values", this);
                this.addOwnPropertyChangeListener("_step", this);
                this.addOwnPropertyChangeListener("axis", this);

                //this._values.addRangeChangeListener(this, "values");
                // this._values.addRangeChangeListener(this);
                this.addRangeAtPathChangeListener("_values",this);

            }
        },

        handleValuesRangeChange: {
            value: function (plus, minus, index) {
                this.needsDraw = true;
            }
        },
        handleRangeChange: {
            value: function (plus, minus, index) {
                this.handlePropertyChange(plus[0], "values", this);
                //this.needsDraw = true;
            }
        },

        /**
         * @private
         */
        _orientation: {value: "horizontal"},

        /**
         * Slider's orientation is horizontal by default,
         * can be overridden by setting this property,
         * isn't auto-responsive due to inability to react to parent container dimension changes.
         *
         * @property {String} orientation
         */
        orientation: {
            get: function () {
                return this._orientation;
            },
            set: function (orientation) {
                if (this._orientation !== orientation) {
                    this._orientation = orientation;
                    this.needsDraw = true;
                }
            }
        },

        thumbElement: {
            get: function() {
                return this.thumbElements[0];
            }
        },
        _spacer: {
            value: void 0,
        },
        thumbWrappers: {
            value: void 0,
        },
        thumbElements: {
            value: void 0,
        },
        trackElements: {
            value: void 0,
        },
        _values: {
            value: void 0,
        },
        values: {
            get: function() {
                return this._values || (this._values = [50]);
            },
            set: function (values) {
                if (this._values !== values) {
                    this._values = values;
                    this.needsDraw = true;
                }
            }
        },
        _percentageValues: {
            value: void 0,
        },
        _previousPercentageValues: {
            value: void 0,
        },
        _translateComposers: {
            value: void 0,
        },
        _spacerMarginEnd: {
            value: void 0,
        },
        enterDocument: {
            value: function (firstTime) {
                this.super(firstTime);

                if (firstTime) {

                    if(this.hasStandardElement) {
                        this.element.addEventListener('input', this);
                        this.element.addEventListener('change', this);

                        // read initial values from the input type=range
                        var used = this._propertyNamesUsed;
                        // if (!used._min) {
                        //     this.min = this.element.getAttribute('min') || this._min;
                        // }
                        // if (!used._max) {
                        //     this.max = this.element.getAttribute('max') || this._max;
                        // }
                        // if (!used._step) {
                        //     this.step = this.element.getAttribute('step') || this._step;
                        // }

                        if (!used._value) {
                            this.value = this.element.getAttribute('value') || this._value;
                        }
                        delete this._propertyNamesUsed;

                    }
                    else {
                        var isHorizontal = (this.orientation === "horizontal");

                        this.thumbWrappers= [];
                        this.thumbElements = [];
                        this.trackElements = [];
                        var ownerDocument = this._element.ownerDocument,
                            fragment = ownerDocument.createDocumentFragment(),
                            spacer = this._spacer = this._element.firstElementChild,
                            dimensionLength = this._dimensionLength,
                            i=0, iThumbElement, offset = 0, iDimension = 0, iThumbWrapper, iTrackElement, iThumbElementWithClass;

                        while((iThumbElement = spacer.firstElementChild)) {
                            //If iThumbElement has no childElement, it got to be the thumb
                            if(!iThumbElement.firstElementChild) {
                                //If it doesn't have the required flag MONTAGE-SLIDER-THUMB-CLASS
                                //We'll gladly fix it, but that's as far as we can go
                                if(!iThumbElement.classList.contains(MONTAGE_SLIDER_THUMB_CLASS)) {
                                    iThumbElement.classList.add(MONTAGE_SLIDER_THUMB_CLASS);
                                }
                                iThumbElementWithClass = iThumbElement;
                            }
                            else {
                                iThumbElementWithClass = iThumbElement.getElementsByClassName(MONTAGE_SLIDER_THUMB_CLASS)[0];
                                if(!iThumbElementWithClass) {
                                    throw new Error("Slider couldn't identify a thumb element with "+MONTAGE_SLIDER_THUMB_CLASS+" class");
                                }
                            }

                            iThumbWrapper = ownerDocument.createElement("div");
                            iThumbWrapper.className = "montage-Slider--thumbWrapper";

                            iTrackElement = ownerDocument.createElement("div");
                            iTrackElement.className = "montage-Slider--track";
                            iTrackElement.setAttribute("data-montage-index",i);

                            iDimension = isHorizontal ? iThumbElementWithClass.offsetWidth : iThumbElementWithClass.offsetHeight;
                            //If the thumb has no size, or if it's horizontak and occupy the whole width, we're stepping in
                            if(iDimension === 0 || (isHorizontal && iDimension === spacer.offsetWidth)) {
                                iThumbElementWithClass.classList.add("montage-Slider-thumb--default");
                            }

                            iThumbElement.parentNode.removeChild(iThumbElement);
                            iThumbWrapper.appendChild(iThumbElement);
                            fragment.appendChild(iTrackElement);
                            fragment.appendChild(iThumbWrapper);
                            this.trackElements.push(iTrackElement);
                            this.thumbWrappers.push(iThumbWrapper);
                            this.thumbElements.push(iThumbElementWithClass);

                            i++;
                        }

                        //Last track element:
                        iTrackElement = ownerDocument.createElement("div");
                        iTrackElement.className = "montage-Slider--track";
                        fragment.appendChild(iTrackElement);
                        this.trackElements.push(iTrackElement);

                        spacer.appendChild(fragment);

                        i = 0;
                        while((iThumbWrapper = this.thumbWrappers[i])) {
                            iThumbElement = this.thumbElements[i];

                            iDimension = isHorizontal ? iThumbElement.offsetWidth : iThumbElement.offsetHeight;
                            // //If the thumb has no size, or if it's horizontak and occupy the whole width, we're stepping in
                            // if(iDimension === 0 || (isHorizontal && iDimension === spacer.offsetWidth)) {
                            //     iThumbElement.classList.add("montage-Slider-thumb--default");
                            // }

                            /* marginLeft / marginTop must be the width of all previous thumbs */
                            if (isHorizontal) {
                                iThumbWrapper.style.marginLeft = offset + "px";
                            } else {
                                iThumbWrapper.style.marginTop = offset + "px";
                            }

                            offset += iDimension;
                            i++;
                        }

                        // this._thumbWidth = offset;
                        if(isHorizontal) {
                            spacer.style.marginRight = (this._spacerMarginEnd = offset) + "px";
                        }
                        else {
                            spacer.style.marginBottom = (this._spacerMarginEnd = offset) + "px";
                        }
                    }

                    // check for transform support. This should really be central and soon not needed anymore
                    if("webkitTransform" in this.element.style) {
                        this._transform = "webkitTransform";
                    } else if("MozTransform" in this.element.style) {
                        this._transform = "MozTransform";
                    } else if("oTransform" in this.element.style) {
                        this._transform = "oTransform";
                    } else {
                        this._transform = "transform";
                    }

                    this.element.setAttribute("role", "slider");

                    //Loosk like this should be 0. And when there are multiple thumbs then it should be -1 and each thumb should have a tabIndex of 0
                    this.element.tabIndex = "-1";

                }
            }
        },

        // @todo: Without prepareForActivationEvents, the _translateComposer does not work
        prepareForActivationEvents: {
            value: function () {
                this.super();

                if(!this.hasStandardElement) {

                    var thumbWrappers = this.thumbWrappers;
                    if(thumbWrappers && thumbWrappers.length > 0) {

                        if(!this._startTranslateValues) {
                            this._startTranslateValues = new Array(thumbWrappers.length);
                        }

                        if(!this._startValues) {
                            this._startValues = new Array(thumbWrappers.length);
                        }

                        this._translateComposers = new Map();

                        for(var i=0, iThumbElement, iTranslateComposer;(iThumbElement = thumbWrappers[i]);i++) {

                            //Setting up our TranslateComposer
                            iTranslateComposer = new TranslateComposer();
                            this._translateComposers.set(iTranslateComposer,i);
                            iTranslateComposer.identifier = "thumb-"+i;
                            iTranslateComposer.axis = this.orientation;
                            iTranslateComposer.hasMomentum = false;

                            this.addComposerForElement(iTranslateComposer, iThumbElement.firstChild);
                            iTranslateComposer.addEventListener('translateStart', this, false);
                            iTranslateComposer.addEventListener('translate', this, false);
                            iTranslateComposer.addEventListener('translateEnd', this, false);
                        }

                        //We're missing pageUp and pageDown that would bring slider to max/min
                        this._upKeyComposer = KeyComposer.createKey(this, "up", "increase");
                        this._downKeyComposer = KeyComposer.createKey(this, "down", "decrease");
                        this._rightKeyComposer = KeyComposer.createKey(this, "right", "increase");
                        this._leftKeyComposer = KeyComposer.createKey(this, "left", "decrease");

                        this._upKeyComposer.addEventListener("keyPress", this, false);
                        this._downKeyComposer.addEventListener("keyPress", this, false);
                        this._leftKeyComposer.addEventListener("keyPress", this, false);
                        this._rightKeyComposer.addEventListener("keyPress", this, false);

                    }
                }
            }
        },

        _previousPercentage: {
            value: null
        },
        _dimensionLength : {
            get: function() {
                var dimensionLength,
                    computedStyle = window.getComputedStyle(this._element);

                if (this.orientation === this._VERTICAL) {
                    dimensionLength = this._spacer.offsetHeight -
                        parseFloat(computedStyle.getPropertyValue("padding-top")) -
                            parseFloat(computedStyle.getPropertyValue("padding-bottom"));
                } else {
                    dimensionLength = this._spacer.offsetWidth -
                        parseFloat(computedStyle.getPropertyValue("padding-left")) -
                            parseFloat(computedStyle.getPropertyValue("padding-right"));
                }

                return dimensionLength;
            }
        },
        _VERTICAL: {
            value: "vertical"
        },
        _PERCENT_UNIT: {
            value: "%"
        },
        _PIXEL_UNIT: {
            value: "px"
        },
        _TRANSLATE_RESET: {
            value: "translate3d(0,0,0)"
        },
        _TRANSLATE_VERTICAL_PREFIX: {
            value: "translate3d(0,"
        },
        _TRANSLATE_VERTICAL_SUFFIX: {
            value: "px,0)"
        },
        _TRANSLATE_HORIZONTAL_PREFIX: {
            value: "translate3d("
        },
        _TRANSLATE_HORIZONTAL_SUFFIX: {
            value: "px,0,0)"
        },
        _drawThumbElement: {
            value: function (thumbElementWrapper, thumbElement, index, isVertical, sliderMagnitude, length, cumulatedThumbSize, thumbElementOffsetSize) {
                var percent = this._percentageValueAt(index), position, positionString, trackElement = this.trackElements[index];

                if(isVertical) {
                    if (this._isThumbElementTranslating.get(thumbElementWrapper)) {
                        position = (this._percentageValueAt(index) - this._previousPercentageValues[index]) * sliderMagnitude * 0.01;
                        positionString = this._TRANSLATE_VERTICAL_PREFIX;
                        positionString += position;
                        positionString += this._TRANSLATE_VERTICAL_SUFFIX;
                        thumbElementWrapper.style[this._transform] = positionString;
                    } else {
                        thumbElementWrapper.style.top = percent + this._PERCENT_UNIT;
                        delete thumbElementWrapper.style.left;
                        thumbElementWrapper.style[this._transform] = this._TRANSLATE_RESET;
                        this._previousPercentageValues[index] = this._percentageValueAt(index);
                    }

                    var trackElemenTopPercent = index === 0 ? 0 : this._percentageValueAt(index-1),
                        height = index ? percent-this._percentageValueAt(index-1) : percent;

                    trackElement.style.top = trackElemenTopPercent+this._PERCENT_UNIT;
                    trackElement.style.marginTop = cumulatedThumbSize+this._PIXEL_UNIT;

                    trackElement.style.height = height+this._PERCENT_UNIT;

                    //Last track part if at the end
                    if((index+1) === length) {
                        trackElement = this.trackElements[index+1];
                        //We need the size of user-land element.
                        trackElement.style.top = percent+this._PERCENT_UNIT;
                        trackElement.style.marginTop = (cumulatedThumbSize + thumbElementOffsetSize)+this._PIXEL_UNIT;
                        trackElement.style.height = 100-percent+this._PERCENT_UNIT;
                    }

                }
                else {

                    if (this._isThumbElementTranslating.get(thumbElementWrapper)) {
                        position = (this._percentageValueAt(index) - this._previousPercentageValues[index]) * sliderMagnitude * 0.01;

                        positionString = this._TRANSLATE_HORIZONTAL_PREFIX;
                        positionString += position;
                        positionString += this._TRANSLATE_HORIZONTAL_SUFFIX;
                        thumbElementWrapper.style[this._transform] = positionString;
                    } else {
                        thumbElementWrapper.style.left = percent+this._PERCENT_UNIT;
                        delete thumbElementWrapper.style.top;
                        thumbElementWrapper.style[this._transform] = this._TRANSLATE_RESET;
                        this._previousPercentageValues[index] = this._percentageValueAt(index);
                    }

                    var trackElementLeftPercent = index === 0 ? 0 : this._percentageValueAt(index-1),
                        width = index ? percent-this._percentageValueAt(index-1) : percent;

                    trackElement.style.left = trackElementLeftPercent+this._PERCENT_UNIT;
                    trackElement.style.marginLeft = cumulatedThumbSize+this._PIXEL_UNIT;

                    trackElement.style.width = width+this._PERCENT_UNIT;

                    //Last track part if at the end
                    if((index+1) === length) {
                        trackElement = this.trackElements[index+1];
                        //We need the size of user-land element.
                        trackElement.style.left = percent+this._PERCENT_UNIT;
                        trackElement.style.marginLeft = (cumulatedThumbSize + thumbElementOffsetSize)+this._PIXEL_UNIT;
                        trackElement.style.width = 100-percent+this._PERCENT_UNIT;
                    }

                }

            }
        },
        draw: {
            value: function () {
                var value = this.value;

                if(!this.hasStandardElement) {
                    //console.log("this._values is ", this._values);
                    var isVertical = (this.orientation === this._VERTICAL),
                        sliderMagnitude = isVertical ? this._spacer.offsetHeight: this._spacer.offsetWidth;

                    for(var i=0, iThumbElementWrapper, iThumbElement, iThumbElementOffsetSize, countI = this.thumbWrappers.length, cumulatedThumbSize = 0;(iThumbElementWrapper = this.thumbWrappers[i]);i++) {
                        iThumbElement = this.thumbElements[i];
                        iThumbElementOffsetSize = isVertical ? iThumbElement.offsetHeight : iThumbElement.offsetWidth;
                        this._drawThumbElement(iThumbElementWrapper,iThumbElement, i,isVertical,sliderMagnitude, countI, cumulatedThumbSize, iThumbElementOffsetSize);
                        cumulatedThumbSize += iThumbElementOffsetSize;
                    }
                    this.element.setAttribute("aria-valuemax", this.max);
                    this.element.setAttribute("aria-valuemin", this.min);
                    this.element.setAttribute("aria-valuenow", value);
                    this.element.setAttribute("aria-orientation", this.orientation);
                }
                else {
                    if (value !== this.element.value) {
                        this.element.value = (value === null || value === undefined ? '' : value);
                    }
                    this.element.setAttribute("max", this.max);
                    this.element.setAttribute("min", this.min);
                }
            }
        },

        // Event Handlers

        acceptsActiveTarget: {
            value: true
        },

        _isThumbElementTranslating: {
            value: void 0
        },
        _startTranslateValues: {
            value: void 0
        },
        _startValues: {
            value: void 0
        },
        handleTranslateStart: {
            value: function (e) {
                this.active = true;
                var index = this._translateComposers.get(e.target);
                this._currentThumbIndex = index;
                if(this.orientation === this._VERTICAL) {
                    this._startTranslateValues[index] = e.translateY;
                } else {
                    this._startTranslateValues[index]= e.translateX;
                }
                this._startValues[index] = this.values[index]||0;
            }
        },

        handleTranslate: {
            value: function (event) {
                var index = this._translateComposers.get(event.target),
                    sliderMagnitude = this._dimensionLength,
                    translate;
                    //sliderMagnitude = this._calculateSliderMagnitude();
                this._currentThumbIndex = index;
                if(this.orientation === this._VERTICAL) {
                    //this.value = this._startValues[index] + ((this._startTranslateValues[index] - event.translateY) / this._sliderMagnitude) * (this._max - this._min);
                    translate = event.translateY;
                } else {
                    translate = event.translateX;
                }
                    // var max = this.values[index+1] || this._max,
                    //     min = this.values[index-1] || this._min,
                    //     diff = event.translateX - this._startTranslateValues[index];
                    //
                    // if(diff < min) diff = min;
                    // else if(diff > max) diff = max;
                    var max = this._max,
                        min = this._min,
                        value;
                    value = this._startValues[index] + ((translate - this._startTranslateValues[index]) / sliderMagnitude) * (max - min);
                    max = this.values[index+1];
                    max = (typeof max === "number" ? max : this._max);
                    min = this.values[index-1];
                    min = (typeof min === "number" ? min : this._min);
                    if(value <= min) {
                        value = min;
                    } else if(value > max) {
                        value = max;
                    }
                    this.value = value;
                    // console.log("this._startValues[index] is ",this._startValues[index], "event.translateX is ",event.translateX," this._startTranslateValues[index] is ",this._startTranslateValues[index],", sliderMagnitude is ",sliderMagnitude);
                    // console.log("this.value = ",this.value, "min is ",min," max is ",max);

                this._isThumbElementTranslating.set(event.target.element, true);
            }
        },

        handleTranslateEnd: {
            value: function (e) {
                //TODO: active should only be false when none of the thumbs are being interacted with.
                this.active = false;
                this._isThumbElementTranslating.set(e.target.element, false);
            }
        },

        _increase: {
            value: function () {
                var stepBase = (typeof this.min === "number") ? this.min : 0;
                var value = this.value - stepBase;
                var step =  this.step | (this.max-this.min)/100;
                if (value % step) {
                    if (value < 0) {
                        value -= value % step;
                    } else {
                        value += step - (value % step);
                    }
                } else {
                    value += step;
                }
                this.value = value + stepBase;
            }
        },

        _decrease: {
            value: function () {
                var stepBase = (typeof this.min === "number") ? this.min : 0;
                var value = this.value - stepBase;
                var step =  this.step | (this.max-this.min)/100;
                if (value % step) {
                    if (value > 0) {
                        value -= value % step;
                    } else {
                        value -= step + (value % step);
                    }
                } else {
                    value -= step;
                }
                this.value = value + stepBase;
            }
        },

        handleKeyPress: {
            value: function (event) {
                if (!this.enabled) {
                    return;
                }
                if(event.identifier === "increase") {
                    this._increase();
                } else if (event.identifier === "decrease") {
                    this._decrease();
                }

            }
        },

        surrenderPointer: {
            value: function (pointer, composer) {
                // If the user is sliding us then we do not want anyone using
                // the pointer
                return !this.active;
                //return false;
            }
        },

        // Properties

        _min: {
            value: 0
        },

        _max: {
            value: 100
        },

        _step: {
            value: "any" //???
        },

        // min: {
        //     get: function () {
        //         return this._min;
        //     },
        //     set: function (value) {
        //         if (! isNaN(value = parseFloat(value))) {
        //             if (this._min !== value) {
        //                 this._min = value;
        //             }
        //         }
        //     }
        // },
        //
        // max: {
        //     get: function () {
        //         return this._max;
        //     },
        //     set: function (value) {
        //         if (! isNaN(value = parseFloat(value))) {
        //             if (this._max !== value) {
        //                 this._max = value;
        //             }
        //         }
        //     }
        // },

        step: {
            get: function () {
                return this._step;
            },
            set: function (value) {
                if (! isNaN(value = parseFloat(value)) && value >= 0) {
                    if (this._step !== value) {
                        this._step = value;
                    }
                }
            }
        },

        _value: {
            get: function () {
                return this.values[this._currentThumbIndex];
            },
            set: function (value) {
                this.values.set(this._currentThumbIndex, value);
            }
        },
    /*

    Should introduce a validate method

    */
        value: {
            get: function () {
                if (this._value > this._max) {
                    return this._max;
                } else if (this._value < this._min) {
                    return this._min;
                }

                return this._value;
            },
            set: function (value) {
                if (! isNaN(value = parseFloat(value))) {
                    if (value > this._max) {
                        value = this._max;
                    } else if (value < this._min) {
                        value = this._min;
                    }

                    if (this._value !== value) {
                        Object.getOwnPropertyDescriptor(Control.prototype, "value").set.call(this,value);
                    }
                }
            }
        },

        /* this should be renamed orientation */
        axis: {
            value: null
        },

        // Machinery
        _currentThumbIndex:  {
            value: 0
        },
        _translateComposer: {
            value: null
        },

        _transform: {
            value: null
        },

        _transition: {
            value: null
        },

        _sliderMagnitude: {
            value: null
        },

        _startTranslate: {
            value: null
        },

        _startValue: {
            value: null
        },

        _percentageValue: {
            value: null
        },

        /* Axis should be renamed orientation and a setter should be put in place for
            backward compatibility
        */

        handleAxisChange: {
            value: function () {
                //TODO: this should handle all the thumb's translate composer
                if (this._translateComposer) {
                    this._translateComposer.axis = this.orientation;
                }
                if(this.orientation === this._VERTICAL) {
                    this.classList.add("montage-Slider--vertical");
                    this.classList.remove("montage-Slider--horizontal");
                } else {
                    this.classList.remove("montage-Slider--vertical");
                    this.classList.add("montage-Slider--horizontal");
                }
            }
        },

        _propertyRegex: {
            value: /_sliderMagnitude|_min|_max|_value|_values|values|_step/
        },

        handlePropertyChange: {
            value: function (changeValue, key, object) {
                if(key.match(this._propertyRegex) !== null) {
                    if(this._propertyNamesUsed) {
                        this._propertyNamesUsed[key] = true;
                    }
                    var MIN = this._min,
                        MAX = this._max,
                        RANGE = this._max - this._min,
                        valueOverriden = false;
                    for(var i=0, values = this.values, countI = values.length, value, min, max;i<countI;i++) {
                        value = values[i];
                        max = values[i+1] || MAX;
                        min = values[i-1] || MIN;

                        //adjust the value
                        if (value <= min) {
                            //first the simple case
                            value = min;
                        } else {
                            var magnitude = value - min;
                            var remainder = magnitude % this._step;
                            if (remainder) {
                                //if we have a remainder then we need to adjust the value
                                // Inspired by http://www.w3.org/html/wg/drafts/html/master/forms.html#range-state-(type=range)
                                // if we are in the middle of two stepped value then go for the larger one.
                                var roundup = (remainder >= this._step * 0.5) && ((value - remainder) + this._step <= max);
                                if (roundup) {
                                    value = (value - remainder) + this._step;
                                } else {
                                    value = value - remainder;
                                }
                            }

                        }

                        //otherwise don't adjust the value just check it's within  min and max
                        if (value > max) {
                            value = max;
                        }

                        values[i] = value;
                        if(i === this._currentThumbIndex) {
                            this._value = value;
                        }

                        if(valueOverriden) {
                            values[i] = value;
                        }

                        this._percentageValues[i] = ((value - MIN) * 100) / RANGE;
                    }
                    this.needsDraw = true;
                }
            }
        },

        _percentageValueAt: {
            value: function (index) {
                var value = this._percentageValues[index];
                return value > 100 ? 100 : (value < 0 ? 0 : value);
            }
        },

        handleInput: {
            enumerable: false,
            value: function() {
                if (this.converter) {
                    if (this.converter.allowPartialConversion === true && this.updateOnInput === true) {
                        this.takeValueFromElement();
                    }
                } else {
                    this.takeValueFromElement();
                }
            }
        },
    /**
        Description TODO
        @function
        @param {Event Handler} event TODO
        */
        handleChange: {
            enumerable: false,
            value: function(event) {
                this.takeValueFromElement();
                //this.dispatchActionEvent();
                // this.hasFocus = false;
            }
        }

    });

    Slider.addAttributes( /** @lends module:"montage/ui/native/input-range.reel".InputRange# */ {
    /**
        The maximum value displayed but the input control.
        @type {number}
        @default null
    */
        max: {
            dataType: 'number',
            get: function () {
                return this._max;
            },
            set: function (value) {
                if (! isNaN(value = parseFloat(value))) {
                    if (this._max !== value) {
                        this._max = value;
                    }
                }
            }
        },

    /**
        The minimum value displayed but the input control.
        @type {number}
        @default null
    */
        min: {
            dataType: 'number',
            get: function () {
                return this._min;
            },
            set: function (value) {
                if (! isNaN(value = parseFloat(value))) {
                    if (this._min !== value) {
                        this._min = value;
                    }
                }
            }
        }

    });

    if (window.MontageElement) {
        MontageElement.define("montage-slider", Slider);
    }