      1 // ==========================================================================
      2 // Project:   The M-Project - Mobile HTML5 Application Framework
      3 // Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
      4 // Creator:   Sebastian
      5 // Date:      04.11.2010
      6 // License:   Dual licensed under the MIT or GPL Version 2 licenses.
      7 //            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
      8 //            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
      9 // ==========================================================================
     10
     11 /**
     12  * @class
     13  *
     14  * M.TextFieldView is the prototype of any text field input view. It can be rendered as both
     15  * a single line text field and a multiple line text field. If it is styled as a multiple
     16  * line text field, is has a built-in autogrow mechanism so the textfield is getting larger
     17  * depending on the number of lines of text a user enters.
     18  *
     19  * @extends M.View
     20  */
     21 M.TextFieldView = M.View.extend(
     22 /** @scope M.TextFieldView.prototype */ {
     23
     24    /**
     25      * The type of this object.
     26      *
     27      * @type String
     28      */
     29     type: 'M.TextFieldView',
     30
     31    /**
     32     * The name of the text field. During the rendering, this property gets assigned to the name
     33     * property of the text field's html representation. This can be used to manually access the
     34     * text field's DOM representation later on.
     35     *
     36     * @type String
     37     */
     38     name: null,
     39
     40     /**
     41      * The label proeprty defines a text that is shown above or next to the textfield as a 'title'
     42      * for the textfield. e.g. "Name:". If no label is specified, no label will be displayed.
     43      *
     44      * @type String
     45      */
     46     label: null,
     47
     48     /**
     49      * The initial text shown inside the text field describing the input or making a suggestion for input
     50      * e.g. "Please enter your Name."
     51      *
     52      * @type String
     53      */
     54     initialText: '',
     55
     56     /**
     57      * Defines whether the text field is rendered as an password field or not.
     58      *
     59      * @type Boolean
     60      */
     61     isPassword: NO,
     62
     63     /**
     64      * Defines whether the text field has multiple lines respectively is a text area.
     65      *
     66      * @type Boolean
     67      */
     68     hasMultipleLines: NO,
     69
     70     /**
     71      * Renders a TextFieldView
     72      *
     73      * @private
     74      * @returns {String} The text field view's html representation.
     75      */
     76     render: function() {
     77         this.html += '<div ' + this.style() + ' data-role="fieldcontain">';
     78
     79         if(this.label) {
     80             this.html += '<label for="' + (this.name ? this.name : this.id) + '">' + this.label + '</label>';
     81         }
     82
     83         var type = this.isPassword ? 'password' : 'text';
     84
     85         if(this.hasMultipleLines) {
     86             this.html += '<textarea cols="40" rows="8" name="' + (this.name ? this.name : this.id) + '" id="' + this.id + '">' + (this.value ? this.value : this.initialText) + '</textarea>';
     87
     88         } else {
     89             this.html += '<input type="' + type + '" name="' + (this.name ? this.name : this.id) + '" id="' + this.id + '" value="' + (this.value ? this.value : this.initialText) + '" />';
     90         }
     91
     92         this.html += '</div>';
     93
     94         return this.html;
     95     },
     96
     97     /**
     98      * Updates a TextFieldView with DOM access by jQuery.
     99      *
    100      * @private
    101      */
    102     renderUpdate: function() {
    103         $('#' + this.id).val(this.value);
    104         this.styleUpdate();
    105     },
    106
    107     /**
    108      * This method is called whenever the view gets the focus.
    109      * If there is a initial text specified and the value of this text field
    110      * still equals this initial text, the value is emptied.
    111      */
    112     gotFocus: function() {
    113         if(this.initialText && (!this.value || this.initialText === this.value)) {
    114             this.setValue('');
    115             if(this.cssClassOnInit) {
    116                 this.removeCssClass(this.cssClassOnInit);
    117             }
    118         }
    119         this.hasFocus = YES;
    120     },
    121
    122     /**
    123      * This method is called whenever the view lost the focus.
    124      * If there is a initial text specified and the value of this text field
    125      * is empty, the value is set to the initial text.
    126      */
    127     lostFocus: function() {
    128         if(this.initialText && !this.value) {
    129             this.setValue(this.initialText, NO);
    130             this.value = '';
    131             if(this.cssClassOnInit) {
    132                 this.addCssClass(this.cssClassOnInit);
    133             }
    134         }
    135         this.hasFocus = NO;
    136     },
    137
    138     /**
    139      * Method to append css styles inline to the rendered text field.
    140      *
    141      * @private
    142      * @returns {String} The text field's styling as html representation.
    143      */
    144     style: function() {
    145         var html = '';
    146         if(this.isInline) {
    147             if(!html) {
    148                 html += 'style="';
    149             }
    150             html += 'display:inline;';
    151         }
    152         if(!this.isEnabled) {
    153             if(!html) {
    154                 html += 'style="';
    155             }
    156             html += 'disabled="disabled"';
    157         }
    158         if(html) {
    159             html += '"';
    160         }
    161         return html;
    162     },
    163
    164     /**
    165      * Triggers the rendering engine, jQuery mobile, to style the text field.
    166      *
    167      * @private
    168      */
    169     theme: function() {
    170         if(this.initialText && !this.value && this.cssClassOnInit) {
    171             this.addCssClass(this.cssClassOnInit);
    172         }
    173     },
    174
    175     /**
    176      * Method to append css styles inline to the rendered view on the fly.
    177      *
    178      * @private
    179      */
    180     styleUpdate: function() {
    181         if(this.isInline) {
    182             $('#' + this.id).attr('display', 'inline');
    183         } else {
    184             $('#' + this.id).removeAttr('display');
    185         }
    186
    187         if(!this.isEnabled) {
    188             $('#' + this.id).attr('disabled', 'disabled');
    189         } else {
    190             $('#' + this.id).removeAttr('disabled');
    191         }
    192     },
    193
    194     /**
    195      * This method sets its value to the value it has in its DOM representation
    196      * and then delegates these changes to a controller property if the
    197      * contentBindingReverse property is set.
    198      *
    199      * Additionally call target / action if set.
    200      *
    201      * @param {Object} evt The event triggered this method.
    202      */
    203     setValueFromDOM: function(evt) {
    204         this.value = this.secure($('#' + this.id).val());
    205         this.delegateValueUpdate();
    206
    207         if((evt === 'change' && this.triggerActionOnChange || evt === 'keyup' && this.triggerActionOnKeyUp) && this.target && this.action) {
    208             this.target[this.action](this.value);
    209         }
    210     },
    211
    212     /**
    213      * This method sets the text field's value, initiates its re-rendering
    214      * and call the delegateValueUpdate().
    215      *
    216      * @param {String} value The value to be applied to the text field view.
    217      * @param {Boolean} delegateUpdate Determines whether to delegate this value update to any observer or not.
    218      */
    219     setValue: function(value, delegateUpdate) {
    220         this.value = value;
    221         this.renderUpdate();
    222
    223         if(delegateUpdate) {
    224             this.delegateValueUpdate();
    225         }
    226     },
    227
    228     /**
    229      * This method disables the text field by setting the disabled property of its
    230      * html representation to true.
    231      */
    232     disable: function() {
    233         this.isEnabled = NO;
    234         this.renderUpdate();
    235     },
    236
    237     /**
    238      * This method enables the text field by setting the disabled property of its
    239      * html representation to false.
    240      */
    241     enable: function() {
    242         this.isEnabled = YES;
    243         this.renderUpdate();
    244     }
    245
    246 });