Search code examples
fuelux

FuelUX spinbox - use custom strings array


Is it possible to leverage FuelUX spinbox to cycle/scroll through array of custom strings?

This is an example of what I mean, but it's a jQueryUI implementation:

Links to jsfiddle.net must be accompanied by code.
Please indent all code by 4 spaces using the code 
toolbar button or the CTRL+K keyboard shortcut.
For more editing help, click the [?] toolbar icon.

http://jsfiddle.net/MartynDavis/gzmvc2ds/


Solution

  • Something quick and dirty based on FuelUX spinbox:

    /*
     * Fuel UX SpinStrings
     * https://github.com/ExactTarget/fuelux
     *
     * Copyright (c) 2014 ExactTarget
     * Licensed under the BSD New license.
     */
    
    // -- BEGIN UMD WRAPPER PREFACE --
    
    // For more information on UMD visit:
    // https://github.com/umdjs/umd/blob/master/jqueryPlugin.js
    
    (function (factory) {
        if (typeof define === 'function' && define.amd) {
            // if AMD loader is available, register as an anonymous module.
            define(['jquery'], factory);
        } else if (typeof exports === 'object') {
            // Node/CommonJS
            module.exports = factory(require('jquery'));
        } else {
            // OR use browser globals if AMD is not present
            factory(jQuery);
        }
    }(function ($) {
        // -- END UMD WRAPPER PREFACE --
    
        // -- BEGIN MODULE CODE HERE --
    
        var old = $.fn.spinstrings;
    
        // SPINSTRINGS CONSTRUCTOR AND PROTOTYPE
    
        var SpinStrings = function SpinStrings(element, options) {
            this.$element = $(element);
            this.$element.find('.btn').on('click', function (e) {
                //keep spinstrings from submitting if they forgot to say type="button" on their spinner buttons
                e.preventDefault();
            });
            if ($.isPlainObject(options) && 'options' in options) {
                if (!$.isArray(options.options)) {
                    delete options.options;
                } else {
                    options.min = 0;
                    options.max = options.options.length - 1;
                    if (options.value && ((idx = options.options.indexOf(options.value)) > -1)) {
                        options.index = idx;
                    } else {
                        options.index = 0;
                    }
                }
            }
    
            this.options = $.extend({}, $.fn.spinstrings.defaults, options);
    
            if (this.options.index < this.options.min) {
                this.options.index = this.options.min;
            } else if (this.options.max < this.options.index) {
                this.options.index = this.options.max;
            }
    
            this.$input = this.$element.find('.spinstrings-input');
            this.$input.on('focusout.fu.spinstrings', this.$input, $.proxy(this.change, this));
            this.$element.on('keydown.fu.spinstrings', this.$input, $.proxy(this.keydown, this));
            this.$element.on('keyup.fu.spinstrings', this.$input, $.proxy(this.keyup, this));
    
            this.bindMousewheelListeners();
            this.mousewheelTimeout = {};
    
            this.$element.on('click.fu.spinstrings', '.spinstrings-up', $.proxy(function () {
                this.step(true);
            }, this));
            this.$element.on('click.fu.spinstrings', '.spinstrings-down', $.proxy(function () {
                this.step(false);
            }, this));
    
            this.lastValue = this.options.value;
    
            this.render();
    
            if (this.options.disabled) {
                this.disable();
            }
        };
    
        // Truly private methods
    
        var _applyLimits = function(value) {
            // if unreadable
            if (isNaN(parseFloat(value))) {
                return value;
            }
    
            // if not within range return the limit
            if (value > this.options.max) {
                if (this.options.cycle) {
                    value = this.options.min;
                } else {
                    value = this.options.max;
                }
            } else if (value < this.options.min) {
                if (this.options.cycle) {
                    value = this.options.max;
                } else {
                    value = this.options.min;
                }
            }
    
            return value;
        };
    
        SpinStrings.prototype = {
            constructor: SpinStrings,
    
            destroy: function destroy() {
                this.$element.remove();
                // any external bindings
                // [none]
                // set input value attrbute
                this.$element.find('input').each(function () {
                    $(this).attr('value', $(this).val());
                });
                // empty elements to return to original markup
                // [none]
                // returns string of markup
                return this.$element[0].outerHTML;
            },
    
            render: function render() {
                this.setValue(this.getDisplayValue());
            },
    
            change: function change() {
                this.setValue(this.getDisplayValue());
    
                this.triggerChangedEvent();
            },
    
            triggerChangedEvent: function triggerChangedEvent() {
                var currentValue = this.getValue();
                if (currentValue === this.lastValue) return;
                this.lastValue = currentValue;
    
                // Primary changed event
                this.$element.trigger('changed.fu.spinstrings', currentValue);
            },
    
            step: function step(isIncrease) {
                //refresh value from display before trying to increment in case they have just been typing before clicking the nubbins
                this.setValue(this.getDisplayValue());
                var newVal;
    
                if (isIncrease) {
                    newVal = this.options.index + this.options.step;
                } else {
                    newVal = this.options.index - this.options.step;
                }
    
                newVal = _applyLimits.call(this, newVal);
                newVal = this.getOptionByIndex(newVal);
    
                this.setValue(newVal);
            },
    
            getDisplayValue: function getDisplayValue() {
                var inputValue = this.$input.val();
                var value = (!!inputValue) ? inputValue : this.options.value;
                return value;
            },
    
            /**
             * @param string value
             */
            setDisplayValue: function setDisplayValue(value) {
                this.$input.val(value);
            },
    
            /**
             * @return string
             */
            getValue: function getValue() {
                return this.options.value;
            },
    
            /**
             * @param string val
             */
            setValue: function setValue(val) {
                var intVal = this.getIndexByOption(val);
    
                //cache the pure int value
                this.options.value = val;
                this.options.index = intVal;
    
                //display number
                this.setDisplayValue(val);
    
                return this;
            },
    
            value: function value(val) {
                if (val || val === 0) {
                    return this.setValue(val);
                } else {
                    return this.getValue();
                }
            },
    
            /**
             * Get string's position in array of options.
             *
             * @param string value
             * @return integer
             */
            getIndexByOption: function(value) {
                ret = null;
                if (this.options.options) {
                    ret = this.options.options.indexOf(value);
                }
                return ret;
            },
    
            /**
             * Get option string by index.
             *
             * @param integer index
             * @return string
             */
            getOptionByIndex: function(value) {
                ret = null;
                if (this.options.options[value]) {
                    ret = this.options.options[value];
                }
                return ret;
            },
    
            disable: function disable() {
                this.options.disabled = true;
                this.$element.addClass('disabled');
                this.$input.attr('disabled', '');
                this.$element.find('button').addClass('disabled');
            },
    
            enable: function enable() {
                this.options.disabled = false;
                this.$element.removeClass('disabled');
                this.$input.removeAttr('disabled');
                this.$element.find('button').removeClass('disabled');
            },
    
            keydown: function keydown(event) {
                var keyCode = event.keyCode;
                if (keyCode === 38) {
                    this.step(true);
                } else if (keyCode === 40) {
                    this.step(false);
                } else if (keyCode === 13) {
                    this.change();
                }
            },
    
            keyup: function keyup(event) {
                var keyCode = event.keyCode;
    
                if (keyCode === 38 || keyCode === 40) {
                    this.triggerChangedEvent();
                }
            },
    
            bindMousewheelListeners: function bindMousewheelListeners() {
                var inputEl = this.$input.get(0);
                if (inputEl.addEventListener) {
                    //IE 9, Chrome, Safari, Opera
                    inputEl.addEventListener('mousewheel', $.proxy(this.mousewheelHandler, this), false);
                    // Firefox
                    inputEl.addEventListener('DOMMouseScroll', $.proxy(this.mousewheelHandler, this), false);
                } else {
                    // IE <9
                    inputEl.attachEvent('onmousewheel', $.proxy(this.mousewheelHandler, this));
                }
            },
    
            mousewheelHandler: function mousewheelHandler(event) {
                if (!this.options.disabled) {
                    var e = window.event || event;// old IE support
                    var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
                    var self = this;
    
                    clearTimeout(this.mousewheelTimeout);
                    this.mousewheelTimeout = setTimeout(function () {
                        self.triggerChangedEvent();
                    }, 300);
    
                    if (delta > 0) {//ACE
                        this.step(true);
                    } else {
                        this.step(false);
                    }
    
                    if (e.preventDefault) {
                        e.preventDefault();
                    } else {
                        e.returnValue = false;
                    }
    
                    return false;
                }
            }
        };
    
    
        // SPINSTRINGS PLUGIN DEFINITION
    
        $.fn.spinstrings = function spinstrings(option) {
            var args = Array.prototype.slice.call(arguments, 1);
            var methodReturn;
    
            var $set = this.each(function () {
                var $this = $(this);
                var data = $this.data('fu.spinstrings');
                var options = typeof option === 'object' && option;
    
                if (!data) {
                    $this.data('fu.spinstrings', (data = new SpinStrings(this, options)));
                }
    
                if (typeof option === 'string') {
                    methodReturn = data[option].apply(data, args);
                }
            });
    
            return (methodReturn === undefined) ? $set : methodReturn;
        };
    
        // value needs to be 0 for this.render();
        $.fn.spinstrings.defaults = {
            value: null,
            index: 0,
            min: 0,
            max: 0,
            step: 1,
            disabled: false,
            cycle: true
        };
    
        $.fn.spinstrings.Constructor = SpinStrings;
    
        $.fn.spinstrings.noConflict = function noConflict() {
            $.fn.spinstrings = old;
            return this;
        };
    
    
        // DATA-API
    
        $(document).on('mousedown.fu.spinstrings.data-api', '[data-initialize=spinstrings]', function (e) {
            var $control = $(e.target).closest('.spinstrings');
            if (!$control.data('fu.spinstrings')) {
                $control.spinstrings($control.data());
            }
        });
    
        // Must be domReady for AMD compatibility
        $(function () {
            $('[data-initialize=spinstrings]').each(function () {
                var $this = $(this);
                if (!$this.data('fu.spinstrings')) {
                    $this.spinstrings($this.data());
                }
            });
        });
    
        // -- BEGIN UMD WRAPPER AFTERWORD --
    }));
    // -- END UMD WRAPPER AFTERWORD --
    

    Mark-up & style:

    <style>
        .spinstrings {position:relative;display:inline-block;margin-left:-2px}
        .spinstrings input {height:26px;color:#444444;font-size:12px;padding:0 5px;margin:0 !important;width:100px}
        .spinstrings input[readonly] {background-color:#ffffff !important}
        .spinstrings .spinstrings-arrows {position:absolute;right:5px;height:22px;width:12px;background:transparent;top:1px}
        .spinstrings .spinstrings-arrows i.fa {position:absolute;display:block;font-size:16px;line-height:10px;width:12px;cursor:pointer}
        .spinstrings .spinstrings-arrows i.fa:hover {color:#307ecc}
        .spinstrings .spinstrings-arrows i.fa.spinstrings-up {top:0}
        .spinstrings .spinstrings-arrows i.fa.spinstrings-down {bottom:0}
    </style>
    <div class="spinstrings" id="mySpinStrings">
        <input type="text" class="spinstrings-input" readonly="readonly">
        <div class="spinstrings-arrows"><i class="fa fa-caret-up spinstrings-up"></i><i class="fa fa-caret-down spinstrings-down"></i></div>
    </div>
    

    Init as:

        $('#mySpinStrings', expiryControlsW).spinstrings({
            options: ['day', 'week', 'month'],
            value: 'week'
        });
    

    That's it, folks!