kendo.numerictextbox.js 24.6 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
/** 
 * Kendo UI v2016.1.112 (http://www.telerik.com/kendo-ui)                                                                                                                                               
 * Copyright 2016 Telerik AD. All rights reserved.                                                                                                                                                      
 *                                                                                                                                                                                                      
 * Kendo UI commercial licenses may be obtained at                                                                                                                                                      
 * http://www.telerik.com/purchase/license-agreement/kendo-ui-complete                                                                                                                                  
 * If you do not own a commercial license, this file shall be governed by the trial license terms.                                                                                                      
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       

*/
(function (f, define) {
    define('kendo.numerictextbox', [
        'kendo.core',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'numerictextbox',
        name: 'NumericTextBox',
        category: 'web',
        description: 'The NumericTextBox widget can format and display numeric, percentage or currency textbox.',
        depends: [
            'core',
            'userevents'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, caret = kendo.caret, keys = kendo.keys, ui = kendo.ui, Widget = ui.Widget, activeElement = kendo._activeElement, extractFormat = kendo._extractFormat, parse = kendo.parseFloat, placeholderSupported = kendo.support.placeholder, getCulture = kendo.getCulture, round = kendo._round, CHANGE = 'change', DISABLED = 'disabled', READONLY = 'readonly', INPUT = 'k-input', SPIN = 'spin', ns = '.kendoNumericTextBox', TOUCHEND = 'touchend', MOUSELEAVE = 'mouseleave' + ns, HOVEREVENTS = 'mouseenter' + ns + ' ' + MOUSELEAVE, DEFAULT = 'k-state-default', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', FOCUS = 'focus', POINT = '.', SELECTED = 'k-state-selected', STATEDISABLED = 'k-state-disabled', ARIA_DISABLED = 'aria-disabled', ARIA_READONLY = 'aria-readonly', INTEGER_REGEXP = /^(-)?(\d*)$/, NULL = null, proxy = $.proxy, extend = $.extend;
        var NumericTextBox = Widget.extend({
            init: function (element, options) {
                var that = this, isStep = options && options.step !== undefined, min, max, step, value, disabled;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element.on('focusout' + ns, proxy(that._focusout, that)).attr('role', 'spinbutton');
                options.placeholder = options.placeholder || element.attr('placeholder');
                that._initialOptions = extend({}, options);
                that._reset();
                that._wrapper();
                that._arrows();
                that._input();
                if (!kendo.support.mobileOS) {
                    that._text.on(FOCUS + ns, proxy(that._click, that));
                } else {
                    that._text.on(TOUCHEND + ns + ' ' + FOCUS + ns, function () {
                        that._toggleText(false);
                        element.focus();
                    });
                }
                min = that.min(element.attr('min'));
                max = that.max(element.attr('max'));
                step = that._parse(element.attr('step'));
                if (options.min === NULL && min !== NULL) {
                    options.min = min;
                }
                if (options.max === NULL && max !== NULL) {
                    options.max = max;
                }
                if (!isStep && step !== NULL) {
                    options.step = step;
                }
                element.attr('aria-valuemin', options.min).attr('aria-valuemax', options.max);
                options.format = extractFormat(options.format);
                value = options.value;
                that.value(value !== NULL ? value : element.val());
                disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                kendo.notify(that);
            },
            options: {
                name: 'NumericTextBox',
                decimals: NULL,
                min: NULL,
                max: NULL,
                value: NULL,
                step: 1,
                culture: '',
                format: 'n',
                spinners: true,
                placeholder: '',
                upArrowText: 'Increase value',
                downArrowText: 'Decrease value'
            },
            events: [
                CHANGE,
                SPIN
            ],
            _editable: function (options) {
                var that = this, element = that.element, disable = options.disable, readonly = options.readonly, text = that._text.add(element), wrapper = that._inputWrapper.off(HOVEREVENTS);
                that._toggleText(true);
                that._upArrowEventHandler.unbind('press');
                that._downArrowEventHandler.unbind('press');
                element.off('keydown' + ns).off('keypress' + ns).off('paste' + ns);
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    text.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false).attr(ARIA_READONLY, false);
                    that._upArrowEventHandler.bind('press', function (e) {
                        e.preventDefault();
                        that._spin(1);
                        that._upArrow.addClass(SELECTED);
                    });
                    that._downArrowEventHandler.bind('press', function (e) {
                        e.preventDefault();
                        that._spin(-1);
                        that._downArrow.addClass(SELECTED);
                    });
                    that.element.on('keydown' + ns, proxy(that._keydown, that)).on('keypress' + ns, proxy(that._keypress, that)).on('paste' + ns, proxy(that._paste, that));
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    text.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable).attr(ARIA_READONLY, readonly);
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            destroy: function () {
                var that = this;
                that.element.add(that._text).add(that._upArrow).add(that._downArrow).add(that._inputWrapper).off(ns);
                that._upArrowEventHandler.destroy();
                that._downArrowEventHandler.destroy();
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
                Widget.fn.destroy.call(that);
            },
            min: function (value) {
                return this._option('min', value);
            },
            max: function (value) {
                return this._option('max', value);
            },
            step: function (value) {
                return this._option('step', value);
            },
            value: function (value) {
                var that = this, adjusted;
                if (value === undefined) {
                    return that._value;
                }
                value = that._parse(value);
                adjusted = that._adjust(value);
                if (value !== adjusted) {
                    return;
                }
                that._update(value);
                that._old = that._value;
            },
            focus: function () {
                this._focusin();
            },
            _adjust: function (value) {
                var that = this, options = that.options, min = options.min, max = options.max;
                if (value === NULL) {
                    return value;
                }
                if (min !== NULL && value < min) {
                    value = min;
                } else if (max !== NULL && value > max) {
                    value = max;
                }
                return value;
            },
            _arrows: function () {
                var that = this, arrows, _release = function () {
                        clearTimeout(that._spinning);
                        arrows.removeClass(SELECTED);
                    }, options = that.options, spinners = options.spinners, element = that.element;
                arrows = element.siblings('.k-icon');
                if (!arrows[0]) {
                    arrows = $(buttonHtml('n', options.upArrowText) + buttonHtml('s', options.downArrowText)).insertAfter(element);
                    arrows.wrapAll('<span class="k-select"/>');
                }
                if (!spinners) {
                    arrows.parent().toggle(spinners);
                    that._inputWrapper.addClass('k-expand-padding');
                }
                that._upArrow = arrows.eq(0);
                that._upArrowEventHandler = new kendo.UserEvents(that._upArrow, { release: _release });
                that._downArrow = arrows.eq(1);
                that._downArrowEventHandler = new kendo.UserEvents(that._downArrow, { release: _release });
            },
            _blur: function () {
                var that = this;
                that._toggleText(true);
                that._change(that.element.val());
            },
            _click: function (e) {
                var that = this;
                clearTimeout(that._focusing);
                that._focusing = setTimeout(function () {
                    var input = e.target, idx = caret(input)[0], value = input.value.substring(0, idx), format = that._format(that.options.format), group = format[','], result, groupRegExp, extractRegExp, caretPosition = 0;
                    if (group) {
                        groupRegExp = new RegExp('\\' + group, 'g');
                        extractRegExp = new RegExp('([\\d\\' + group + ']+)(\\' + format[POINT] + ')?(\\d+)?');
                    }
                    if (extractRegExp) {
                        result = extractRegExp.exec(value);
                    }
                    if (result) {
                        caretPosition = result[0].replace(groupRegExp, '').length;
                        if (value.indexOf('(') != -1 && that._value < 0) {
                            caretPosition++;
                        }
                    }
                    that._focusin();
                    caret(that.element[0], caretPosition);
                });
            },
            _change: function (value) {
                var that = this;
                that._update(value);
                value = that._value;
                if (that._old != value) {
                    that._old = value;
                    if (!that._typing) {
                        that.element.trigger(CHANGE);
                    }
                    that.trigger(CHANGE);
                }
                that._typing = false;
            },
            _culture: function (culture) {
                return culture || getCulture(this.options.culture);
            },
            _focusin: function () {
                var that = this;
                that._inputWrapper.addClass(FOCUSED);
                that._toggleText(false);
                that.element[0].focus();
            },
            _focusout: function () {
                var that = this;
                clearTimeout(that._focusing);
                that._inputWrapper.removeClass(FOCUSED).removeClass(HOVER);
                that._blur();
            },
            _format: function (format, culture) {
                var numberFormat = this._culture(culture).numberFormat;
                format = format.toLowerCase();
                if (format.indexOf('c') > -1) {
                    numberFormat = numberFormat.currency;
                } else if (format.indexOf('p') > -1) {
                    numberFormat = numberFormat.percent;
                }
                return numberFormat;
            },
            _input: function () {
                var that = this, CLASSNAME = 'k-formatted-value', element = that.element.addClass(INPUT).show()[0], accessKey = element.accessKey, wrapper = that.wrapper, text;
                text = wrapper.find(POINT + CLASSNAME);
                if (!text[0]) {
                    text = $('<input type="text"/>').insertBefore(element).addClass(CLASSNAME);
                }
                try {
                    element.setAttribute('type', 'text');
                } catch (e) {
                    element.type = 'text';
                }
                text[0].tabIndex = element.tabIndex;
                text[0].style.cssText = element.style.cssText;
                text[0].title = element.title;
                text.prop('placeholder', that.options.placeholder);
                if (accessKey) {
                    text.attr('accesskey', accessKey);
                    element.accessKey = '';
                }
                that._text = text.addClass(element.className);
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode;
                that._key = key;
                if (key == keys.DOWN) {
                    that._step(-1);
                } else if (key == keys.UP) {
                    that._step(1);
                } else if (key == keys.ENTER) {
                    that._change(that.element.val());
                } else {
                    that._typing = true;
                }
            },
            _keypress: function (e) {
                if (e.which === 0 || e.metaKey || e.ctrlKey || e.keyCode === keys.BACKSPACE || e.keyCode === keys.ENTER) {
                    return;
                }
                var that = this;
                var min = that.options.min;
                var element = that.element;
                var selection = caret(element);
                var selectionStart = selection[0];
                var selectionEnd = selection[1];
                var character = String.fromCharCode(e.which);
                var numberFormat = that._format(that.options.format);
                var isNumPadDecimal = that._key === keys.NUMPAD_DOT;
                var value = element.val();
                var isValid;
                if (isNumPadDecimal) {
                    character = numberFormat[POINT];
                }
                value = value.substring(0, selectionStart) + character + value.substring(selectionEnd);
                isValid = that._numericRegex(numberFormat).test(value);
                if (isValid && isNumPadDecimal) {
                    element.val(value);
                    caret(element, selectionStart + character.length);
                    e.preventDefault();
                } else if (min !== null && min >= 0 && value.charAt(0) === '-' || !isValid) {
                    e.preventDefault();
                }
                that._key = 0;
            },
            _numericRegex: function (numberFormat) {
                var that = this;
                var separator = numberFormat[POINT];
                var precision = that.options.decimals;
                if (separator === POINT) {
                    separator = '\\' + separator;
                }
                if (precision === NULL) {
                    precision = numberFormat.decimals;
                }
                if (precision === 0) {
                    return INTEGER_REGEXP;
                }
                if (that._separator !== separator) {
                    that._separator = separator;
                    that._floatRegExp = new RegExp('^(-)?(((\\d+(' + separator + '\\d*)?)|(' + separator + '\\d*)))?$');
                }
                return that._floatRegExp;
            },
            _paste: function (e) {
                var that = this, element = e.target, value = element.value;
                setTimeout(function () {
                    if (that._parse(element.value) === NULL) {
                        that._update(value);
                    }
                });
            },
            _option: function (option, value) {
                var that = this, options = that.options;
                if (value === undefined) {
                    return options[option];
                }
                value = that._parse(value);
                if (!value && option === 'step') {
                    return;
                }
                options[option] = value;
                that.element.attr('aria-value' + option, value).attr(option, value);
            },
            _spin: function (step, timeout) {
                var that = this;
                timeout = timeout || 500;
                clearTimeout(that._spinning);
                that._spinning = setTimeout(function () {
                    that._spin(step, 50);
                }, timeout);
                that._step(step);
            },
            _step: function (step) {
                var that = this, element = that.element, value = that._parse(element.val()) || 0;
                if (activeElement() != element[0]) {
                    that._focusin();
                }
                value += that.options.step * step;
                that._update(that._adjust(value));
                that._typing = false;
                that.trigger(SPIN);
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _toggleText: function (toggle) {
                var that = this;
                that._text.toggle(toggle);
                that.element.toggle(!toggle);
            },
            _parse: function (value, culture) {
                return parse(value, this._culture(culture), this.options.format);
            },
            _update: function (value) {
                var that = this, options = that.options, format = options.format, decimals = options.decimals, culture = that._culture(), numberFormat = that._format(format, culture), isNotNull;
                if (decimals === NULL) {
                    decimals = numberFormat.decimals;
                }
                value = that._parse(value, culture);
                isNotNull = value !== NULL;
                if (isNotNull) {
                    value = parseFloat(round(value, decimals));
                }
                that._value = value = that._adjust(value);
                that._placeholder(kendo.toString(value, format, culture));
                if (isNotNull) {
                    value = value.toString();
                    if (value.indexOf('e') !== -1) {
                        value = round(+value, decimals);
                    }
                    value = value.replace(POINT, numberFormat[POINT]);
                } else {
                    value = '';
                }
                that.element.val(value).attr('aria-valuenow', value);
            },
            _placeholder: function (value) {
                this._text.val(value);
                if (!placeholderSupported && !value) {
                    this._text.val(this.options.placeholder);
                }
            },
            _wrapper: function () {
                var that = this, element = that.element, DOMElement = element[0], wrapper;
                wrapper = element.parents('.k-numerictextbox');
                if (!wrapper.is('span.k-numerictextbox')) {
                    wrapper = element.hide().wrap('<span class="k-numeric-wrap k-state-default" />').parent();
                    wrapper = wrapper.wrap('<span/>').parent();
                }
                wrapper[0].style.cssText = DOMElement.style.cssText;
                DOMElement.style.width = '';
                that.wrapper = wrapper.addClass('k-widget k-numerictextbox').addClass(DOMElement.className).css('display', '');
                that._inputWrapper = $(wrapper[0].firstChild);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(element[0].value);
                            that.max(that._initialOptions.max);
                            that.min(that._initialOptions.min);
                        });
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            }
        });
        function buttonHtml(className, text) {
            return '<span unselectable="on" class="k-link"><span unselectable="on" class="k-icon k-i-arrow-' + className + '" title="' + text + '">' + text + '</span></span>';
        }
        ui.plugin(NumericTextBox);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));