| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-slider-Multi'>/**</span> * Slider which supports vertical or horizontal orientation, keyboard adjustments, configurable snapping, axis clicking * and animation. Can be added as an item to any container. * * Sliders can be created with more than one thumb handle by passing an array of values instead of a single one: * *     @example *     Ext.create('Ext.slider.Multi', { *         width: 200, *         values: [25, 50, 75], *         increment: 5, *         minValue: 0, *         maxValue: 100, * *         // this defaults to true, setting to false allows the thumbs to pass each other *         constrainThumbs: false, *         renderTo: Ext.getBody() *     }); */Ext.define('Ext.slider.Multi', {    extend: 'Ext.form.field.Base',    alias: 'widget.multislider',    alternateClassName: 'Ext.slider.MultiSlider',    requires: [        'Ext.slider.Thumb',        'Ext.slider.Tip',        'Ext.Number',        'Ext.util.Format',        'Ext.Template',        'Ext.layout.component.field.Slider'    ],    childEls: [        'endEl', 'innerEl'    ],    // note: {id} here is really {inputId}, but {cmpId} is available    fieldSubTpl: [        '<div id="{id}" class="' + Ext.baseCSSPrefix + 'slider {fieldCls} {vertical}" aria-valuemin="{minValue}" aria-valuemax="{maxValue}" aria-valuenow="{value}" aria-valuetext="{value}">',            '<div id="{cmpId}-endEl" class="' + Ext.baseCSSPrefix + 'slider-end" role="presentation">',                '<div id="{cmpId}-innerEl" class="' + Ext.baseCSSPrefix + 'slider-inner" role="presentation">',                    '{%this.renderThumbs(out, values)%}',                '</div>',            '</div>',        '</div>',        {            renderThumbs: function(out, values) {                var me = values.$comp,                    i = 0,                    thumbs = me.thumbs,                    len = thumbs.length,                    thumb,                    thumbConfig;                for (; i < len; i++) {                    thumb = thumbs[i];                    thumbConfig = thumb.getElConfig();                    thumbConfig.id = me.id + '-thumb-' + i;                    Ext.DomHelper.generateMarkup(thumbConfig, out);                }            },            disableFormats: true        }    ],<span id='Ext-slider-Multi-cfg-value'>    /**</span>     * @cfg {Number} value     * A value with which to initialize the slider. Setting this will only result in the creation     * of a single slider thumb; if you want multiple thumbs then use the {@link #values} config instead.     *     * Defaults to #minValue.     */<span id='Ext-slider-Multi-cfg-values'>    /**</span>     * @cfg {Number[]} values     * Array of Number values with which to initalize the slider. A separate slider thumb will be created for each value     * in this array. This will take precedence over the single {@link #value} config.     */<span id='Ext-slider-Multi-cfg-vertical'>    /**</span>     * @cfg {Boolean} vertical     * Orient the Slider vertically rather than horizontally.     */    vertical: false,<span id='Ext-slider-Multi-cfg-minValue'>    /**</span>     * @cfg {Number} minValue     * The minimum value for the Slider.     */    minValue: 0,<span id='Ext-slider-Multi-cfg-maxValue'>    /**</span>     * @cfg {Number} maxValue     * The maximum value for the Slider.     */    maxValue: 100,<span id='Ext-slider-Multi-cfg-decimalPrecision'>    /**</span>     * @cfg {Number/Boolean} decimalPrecision The number of decimal places to which to round the Slider's value.     *     * To disable rounding, configure as **false**.     */    decimalPrecision: 0,<span id='Ext-slider-Multi-cfg-keyIncrement'>    /**</span>     * @cfg {Number} keyIncrement     * How many units to change the Slider when adjusting with keyboard navigation. If the increment     * config is larger, it will be used instead.     */    keyIncrement: 1,<span id='Ext-slider-Multi-cfg-increment'>    /**</span>     * @cfg {Number} increment     * How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.     */    increment: 0,<span id='Ext-slider-Multi-cfg-zeroBasedSnapping'>    /**</span>     * @cfg {Boolean} [zeroBasedSnapping=false]     * Set to `true` to calculate snap points based on {@link #increment}s from zero as opposed to     * from this Slider's {@link #minValue}.     *     * By Default, valid snap points are calculated starting {@link #increment}s from the {@link #minValue}     */<span id='Ext-slider-Multi-property-clickRange'>    /**</span>     * @private     * @property {Number[]} clickRange     * Determines whether or not a click to the slider component is considered to be a user request to change the value. Specified as an array of [top, bottom],     * the click event's 'top' property is compared to these numbers and the click only considered a change request if it falls within them. e.g. if the 'top'     * value of the click event is 4 or 16, the click is not considered a change request as it falls outside of the [5, 15] range     */    clickRange: [5,15],<span id='Ext-slider-Multi-cfg-clickToChange'>    /**</span>     * @cfg {Boolean} clickToChange     * Determines whether or not clicking on the Slider axis will change the slider.     */    clickToChange : true,<span id='Ext-slider-Multi-cfg-animate'>    /**</span>     * @cfg {Boolean} animate     * Turn on or off animation.     */    animate: true,<span id='Ext-slider-Multi-property-dragging'>    /**</span>     * @property {Boolean} dragging     * True while the thumb is in a drag operation     */    dragging: false,<span id='Ext-slider-Multi-cfg-constrainThumbs'>    /**</span>     * @cfg {Boolean} constrainThumbs     * True to disallow thumbs from overlapping one another.     */    constrainThumbs: true,    componentLayout: 'sliderfield',<span id='Ext-slider-Multi-cfg-useTips'>    /**</span>     * @cfg {Object/Boolean} useTips     * True to use an {@link Ext.slider.Tip} to display tips for the value. This option may also     * provide a configuration object for an {@link Ext.slider.Tip}.     */    useTips : true,<span id='Ext-slider-Multi-cfg-tipText'>    /**</span>     * @cfg {Function} [tipText=undefined]     * A function used to display custom text for the slider tip.     *     * Defaults to null, which will use the default on the plugin.     *     * @cfg {Ext.slider.Thumb} tipText.thumb The Thumb that the Tip is attached to     * @cfg {String} tipText.return The text to display in the tip     */    tipText : null,    ariaRole: 'slider',    // private override    initValue: function() {        var me = this,            extValue = Ext.value,            // Fallback for initial values: values config -> value config -> minValue config -> 0            values = extValue(me.values, [extValue(me.value, extValue(me.minValue, 0))]),            i = 0,            len = values.length;        // Store for use in dirty check        me.originalValue = values;        // Add a thumb for each value        for (; i < len; i++) {            me.addThumb(values[i]);        }    },    // private override    initComponent : function() {        var me = this,            tipPlug,            hasTip,            p, pLen, plugins;<span id='Ext-slider-Multi-property-thumbs'>        /**</span>         * @property {Array} thumbs         * Array containing references to each thumb         */        me.thumbs = [];        me.keyIncrement = Math.max(me.increment, me.keyIncrement);        me.addEvents(<span id='Ext-slider-Multi-event-beforechange'>            /**</span>             * @event beforechange             * Fires before the slider value is changed. By returning false from an event handler, you can cancel the             * event and prevent the slider from changing.             * @param {Ext.slider.Multi} slider The slider             * @param {Number} newValue The new value which the slider is being changed to.             * @param {Number} oldValue The old value which the slider was previously.             */            'beforechange',<span id='Ext-slider-Multi-event-change'>            /**</span>             * @event change             * Fires when the slider value is changed.             * @param {Ext.slider.Multi} slider The slider             * @param {Number} newValue The new value which the slider has been changed to.             * @param {Ext.slider.Thumb} thumb The thumb that was changed             */            'change',<span id='Ext-slider-Multi-event-changecomplete'>            /**</span>             * @event changecomplete             * Fires when the slider value is changed by the user and any drag operations have completed.             * @param {Ext.slider.Multi} slider The slider             * @param {Number} newValue The new value which the slider has been changed to.             * @param {Ext.slider.Thumb} thumb The thumb that was changed             */            'changecomplete',<span id='Ext-slider-Multi-event-dragstart'>            /**</span>             * @event dragstart             * Fires after a drag operation has started.             * @param {Ext.slider.Multi} slider The slider             * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker             */            'dragstart',<span id='Ext-slider-Multi-event-drag'>            /**</span>             * @event drag             * Fires continuously during the drag operation while the mouse is moving.             * @param {Ext.slider.Multi} slider The slider             * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker             */            'drag',<span id='Ext-slider-Multi-event-dragend'>            /**</span>             * @event dragend             * Fires after the drag operation has completed.             * @param {Ext.slider.Multi} slider The slider             * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker             */            'dragend'        );        // Ensure that the maxValue is a snap point, and that the initial value is snapped.        if (me.increment) {            me.maxValue = Ext.Number.snapInRange(me.maxValue, me.increment, me.minValue);            me.value = me.normalizeValue(me.value);        }        me.callParent();        // only can use it if it exists.        if (me.useTips) {            if (Ext.isObject(me.useTips)) {                tipPlug = Ext.apply({}, me.useTips);            } else {                tipPlug = me.tipText ? {getText: me.tipText} : {};                }            plugins = me.plugins = me.plugins || [];            pLen    = plugins.length;                        for (p = 0; p < pLen; p++) {                if (plugins[p].isSliderTip) {                    hasTip = true;                    break;                }            }            if (!hasTip) {                me.plugins.push(new Ext.slider.Tip(tipPlug));            }        }    },<span id='Ext-slider-Multi-method-addThumb'>    /**</span>     * Creates a new thumb and adds it to the slider     * @param {Number} [value=0] The initial value to set on the thumb.     * @return {Ext.slider.Thumb} The thumb     */    addThumb: function(value) {        var me = this,            thumb = new Ext.slider.Thumb({                ownerCt     : me,                ownerLayout : me.getComponentLayout(),                value       : value,                slider      : me,                index       : me.thumbs.length,                constrain   : me.constrainThumbs,                disabled    : !!me.readOnly            });        me.thumbs.push(thumb);        //render the thumb now if needed        if (me.rendered) {            thumb.render();        }        return thumb;    },<span id='Ext-slider-Multi-method-promoteThumb'>    /**</span>     * @private     * Moves the given thumb above all other by increasing its z-index. This is called when as drag     * any thumb, so that the thumb that was just dragged is always at the highest z-index. This is     * required when the thumbs are stacked on top of each other at one of the ends of the slider's     * range, which can result in the user not being able to move any of them.     * @param {Ext.slider.Thumb} topThumb The thumb to move to the top     */    promoteThumb: function(topThumb) {        var thumbs = this.thumbs,            ln = thumbs.length,            zIndex, thumb, i;        for (i = 0; i < ln; i++) {            thumb = thumbs[i];            if (thumb == topThumb) {                thumb.bringToFront();            } else {                thumb.sendToBack();            }        }    },    // private override    getSubTplData : function() {        var me = this;        return Ext.apply(me.callParent(), {            $comp: me,            vertical: me.vertical ? Ext.baseCSSPrefix + 'slider-vert' : Ext.baseCSSPrefix + 'slider-horz',            minValue: me.minValue,            maxValue: me.maxValue,            value: me.value        });    },    onRender : function() {        var me = this,            thumbs = me.thumbs,            len = thumbs.length,            i = 0,            thumb;        me.callParent(arguments);        for (i = 0; i < len; i++) {            thumb = thumbs[i];            thumb.el = me.el.getById(me.id + '-thumb-' + i);            thumb.onRender();        }    },<span id='Ext-slider-Multi-method-initEvents'>    /**</span>     * @private     * Adds keyboard and mouse listeners on this.el. Ignores click events on the internal focus element.     */    initEvents : function() {        var me = this;        me.mon(me.el, {            scope    : me,            mousedown: me.onMouseDown,            keydown  : me.onKeyDown        });    },<span id='Ext-slider-Multi-method-getTrackpoint'>    /**</span>     * @private     * Given an `[x, y]` position within the slider's track (Points outside the slider's track are coerced to either the minimum or maximum value),     * calculate how many pixels **from the slider origin** (left for horizontal Sliders and bottom for vertical Sliders) that point is.     *     * If the point is outside the range of the Slider's track, the return value is `undefined`     * @param {Number[]} xy The point to calculate the track point for     */    getTrackpoint : function(xy) {        var me = this,            result,            positionProperty,            sliderTrack = me.innerEl,            trackLength;        if (me.vertical) {            positionProperty = 'top';            trackLength = sliderTrack.getHeight();        } else {            positionProperty = 'left';            trackLength = sliderTrack.getWidth();        }        result = Ext.Number.constrain(sliderTrack.translatePoints(xy)[positionProperty], 0, trackLength);        return me.vertical ? trackLength - result : result;    },<span id='Ext-slider-Multi-method-onMouseDown'>    /**</span>     * @private     * Mousedown handler for the slider. If the clickToChange is enabled and the click was not on the draggable 'thumb',     * this calculates the new value of the slider and tells the implementation (Horizontal or Vertical) to move the thumb     * @param {Ext.EventObject} e The click event     */    onMouseDown : function(e) {        var me = this,            thumbClicked = false,            i = 0,            thumbs = me.thumbs,            len = thumbs.length,            trackPoint;        if (me.disabled) {            return;        }        //see if the click was on any of the thumbs        for (; i < len; i++) {            thumbClicked = thumbClicked || e.target == thumbs[i].el.dom;        }        if (me.clickToChange && !thumbClicked) {            trackPoint = me.getTrackpoint(e.getXY());            if (trackPoint !== undefined) {                me.onClickChange(trackPoint);            }        }        me.focus();    },<span id='Ext-slider-Multi-method-onClickChange'>    /**</span>     * @private     * Moves the thumb to the indicated position.     * Only changes the value if the click was within this.clickRange.     * @param {Number} trackPoint local pixel offset **from the origin** (left for horizontal and bottom for vertical) along the Slider's axis at which the click event occured.     */    onClickChange : function(trackPoint) {        var me = this,            thumb, index;        // How far along the track *from the origin* was the click.        // If vertical, the origin is the bottom of the slider track.        //find the nearest thumb to the click event        thumb = me.getNearest(trackPoint);        if (!thumb.disabled) {            index = thumb.index;            me.setValue(index, Ext.util.Format.round(me.reversePixelValue(trackPoint), me.decimalPrecision), undefined, true);        }    },<span id='Ext-slider-Multi-method-getNearest'>    /**</span>     * @private     * Returns the nearest thumb to a click event, along with its distance     * @param {Number} trackPoint local pixel position along the Slider's axis to find the Thumb for     * @return {Object} The closest thumb object and its distance from the click event     */    getNearest: function(trackPoint) {        var me = this,            clickValue = me.reversePixelValue(trackPoint),            nearestDistance = (me.maxValue - me.minValue) + 5, //add a small fudge for the end of the slider            nearest = null,            thumbs = me.thumbs,            i = 0,            len = thumbs.length,            thumb,            value,            dist;        for (; i < len; i++) {            thumb = me.thumbs[i];            value = thumb.value;            dist  = Math.abs(value - clickValue);            if (Math.abs(dist <= nearestDistance)) {                nearest = thumb;                nearestDistance = dist;            }        }        return nearest;    },<span id='Ext-slider-Multi-method-onKeyDown'>    /**</span>     * @private     * Handler for any keypresses captured by the slider. If the key is UP or RIGHT, the thumb is moved along to the right     * by this.keyIncrement. If DOWN or LEFT it is moved left. Pressing CTRL moves the slider to the end in either direction     * @param {Ext.EventObject} e The Event object     */    onKeyDown : function(e) {        /*         * The behaviour for keyboard handling with multiple thumbs is currently undefined.         * There's no real sane default for it, so leave it like this until we come up         * with a better way of doing it.         */        var me = this,            k,            val;        if(me.disabled || me.thumbs.length !== 1) {            e.preventDefault();            return;        }        k = e.getKey();        switch(k) {            case e.UP:            case e.RIGHT:                e.stopEvent();                val = e.ctrlKey ? me.maxValue : me.getValue(0) + me.keyIncrement;                me.setValue(0, val, undefined, true);            break;            case e.DOWN:            case e.LEFT:                e.stopEvent();                val = e.ctrlKey ? me.minValue : me.getValue(0) - me.keyIncrement;                me.setValue(0, val, undefined, true);            break;            default:                e.preventDefault();        }    },<span id='Ext-slider-Multi-method-normalizeValue'>    /**</span>     * @private     * Returns a snapped, constrained value when given a desired value     * @param {Number} value Raw number value     * @return {Number} The raw value rounded to the correct d.p. and constrained within the set max and min values     */    normalizeValue : function(v) {        var me = this,            Num = Ext.Number,            snapFn = Num[me.zeroBasedSnapping ? 'snap' : 'snapInRange'];        v = snapFn.call(Num, v, me.increment, me.minValue, me.maxValue);        v = Ext.util.Format.round(v, me.decimalPrecision);        v = Ext.Number.constrain(v, me.minValue, me.maxValue);        return v;    },<span id='Ext-slider-Multi-method-setMinValue'>    /**</span>     * Sets the minimum value for the slider instance. If the current value is less than the minimum value, the current     * value will be changed.     * @param {Number} val The new minimum value     */    setMinValue : function(val) {        var me = this,            i = 0,            thumbs = me.thumbs,            len = thumbs.length,            t;        me.minValue = val;        if (me.rendered) {            me.inputEl.dom.setAttribute('aria-valuemin', val);        }        for (; i < len; ++i) {            t = thumbs[i];            t.value = t.value < val ? val : t.value;        }        me.syncThumbs();    },<span id='Ext-slider-Multi-method-setMaxValue'>    /**</span>     * Sets the maximum value for the slider instance. If the current value is more than the maximum value, the current     * value will be changed.     * @param {Number} val The new maximum value     */    setMaxValue : function(val) {        var me = this,            i = 0,            thumbs = me.thumbs,            len = thumbs.length,            t;        me.maxValue = val;        if (me.rendered) {            me.inputEl.dom.setAttribute('aria-valuemax', val);        }        for (; i < len; ++i) {            t = thumbs[i];            t.value = t.value > val ? val : t.value;        }        me.syncThumbs();    },<span id='Ext-slider-Multi-method-setValue'>    /**</span>     * Programmatically sets the value of the Slider. Ensures that the value is constrained within the minValue and     * maxValue.     * @param {Number} index Index of the thumb to move     * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)     * @param {Boolean} [animate=true] Turn on or off animation     */    setValue : function(index, value, animate, changeComplete) {        var me = this,            thumb = me.thumbs[index];        // ensures value is contstrained and snapped        value = me.normalizeValue(value);        if (value !== thumb.value && me.fireEvent('beforechange', me, value, thumb.value, thumb) !== false) {            thumb.value = value;            if (me.rendered) {                // TODO this only handles a single value; need a solution for exposing multiple values to aria.                // Perhaps this should go on each thumb element rather than the outer element.                me.inputEl.set({                    'aria-valuenow': value,                    'aria-valuetext': value                });                thumb.move(me.calculateThumbPosition(value), Ext.isDefined(animate) ? animate !== false : me.animate);                me.fireEvent('change', me, value, thumb);                me.checkDirty();                if (changeComplete) {                    me.fireEvent('changecomplete', me, value, thumb);                }            }        }    },<span id='Ext-slider-Multi-method-calculateThumbPosition'>    /**</span>     * @private     * Given a value within this Slider's range, calculates a Thumb's percentage CSS position to map that value.     */    calculateThumbPosition : function(v) {        return (v - this.minValue) / (this.maxValue - this.minValue) * 100;    },<span id='Ext-slider-Multi-method-getRatio'>    /**</span>     * @private     * Returns the ratio of pixels to mapped values. e.g. if the slider is 200px wide and maxValue - minValue is 100,     * the ratio is 2     * @return {Number} The ratio of pixels to mapped values     */    getRatio : function() {        var me = this,            trackLength = this.vertical ? this.innerEl.getHeight() : this.innerEl.getWidth(),            valueRange = this.maxValue - this.minValue;        return valueRange === 0 ? trackLength : (trackLength / valueRange);    },<span id='Ext-slider-Multi-method-reversePixelValue'>    /**</span>     * @private     * Given a pixel location along the slider, returns the mapped slider value for that pixel.     * E.g. if we have a slider 200px wide with minValue = 100 and maxValue = 500, reversePixelValue(50)     * returns 200     * @param {Number} pos The position along the slider to return a mapped value for     * @return {Number} The mapped value for the given position     */    reversePixelValue : function(pos) {        return this.minValue + (pos / this.getRatio());    },<span id='Ext-slider-Multi-method-reversePercentageValue'>    /**</span>     * @private     * Given a Thumb's percentage position along the slider, returns the mapped slider value for that pixel.     * E.g. if we have a slider 200px wide with minValue = 100 and maxValue = 500, reversePercentageValue(25)     * returns 200     * @param {Number} pos The percentage along the slider track to return a mapped value for     * @return {Number} The mapped value for the given position     */    reversePercentageValue : function(pos) {        return this.minValue + (this.maxValue - this.minValue) * (pos / 100);    },    //private    onDisable: function() {        var me = this,            i = 0,            thumbs = me.thumbs,            len = thumbs.length,            thumb,            el,            xy;        me.callParent();        for (; i < len; i++) {            thumb = thumbs[i];            el = thumb.el;            thumb.disable();            if(Ext.isIE) {                //IE breaks when using overflow visible and opacity other than 1.                //Create a place holder for the thumb and display it.                xy = el.getXY();                el.hide();                me.innerEl.addCls(me.disabledCls).dom.disabled = true;                if (!me.thumbHolder) {                    me.thumbHolder = me.endEl.createChild({cls: Ext.baseCSSPrefix + 'slider-thumb ' + me.disabledCls});                }                me.thumbHolder.show().setXY(xy);            }        }    },    //private    onEnable: function() {        var me = this,            i = 0,            thumbs = me.thumbs,            len = thumbs.length,            thumb,            el;        this.callParent();        for (; i < len; i++) {            thumb = thumbs[i];            el = thumb.el;            thumb.enable();            if (Ext.isIE) {                me.innerEl.removeCls(me.disabledCls).dom.disabled = false;                if (me.thumbHolder) {                    me.thumbHolder.hide();                }                el.show();                me.syncThumbs();            }        }    },<span id='Ext-slider-Multi-method-syncThumbs'>    /**</span>     * Synchronizes thumbs position to the proper proportion of the total component width based on the current slider     * {@link #value}. This will be called automatically when the Slider is resized by a layout, but if it is rendered     * auto width, this method can be called from another resize handler to sync the Slider if necessary.     */    syncThumbs : function() {        if (this.rendered) {            var thumbs = this.thumbs,                length = thumbs.length,                i = 0;            for (; i < length; i++) {                thumbs[i].move(this.calculateThumbPosition(thumbs[i].value));            }        }    },<span id='Ext-slider-Multi-method-getValue'>    /**</span>     * Returns the current value of the slider     * @param {Number} index The index of the thumb to return a value for     * @return {Number/Number[]} The current value of the slider at the given index, or an array of all thumb values if     * no index is given.     */    getValue : function(index) {        return Ext.isNumber(index) ? this.thumbs[index].value : this.getValues();    },<span id='Ext-slider-Multi-method-getValues'>    /**</span>     * Returns an array of values - one for the location of each thumb     * @return {Number[]} The set of thumb values     */    getValues: function() {        var values = [],            i = 0,            thumbs = this.thumbs,            len = thumbs.length;        for (; i < len; i++) {            values.push(thumbs[i].value);        }        return values;    },    getSubmitValue: function() {        var me = this;        return (me.disabled || !me.submitValue) ? null : me.getValue();    },    reset: function() {        var me = this,            arr = [].concat(me.originalValue),            a     = 0,            aLen  = arr.length,            val;        for (; a < aLen; a++) {            val = arr[a];            me.setValue(a, val);        }        me.clearInvalid();        // delete here so we reset back to the original state        delete me.wasValid;    },        setReadOnly: function(readOnly){        var me = this,            thumbs = me.thumbs,            len = thumbs.length,            i = 0;                    me.callParent(arguments);         readOnly = me.readOnly;                for (; i < len; ++i) {            if (readOnly) {                thumbs[i].disable();            } else {                thumbs[i].enable();            }                    }               },    // private    beforeDestroy : function() {        var me     = this,            thumbs = me.thumbs,            t      = 0,            tLen   = thumbs.length,            thumb;        Ext.destroy(me.innerEl, me.endEl, me.focusEl);        for (; t < tLen; t++) {            thumb = thumbs[t];            Ext.destroy(thumb);        }        me.callParent();    }});</pre></body></html>
 |