/*globals define, document*/ /*jslint nomen:true*/ /** * Advanced handling for input elements. * * The `.uiInput()` method add advanced handling to a input elements. * * ### Examples * Apply .uiInput() to all input element and set autofocus to the first matched element. * * JavaScript: * * ep(':input') * .first() * .uiInput({autofocus: true}) * .end() * .not(':first') * .uiInput() * .end(); * * * @class jQuery.ui.uiInput * @extends jQuery.widget * * @uses ep * @uses ep.dict * @uses jQuery.support.placeholder * @uses jQuery.support.multipleUpload * @uses jQuery.fn.form * @uses jQuery.fn.class * @uses ep.ui.tooltip * @since 6.11.0 */ /** * See `jQuery.ui.uiInput` for details. * * @fires changeValue * * @method uiInput * @member jQuery * * @since 6.11.0 */ /* * @copyright © Copyright 2006-2010, epages GmbH, All Rights Reserved. * * @module ep.ui.input * * @revision $Revision: 1.18 $ */ define("ep/ui/input", [ "jquery", "ep", "util/support", "$dict!ep/dict", "jquery/fn/form", "jquery/fn/class", "ep/ui/tooltip" ], function ($, ep, support, epDict) { 'use strict'; /* * @dictionary ep.dict * * @translation {SelectFile} */ /** * @event changeValue This event is triggered when the value is changed. * @member jQuery.ui.uiInput * @since 6.11.0 */ $(document) .on("click", "input + .ep-uiInput-custom:not(label *, input:disabled + *)", function (event) { // Trigger click from custom ui element on original one $(this.previousSibling) .trigger({ type: "click", data: event.data, originalTarget: this.previousSibling }); }); $.widget('ui.uiInput', { /** * @cfg {Object} options Option to pass to the widget. * @cfg {String} options.placeholder Placeholder text. * @cfg {String} options.info An info text show as tooltip if the element has focus. * @cfg {Boolean} options.autofocus=false Indication whether the element gets focus on page load. * @cfg {Boolean} options.big=false Indication whether the element is displayed bigger than the normal one. * @cfg {String} options.orientation Decide in which direction tooltipps will be shown. Can be either *right*, *left*, *top* or *bottom* */ options: { // placeholder: 'text', // info: 'text', autofocus: false, big: false }, _create: function () { var self = this, o = self.options, elem = self.elem = self.element .data('uiUiInput', self), // stack of additional elements stack = self.stack = $([]), // get type type = self.type = elem[0].tagName.toLowerCase() + ':', // classes elemClasses = ''; // detailed type self.type = type = (type === 'input:' || type === 'button:') ? type + elem[0].type : type; // get instance of dict self.dict = epDict; // set placeholder if (o.placeholder) { elem.attr('placeholder', o.placeholder); } elem.on('changeAttr.uiInput', $.proxy(self, '_changeAttr')) .on('reset.uiInput', $.proxy(self, '_change')) .on('focusin.uiInput', function () { if (self.tooltip) { self.tooltip[self.tooltip.is(':empty') ? 'hide' : 'show'](); } }) .on('focusout.uiInput', function () { self._leave(); if (self.tooltip) { self.tooltip.hide(); } }); if ((/file$/i).test(type)) { elemClasses += ' ep-uiInput-file'; // create a button stack.push( ( self.custom = $('<span class="ep-uiInput-custom"><span class="ep-uiInput ep-uiInput-button">' + self.dict.translate('SelectFile') + '...</span></span>') .insertAfter(elem) )[0] ); // create a input to display selected file name stack.push( ( self.fileText = $('<span class="ep-uiInput ep-uiInput-text">' + (elem.val() || ' ') + '</span>') .prependTo(self.custom) )[0] ); } if (self.options.big) { elemClasses += ' ep-uiInput-big'; } if ((/(^(textarea:|select:)|(text|password|email|url|tel|date|datetime|time|number)$)/).test(type)) { elemClasses += ' ep-uiInput'; } if ((/^select:/).test(type)) { elemClasses += ' ep-uiInput-select'; } else if ((/(^(button:|a:)|(submit|reset|button|image)$)/).test(type)) { elemClasses += (/image$/).test(type) ? ' ep-uiInput ep-uiInput-image' : ' ep-uiInput ep-uiInput-button'; // handle reset on form if ((/reset$/).test(type)) { elem.on('click.uiInput', function (event) { event.preventDefault(); $(this.form).formReset(); }); } // handle submit on buttons having the form attribute if ((/submit$/).test(type)) { if (this.elem.attr('form')) { if (!support.inputFormAttr) { //#JSCOVERAGE_IF false // not testable because HTML5 compatability cannot be faked this.elem.on('click', function (event) { if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } $('form#' + $(this).attr('form')).submit(); }); //#JSCOVERAGE_ENDIF } } } } else if ((/^textarea:$/).test(type)) { elemClasses += ' ep-uiInput-textarea2'; } else if ((/(text|password|email|url|tel|date|datetime|time|number)$/i).test(type)) { elemClasses += ' ep-uiInput-text'; } // change event if ((/(^(select:)|(file|checkbox|radio)$)/).test(type)) { elem.on('change.uiInput', $.proxy(self, '_change')); } // key event if ((/(^(textarea:)|(text|password|checkbox|radio|email|url|tel|date|datetime|time|number)$)/).test(type)) { elem.on('keyup.uiInput', $.proxy(self, '_change')); } // handle z-index of input[text] // if ((/(text|password|email|url|tel|date|datetime|time|number)$/i).test(type)) { if ((/text$/).test(type)) { elem.on('mouseup.uiInput', function (event) { if (self.tooltip) { // force focus for text input // (Firefox bug with tooltip that compete with the input about the z-index => input loses the focus and is not clickable) window.setTimeout(function() { elem.trigger('focus'); }, 0); } }); } // add classes for styling elem.addClass(elemClasses); // save value state self.lastState = [elem[0].value, elem[0].checked, elem[0].selectedIndex]; }, // init binds _init: function () { // init tooltip this._tooltipInit(); // handle autofocus for this elem if (this.elem.attr('autofocus') || this.options.autofocus) { this.elem[0].focus(); } }, // handle addClass to the wrap /** * The `.uiInput()` method wraps an element around the input, the addClass add classes to the wrap element. * * @param {String} className One or more class names to be added to the class attribute of each matched element. * * @method addClass * @member jQuery.ui.uiInput * * @since 6.11.0 */ addClass: function (name) { if (!(/(hover|active|focused)/).test(name) || !this.elem.is(':disabled,:readonly')) { this.elem.addClass(name); } }, // handle removeClass to the wrap /** * The `.uiInput()` method wraps an element around the input, the removeClass removes classes from the wrap element. * * @param {String} className A class name to be removed from the class attribute of each matched element. * * @method removeClass * @member jQuery.ui.uiInput * * @since 6.11.0 */ removeClass: function (name) { this.elem.removeClass(name); }, _tooltipInit: function (buildManual) { if (!this.tooltip && (this.options.info || buildManual)) { this.tooltip = ep('<div>') .addClass('ep-uiInput-info') .uiTooltip({ interactive: true, event: 'focus', context: this.elem, orientation: 'right', offsetAdjust: [0, 0] }); if (this.options.info) { this.tooltip.html(this.options.info); } // add to stack this.stack.push(this.tooltip[0]); } }, _setOption: function (key, value) { if (key === 'placeholder') { this.elem.attr('placeholder', value); } return this._superApply(arguments); }, // actions if change attr by javascript _changeAttr: function (event, attr) { if (attr.hasOwnProperty('value')) { this._change({}); } }, _stateChanged: function () { var oldState = this.lastState, newState = [this.elem[0].value, this.elem[0].checked, this.elem[0].selectedIndex], ret = !(oldState[0] === newState[0] && oldState[1] === newState[1] && oldState[2] === newState[2]); this.lastState = newState; return ret; }, _change: function (event) { if (event.keyCode !== 9) { // special for checkbox if ((/checkbox$/i).test(this.type)) { this.elem.trigger('changeAttr', { 'checked': this.elem.is(':checked') }); } else if ((/radio$/i).test(this.type)) { // special for radios this.elem .formGroup(':radio') .filter(':checked') .trigger('changeAttr', { 'checked': false }) .end() .filter(':not(:checked)') .trigger('changeAttr', { 'checked': true }); } else if ((/file$/i).test(this.type)) { // display selected file if (this.elem.val() !== "") { this.fileText.text(this.elem.val().replace(/^.*?fakepath[\/\\]?/, '')); } else { this.fileText.html(' '); } } } this._leave(); }, _leave: function () { this.elem.toggleClass('ui-changed', this.elem.is(':changed')); if (this._stateChanged()) { this.elem.trigger('changeValue'); // trigger changed to form $(this.elem[0].form).trigger('change'); } }, destroy: function () { this.elem .removeClass('ep-uiInput') .removeClass(/(ep-uiInput[\w\d-]*|epWidth-\d+)/g); this.stack.remove(); return this._superApply(arguments); } }); return ep; });