Home | History | Annotate | Download | only in paper-input
      1 
      2 
      3   (function() {
      4 
      5     var paperInput = CoreStyle.g.paperInput = CoreStyle.g.paperInput || {};
      6     paperInput.focusedColor = '#4059a9';
      7     paperInput.invalidColor = '#d34336';
      8 
      9     Polymer('paper-input', {
     10 
     11       /**
     12        * The label for this input. It normally appears as grey text inside
     13        * the text input and disappears once the user enters text.
     14        *
     15        * @attribute label
     16        * @type string
     17        * @default ''
     18        */
     19       label: '',
     20 
     21       /**
     22        * If true, the label will "float" above the text input once the
     23        * user enters text instead of disappearing.
     24        *
     25        * @attribute floatingLabel
     26        * @type boolean
     27        * @default false
     28        */
     29       floatingLabel: false,
     30 
     31       /**
     32        * (multiline only) If set to a non-zero value, the height of this
     33        * text input will grow with the value changes until it is maxRows
     34        * rows tall. If the maximum size does not fit the value, the text
     35        * input will scroll internally.
     36        *
     37        * @attribute maxRows
     38        * @type number
     39        * @default 0
     40        */
     41       maxRows: 0,
     42 
     43       /**
     44        * The message to display if the input value fails validation. If this
     45        * is unset or the empty string, a default message is displayed depending
     46        * on the type of validation error.
     47        *
     48        * @attribute error
     49        * @type string
     50        */
     51       error: '',
     52 
     53       focused: false,
     54       pressed: false,
     55 
     56       attached: function() {
     57         if (this.multiline) {
     58           this.resizeInput();
     59           window.requestAnimationFrame(function() {
     60             this.$.underlineContainer.classList.add('animating');
     61           }.bind(this));
     62         }
     63       },
     64 
     65       resizeInput: function() {
     66         var height = this.$.inputClone.getBoundingClientRect().height;
     67         var bounded = this.maxRows > 0 || this.rows > 0;
     68         if (bounded) {
     69           var minHeight = this.$.minInputHeight.getBoundingClientRect().height;
     70           var maxHeight = this.$.maxInputHeight.getBoundingClientRect().height;
     71           height = Math.max(minHeight, Math.min(height, maxHeight));
     72         }
     73         this.$.inputContainer.style.height = height + 'px';
     74         this.$.underlineContainer.style.top = height + 'px';
     75       },
     76 
     77       prepareLabelTransform: function() {
     78         var toRect = this.$.floatedLabelSpan.getBoundingClientRect();
     79         var fromRect = this.$.labelSpan.getBoundingClientRect();
     80         if (toRect.width !== 0) {
     81           this.$.label.cachedTransform = 'scale(' + (toRect.width / fromRect.width) + ') ' +
     82             'translateY(' + (toRect.bottom - fromRect.bottom) + 'px)';
     83         }
     84       },
     85 
     86       toggleLabel: function(force) {
     87         var v = force !== undefined ? force : this.inputValue;
     88 
     89         if (!this.floatingLabel) {
     90           this.$.label.classList.toggle('hidden', v);
     91         }
     92 
     93         if (this.floatingLabel && !this.focused) {
     94           this.$.label.classList.toggle('hidden', v);
     95           this.$.floatedLabel.classList.toggle('hidden', !v);
     96         }
     97       },
     98 
     99       rowsChanged: function() {
    100         if (this.multiline && !isNaN(parseInt(this.rows))) {
    101           this.$.minInputHeight.innerHTML = '';
    102           for (var i = 0; i < this.rows; i++) {
    103             this.$.minInputHeight.appendChild(document.createElement('br'));
    104           }
    105           this.resizeInput();
    106         }
    107       },
    108 
    109       maxRowsChanged: function() {
    110         if (this.multiline && !isNaN(parseInt(this.maxRows))) {
    111           this.$.maxInputHeight.innerHTML = '';
    112           for (var i = 0; i < this.maxRows; i++) {
    113             this.$.maxInputHeight.appendChild(document.createElement('br'));
    114           }
    115           this.resizeInput();
    116         }
    117       },
    118 
    119       inputValueChanged: function() {
    120         this.super();
    121 
    122         if (this.multiline) {
    123           var escaped = this.inputValue.replace(/\n/gm, '<br>');
    124           if (!escaped || escaped.lastIndexOf('<br>') === escaped.length - 4) {
    125             escaped += '&nbsp';
    126           }
    127           this.$.inputCloneSpan.innerHTML = escaped;
    128           this.resizeInput();
    129         }
    130 
    131         this.toggleLabel();
    132       },
    133 
    134       labelChanged: function() {
    135         if (this.floatingLabel && this.$.floatedLabel && this.$.label) {
    136           // If the element is created programmatically, labelChanged is called before
    137           // binding. Run the measuring code in async so the DOM is ready.
    138           this.async(function() {
    139             this.prepareLabelTransform();
    140           });
    141         }
    142       },
    143 
    144       placeholderChanged: function() {
    145         this.label = this.placeholder;
    146       },
    147 
    148       inputFocusAction: function() {
    149         if (!this.pressed) {
    150           if (this.floatingLabel) {
    151             this.$.floatedLabel.classList.remove('hidden');
    152             this.$.floatedLabel.classList.add('focused');
    153             this.$.floatedLabel.classList.add('focusedColor');
    154           }
    155           this.$.label.classList.add('hidden');
    156           this.$.underlineHighlight.classList.add('focused');
    157           this.$.caret.classList.add('focused');
    158 
    159           this.super(arguments);
    160         }
    161         this.focused = true;
    162       },
    163 
    164       shouldFloatLabel: function() {
    165         // if type = number, the input value is the empty string until a valid number
    166         // is entered so we must do some hacks here
    167         return this.inputValue || (this.type === 'number' && !this.validity.valid);
    168       },
    169 
    170       inputBlurAction: function() {
    171         this.super(arguments);
    172 
    173         this.$.underlineHighlight.classList.remove('focused');
    174         this.$.caret.classList.remove('focused');
    175 
    176         if (this.floatingLabel) {
    177           this.$.floatedLabel.classList.remove('focused');
    178           this.$.floatedLabel.classList.remove('focusedColor');
    179           if (!this.shouldFloatLabel()) {
    180             this.$.floatedLabel.classList.add('hidden');
    181           }
    182         }
    183 
    184         // type = number hack. see core-input for more info
    185         if (!this.shouldFloatLabel()) {
    186           this.$.label.classList.remove('hidden');
    187           this.$.label.classList.add('animating');
    188           this.async(function() {
    189             this.$.label.style.webkitTransform = 'none';
    190             this.$.label.style.transform = 'none';
    191           });
    192         }
    193 
    194         this.focused = false;
    195       },
    196 
    197       downAction: function(e) {
    198         if (this.disabled) {
    199           return;
    200         }
    201 
    202         if (this.focused) {
    203           return;
    204         }
    205 
    206         this.pressed = true;
    207         var rect = this.$.underline.getBoundingClientRect();
    208         var right = e.x - rect.left;
    209         this.$.underlineHighlight.style.webkitTransformOriginX = right + 'px';
    210         this.$.underlineHighlight.style.transformOriginX = right + 'px';
    211         this.$.underlineHighlight.classList.remove('focused');
    212         this.underlineAsync = this.async(function() {
    213           this.$.underlineHighlight.classList.add('pressed');
    214         }, null, 200);
    215 
    216         // No caret animation if there is text in the input.
    217         if (!this.inputValue) {
    218           this.$.caret.classList.remove('focused');
    219         }
    220       },
    221 
    222       upAction: function(e) {
    223         if (this.disabled) {
    224           return;
    225         }
    226 
    227         if (!this.pressed) {
    228           return;
    229         }
    230 
    231         // if a touchevent caused the up, the synthentic mouseevents will blur
    232         // the input, make sure to prevent those from being generated.
    233         if (e._source === 'touch') {
    234           e.preventDefault();
    235         }
    236 
    237         if (this.underlineAsync) {
    238           clearTimeout(this.underlineAsync);
    239           this.underlineAsync = null;
    240         }
    241 
    242         // Focus the input here to bring up the virtual keyboard.
    243         this.$.input.focus();
    244         this.pressed = false;
    245         this.animating = true;
    246 
    247         this.$.underlineHighlight.classList.remove('pressed');
    248         this.$.underlineHighlight.classList.add('animating');
    249         this.async(function() {
    250           this.$.underlineHighlight.classList.add('focused');
    251         });
    252 
    253         // No caret animation if there is text in the input.
    254         if (!this.inputValue) {
    255           this.$.caret.classList.add('animating');
    256           this.async(function() {
    257             this.$.caret.classList.add('focused');
    258           }, null, 100);
    259         }
    260 
    261         if (this.floatingLabel) {
    262           this.$.label.classList.add('focusedColor');
    263           this.$.label.classList.add('animating');
    264           if (!this.$.label.cachedTransform) {
    265             this.prepareLabelTransform();
    266           }
    267           this.$.label.style.webkitTransform = this.$.label.cachedTransform;
    268           this.$.label.style.transform = this.$.label.cachedTransform;
    269         }
    270       },
    271 
    272       keydownAction: function() {
    273         this.super();
    274 
    275         // more type = number hacks. see core-input for more info
    276         if (this.type === 'number') {
    277           this.async(function() {
    278             if (!this.inputValue) {
    279               this.toggleLabel(!this.validity.valid);
    280             }
    281           });
    282         }
    283       },
    284 
    285       keypressAction: function() {
    286         if (this.animating) {
    287           this.transitionEndAction();
    288         }
    289       },
    290 
    291       transitionEndAction: function(e) {
    292         this.animating = false;
    293         if (this.pressed) {
    294           return;
    295         }
    296 
    297         if (this.focused) {
    298 
    299           if (this.floatingLabel || this.inputValue) {
    300             this.$.label.classList.add('hidden');
    301           }
    302 
    303           if (this.floatingLabel) {
    304             this.$.label.classList.remove('focusedColor');
    305             this.$.label.classList.remove('animating');
    306             this.$.floatedLabel.classList.remove('hidden');
    307             this.$.floatedLabel.classList.add('focused');
    308             this.$.floatedLabel.classList.add('focusedColor');
    309           }
    310 
    311           this.async(function() {
    312             this.$.underlineHighlight.classList.remove('animating');
    313             this.$.caret.classList.remove('animating');
    314           }, null, 100);
    315 
    316         } else {
    317 
    318           this.$.label.classList.remove('animating');
    319 
    320         }
    321       }
    322 
    323     });
    324 
    325   }());
    326 
    327