'use strict'; /*@ Ox.Input Input Element options Options object arrows if true, and type is 'float' or 'int', display arrows arrowStep step when clicking arrows autocomplete array of possible values, or function(key, value, callback), returns one or more values autocompleteReplace if true, value is replaced autocompleteReplaceCorrect if true, only valid values can be entered autocompleteSelect if true, menu is displayed autocompleteSelectHighlight if true, value in menu is highlighted autocompleteSelectMaxWidth Maximum width of autocomplete menu, or 0 autocompleteSelectOffset Offset of autocomplete menu autocompleteSelectSubmit if true, submit input on menu selection autocompleteSelectUpdate if true, update menu position on keypress autocorrect ('email', 'float', 'int', 'phone', 'url'), or regexp(value), or function(key, value, blur, callback), returns value autovalidate --remote validation-- clear if true, has clear button clearTooltip clear button tooltip changeOnKeypress if true, fire change event while typing disabled if true, is disabled height px (for type='textarea' and type='range' with orientation='horizontal') id element id key to be passed to autocomplete and autovalidate functions label Label labelWidth Label width max max value if type is 'int' or 'float' min min value if type is 'int' or 'float' name will be displayed by autovalidate function ('invalid ' + name) overlap '', 'left' or 'right', will cause padding and negative margin picker picker object rangeOptions range options arrows boolean, if true, display arrows //arrowStep number, step when clicking arrows //arrowSymbols array of two strings max number, maximum value min number, minimum value orientation 'horizontal' or 'vertical' step number, step thumbValue boolean, if true, value is displayed on thumb, or array of strings per value, or function(value), returns string thumbSize integer, px trackGradient string, css gradient for track trackImage string, image url, or array of image urls //trackStep number, 0 for 'scroll here', positive for step trackValues boolean readonly if true, is readonly serialize function used to serialize value in submit style 'rounded' or 'square' textAlign 'left', 'center' or 'right' type 'float', 'int', 'password', 'text', 'textarea' value string validate remote validation width px ([options[, self]]) -> Input Element autocomplete autocomplete autovalidate autovalidate blur blur cancel cancel change input changed event clear clear focus focus insert insert submit input submit event validate validate @*/ Ox.Input = function(options, self) { self = self || {}; var that = Ox.Element({ element: (options || {}).element || '
' }, self) .defaults({ arrows: false, arrowStep: 1, autocomplete: null, autocompleteReplace: false, autocompleteReplaceCorrect: false, autocompleteSelect: false, autocompleteSelectHighlight: false, autocompleteSelectMax: 0, autocompleteSelectMaxWidth: 0, autocompleteSelectOffset: {left: 4, top: 0}, autocompleteSelectSubmit: false, autocompleteSelectUpdate: false, autovalidate: null, changeOnKeypress: false, clear: false, clearTooltip: '', decimals: 0, disabled: false, height: 16, key: '', min: -Infinity, max: Infinity, label: '', labelWidth: 64, overlap: 'none', placeholder: '', readonly: false, serialize: null, style: 'rounded', textAlign: 'left', type: 'text', validate: null, value: '', width: 128 }) .options(options || {}) .update(function(key, value) { var inputWidth; if ([ 'autocomplete', 'autocompleteReplace', 'autocompleteSelect', 'autovalidate' ].indexOf(key) > -1) { if (self.options.autocomplete && self.options.autocompleteSelect) { self.$autocompleteMenu = constructAutocompleteMenu(); } self.bindKeyboard = self.options.autocomplete || self.options.autovalidate; } else if (key == 'disabled') { self.$input.attr({disabled: value}); } else if (key == 'height') { that.css({height: value + 'px'}); self.$input.css({height: value - 6 + 'px'}); } else if (key == 'label') { self.$label.options({title: value}); } else if (key == 'labelWidth') { self.$label.options({width: value}); inputWidth = getInputWidth(); self.$input.css({ width: inputWidth + 'px' }); self.hasPasswordPlaceholder && self.$placeholder.css({ width: inputWidth + 'px' }); } else if (key == 'placeholder') { setPlaceholder(); } else if (key == 'readonly') { self.$input.attr({readonly: value}); } else if (key == 'type') { // jQuery does not allow update via attr({type: value}) due to IE 6 bug self.$input[0].type = value } else if (key == 'value') { if (self.options.type == 'float' && self.options.decimals) { self.options.value = self.options.value.toFixed(self.options.decimals); } self.$input.val(self.options.value); that.is('.OxError') && that.removeClass('OxError'); setPlaceholder(); } else if (key == 'width') { that.css({width: self.options.width + 'px'}); inputWidth = getInputWidth(); self.$input.css({ width: inputWidth + 'px' }); self.hasPasswordPlaceholder && self.$placeholder.css({ width: inputWidth + 'px' }); } }) .addClass( 'OxInput OxKeyboardFocus OxMedium Ox' + Ox.toTitleCase(self.options.style) + (self.options.type == 'textarea' ? ' OxTextarea' : '') /*+ ( self.options.overlap != 'none' ? ' OxOverlap' + Ox.toTitleCase(self.options.overlap) : '' )*/ ) .css( Ox.extend({ width: self.options.width + 'px' }, self.options.type == 'textarea' ? { height: self.options.height + 'px' } : {}) ) .bindEvent(Ox.extend(self.options.type != 'textarea' ? { key_enter: submit } : {}, { key_control_i: insert, key_escape: cancel, key_shift_enter: submit })); if ( Ox.isArray(self.options.autocomplete) && self.options.autocompleteReplace && self.options.autocompleteReplaceCorrect && self.options.value === '' ) { self.options.value = self.options.autocomplete[0] } // fixme: set to min, not 0 // fixme: validate self.options.value ! if (self.options.type == 'float') { self.decimals = Ox.repeat('0', self.options.decimals || 1) Ox.extend(self.options, { autovalidate: 'float', textAlign: 'right', value: self.options.value || '0.' + self.decimals }); } else if (self.options.type == 'int') { Ox.extend(self.options, { autovalidate: 'int', textAlign: 'right', value: self.options.value || '0' }); } if (self.options.label) { self.$label = Ox.Label({ overlap: 'right', style: self.options.style, textAlign: 'right', title: self.options.label, width: self.options.labelWidth }) .css({ float: 'left' // fixme: use css rule }) .on({ click: function() { // fixme: ??? // that.focus(); } }) .appendTo(that); } if (self.options.arrows) { self.arrows = []; self.arrows[0] = [ Ox.Button({ overlap: 'right', title: 'left', type: 'image' }) .css({float: 'left'}) .on({ click: function() { clickArrow(-1); } }) .appendTo(that), Ox.Button({ overlap: 'left', title: 'right', type: 'image' }) .css({float: 'right'}) .on({ click: function() { clickArrow(1); } }) .appendTo(that) ] } self.bindKeyboard = self.options.autocomplete || self.options.autovalidate || self.options.changeOnKeypress; self.hasPasswordPlaceholder = self.options.type == 'password' && self.options.placeholder; self.inputWidth = getInputWidth(); if (self.options.clear) { self.$button = Ox.Button({ overlap: 'left', // FIXME: should always be self.options.style, but there // is a CSS bug for rounded image buttons style: self.options.style == 'squared' ? 'squared' : '', title: 'close', tooltip: self.options.clearTooltip, type: 'image' }) .css({ float: 'right' // fixme: use css rule }) .bindEvent({ click: clear, doubleclick: submit }) .appendTo(that); } self.$input = $(self.options.type == 'textarea' ? '