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 += ' '; 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