Index: third_party/polymer/components/paper-input/paper-input.html |
diff --git a/third_party/polymer/components/paper-input/paper-input.html b/third_party/polymer/components/paper-input/paper-input.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..613cca64af7bfdaf30c510f334a0fdc569a6d07f |
--- /dev/null |
+++ b/third_party/polymer/components/paper-input/paper-input.html |
@@ -0,0 +1,433 @@ |
+<!-- |
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE |
+The complete set of authors may be found at http://polymer.github.io/AUTHORS |
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS |
+Code distributed by Google as part of the polymer project is also |
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS |
+--> |
+ |
+<!-- |
+`paper-input` is a single- or multi-line text field where user can enter input. |
+It can optionally have a label. |
+ |
+Example: |
+ |
+ <paper-input label="Your Name"></paper-input> |
+ <paper-input multiline label="Enter multiple lines here"></paper-input> |
+ |
+Theming |
+-------- |
+ |
+Set `CoreStyle.g.paperInput.focusedColor` and `CoreStyle.g.paperInput.invalidColor` to theme |
+the focused and invalid states. |
+ |
+@group Paper Elements |
+@element paper-input |
+@extends core-input |
+@homepage github.io |
+--> |
+<link href="../polymer/polymer.html" rel="import"> |
+<link href="../core-input/core-input.html" rel="import"> |
+<link href="../core-style/core-style.html" rel="import"> |
+ |
+<core-style id="paper-input"> |
+ |
+#label.focused, |
+#floatedLabel.focused { |
+ color: {{g.paperInput.focusedColor}}; |
+} |
+ |
+#underlineHighlight.focused, |
+#caretInner { |
+ background-color: {{g.paperInput.focusedColor}}; |
+} |
+ |
+#error, |
+:host(.invalid) #label.focused, |
+:host(.invalid) #floatedLabel.focused { |
+ color: {{g.paperInput.invalidColor}}; |
+} |
+:host(.invalid) #underlineHighlight.focused, |
+:host(.invalid) #caretInner { |
+ background-color: {{g.paperInput.invalidColor}}; |
+} |
+ |
+</core-style> |
+ |
+<polymer-element name="paper-input" extends="core-input" attributes="label floatingLabel maxRows error" on-down="{{downAction}}" on-up="{{upAction}}"> |
+ |
+ <template> |
+ |
+ <link href="paper-input.css" rel="stylesheet"> |
+ |
+ <core-style ref="paper-input"></core-style> |
+ |
+ <div id="floatedLabel" class="hidden" hidden?="{{!floatingLabel}}"><span id="floatedLabelSpan">{{label}}</span></div> |
+ |
+ <div id="container" on-transitionend="{{transitionEndAction}}" on-webkitTransitionEnd="{{transitionEndAction}}"> |
+ |
+ <div id="label"><span id="labelSpan">{{label}}</span></div> |
+ |
+ <div id="inputContainer"> |
+ |
+ <div id="inputClone"> |
+ <span id="inputCloneSpan" aria-hidden="true"> </span> |
+ </div> |
+ |
+ <template if="{{multiline}}"> |
+ <div id="minInputHeight"></div> |
+ <div id="maxInputHeight"></div> |
+ </template> |
+ |
+ <shadow></shadow> |
+ |
+ </div> |
+ |
+ <div id="underlineContainer"> |
+ <div id="underline"></div> |
+ <div id="underlineHighlight" class="focusedColor"></div> |
+ </div> |
+ |
+ <div id="caret"> |
+ <div id="caretInner" class="focusedColor"></div> |
+ </div> |
+ |
+ </div> |
+ |
+ <div id="errorContainer"> |
+ <div id="error" role="alert" aria-hidden="{{!invalid}}">{{error || validationMessage}}</div> |
+ <div id="errorIcon"></div> |
+ </div> |
+ |
+ </template> |
+ |
+ <script> |
+ |
+ (function() { |
+ |
+ var paperInput = CoreStyle.g.paperInput = CoreStyle.g.paperInput || {}; |
+ paperInput.focusedColor = '#4059a9'; |
+ paperInput.invalidColor = '#d34336'; |
+ |
+ Polymer('paper-input', { |
+ |
+ /** |
+ * The label for this input. It normally appears as grey text inside |
+ * the text input and disappears once the user enters text. |
+ * |
+ * @attribute label |
+ * @type string |
+ * @default '' |
+ */ |
+ label: '', |
+ |
+ /** |
+ * If true, the label will "float" above the text input once the |
+ * user enters text instead of disappearing. |
+ * |
+ * @attribute floatingLabel |
+ * @type boolean |
+ * @default false |
+ */ |
+ floatingLabel: false, |
+ |
+ /** |
+ * (multiline only) If set to a non-zero value, the height of this |
+ * text input will grow with the value changes until it is maxRows |
+ * rows tall. If the maximum size does not fit the value, the text |
+ * input will scroll internally. |
+ * |
+ * @attribute maxRows |
+ * @type number |
+ * @default 0 |
+ */ |
+ maxRows: 0, |
+ |
+ /** |
+ * The message to display if the input value fails validation. If this |
+ * is unset or the empty string, a default message is displayed depending |
+ * on the type of validation error. |
+ * |
+ * @attribute error |
+ * @type string |
+ */ |
+ error: '', |
+ |
+ focused: false, |
+ pressed: false, |
+ |
+ attached: function() { |
+ if (this.multiline) { |
+ this.resizeInput(); |
+ window.requestAnimationFrame(function() { |
+ this.$.underlineContainer.classList.add('animating'); |
+ }.bind(this)); |
+ } |
+ }, |
+ |
+ resizeInput: function() { |
+ var height = this.$.inputClone.getBoundingClientRect().height; |
+ var bounded = this.maxRows > 0 || this.rows > 0; |
+ if (bounded) { |
+ var minHeight = this.$.minInputHeight.getBoundingClientRect().height; |
+ var maxHeight = this.$.maxInputHeight.getBoundingClientRect().height; |
+ height = Math.max(minHeight, Math.min(height, maxHeight)); |
+ } |
+ this.$.inputContainer.style.height = height + 'px'; |
+ this.$.underlineContainer.style.top = height + 'px'; |
+ }, |
+ |
+ prepareLabelTransform: function() { |
+ var toRect = this.$.floatedLabelSpan.getBoundingClientRect(); |
+ var fromRect = this.$.labelSpan.getBoundingClientRect(); |
+ if (toRect.width !== 0) { |
+ this.$.label.cachedTransform = 'scale(' + (toRect.width / fromRect.width) + ') ' + |
+ 'translateY(' + (toRect.bottom - fromRect.bottom) + 'px)'; |
+ } |
+ }, |
+ |
+ toggleLabel: function(force) { |
+ var v = force !== undefined ? force : this.inputValue; |
+ |
+ if (!this.floatingLabel) { |
+ this.$.label.classList.toggle('hidden', v); |
+ } |
+ |
+ if (this.floatingLabel && !this.focused) { |
+ this.$.label.classList.toggle('hidden', v); |
+ this.$.floatedLabel.classList.toggle('hidden', !v); |
+ } |
+ }, |
+ |
+ rowsChanged: function() { |
+ if (this.multiline && !isNaN(parseInt(this.rows))) { |
+ this.$.minInputHeight.innerHTML = ''; |
+ for (var i = 0; i < this.rows; i++) { |
+ this.$.minInputHeight.appendChild(document.createElement('br')); |
+ } |
+ this.resizeInput(); |
+ } |
+ }, |
+ |
+ maxRowsChanged: function() { |
+ if (this.multiline && !isNaN(parseInt(this.maxRows))) { |
+ this.$.maxInputHeight.innerHTML = ''; |
+ for (var i = 0; i < this.maxRows; i++) { |
+ this.$.maxInputHeight.appendChild(document.createElement('br')); |
+ } |
+ this.resizeInput(); |
+ } |
+ }, |
+ |
+ inputValueChanged: function() { |
+ this.super(); |
+ |
+ if (this.multiline) { |
+ var escaped = this.inputValue.replace(/\n/gm, '<br>'); |
+ if (!escaped || escaped.lastIndexOf('<br>') === escaped.length - 4) { |
+ escaped += ' '; |
+ } |
+ this.$.inputCloneSpan.innerHTML = escaped; |
+ this.resizeInput(); |
+ } |
+ |
+ this.toggleLabel(); |
+ }, |
+ |
+ labelChanged: function() { |
+ if (this.floatingLabel && this.$.floatedLabel && this.$.label) { |
+ // If the element is created programmatically, labelChanged is called before |
+ // binding. Run the measuring code in async so the DOM is ready. |
+ this.async(function() { |
+ this.prepareLabelTransform(); |
+ }); |
+ } |
+ }, |
+ |
+ placeholderChanged: function() { |
+ this.label = this.placeholder; |
+ }, |
+ |
+ inputFocusAction: function() { |
+ if (!this.pressed) { |
+ if (this.floatingLabel) { |
+ this.$.floatedLabel.classList.remove('hidden'); |
+ this.$.floatedLabel.classList.add('focused'); |
+ this.$.floatedLabel.classList.add('focusedColor'); |
+ } |
+ this.$.label.classList.add('hidden'); |
+ this.$.underlineHighlight.classList.add('focused'); |
+ this.$.caret.classList.add('focused'); |
+ |
+ this.super(arguments); |
+ } |
+ this.focused = true; |
+ }, |
+ |
+ shouldFloatLabel: function() { |
+ // if type = number, the input value is the empty string until a valid number |
+ // is entered so we must do some hacks here |
+ return this.inputValue || (this.type === 'number' && !this.validity.valid); |
+ }, |
+ |
+ inputBlurAction: function() { |
+ this.super(arguments); |
+ |
+ this.$.underlineHighlight.classList.remove('focused'); |
+ this.$.caret.classList.remove('focused'); |
+ |
+ if (this.floatingLabel) { |
+ this.$.floatedLabel.classList.remove('focused'); |
+ this.$.floatedLabel.classList.remove('focusedColor'); |
+ if (!this.shouldFloatLabel()) { |
+ this.$.floatedLabel.classList.add('hidden'); |
+ } |
+ } |
+ |
+ // type = number hack. see core-input for more info |
+ if (!this.shouldFloatLabel()) { |
+ this.$.label.classList.remove('hidden'); |
+ this.$.label.classList.add('animating'); |
+ this.async(function() { |
+ this.$.label.style.webkitTransform = 'none'; |
+ this.$.label.style.transform = 'none'; |
+ }); |
+ } |
+ |
+ this.focused = false; |
+ }, |
+ |
+ downAction: function(e) { |
+ if (this.disabled) { |
+ return; |
+ } |
+ |
+ if (this.focused) { |
+ return; |
+ } |
+ |
+ this.pressed = true; |
+ var rect = this.$.underline.getBoundingClientRect(); |
+ var right = e.x - rect.left; |
+ this.$.underlineHighlight.style.webkitTransformOriginX = right + 'px'; |
+ this.$.underlineHighlight.style.transformOriginX = right + 'px'; |
+ this.$.underlineHighlight.classList.remove('focused'); |
+ this.underlineAsync = this.async(function() { |
+ this.$.underlineHighlight.classList.add('pressed'); |
+ }, null, 200); |
+ |
+ // No caret animation if there is text in the input. |
+ if (!this.inputValue) { |
+ this.$.caret.classList.remove('focused'); |
+ } |
+ }, |
+ |
+ upAction: function(e) { |
+ if (this.disabled) { |
+ return; |
+ } |
+ |
+ if (!this.pressed) { |
+ return; |
+ } |
+ |
+ // if a touchevent caused the up, the synthentic mouseevents will blur |
+ // the input, make sure to prevent those from being generated. |
+ if (e._source === 'touch') { |
+ e.preventDefault(); |
+ } |
+ |
+ if (this.underlineAsync) { |
+ clearTimeout(this.underlineAsync); |
+ this.underlineAsync = null; |
+ } |
+ |
+ // Focus the input here to bring up the virtual keyboard. |
+ this.$.input.focus(); |
+ this.pressed = false; |
+ this.animating = true; |
+ |
+ this.$.underlineHighlight.classList.remove('pressed'); |
+ this.$.underlineHighlight.classList.add('animating'); |
+ this.async(function() { |
+ this.$.underlineHighlight.classList.add('focused'); |
+ }); |
+ |
+ // No caret animation if there is text in the input. |
+ if (!this.inputValue) { |
+ this.$.caret.classList.add('animating'); |
+ this.async(function() { |
+ this.$.caret.classList.add('focused'); |
+ }, null, 100); |
+ } |
+ |
+ if (this.floatingLabel) { |
+ this.$.label.classList.add('focusedColor'); |
+ this.$.label.classList.add('animating'); |
+ if (!this.$.label.cachedTransform) { |
+ this.prepareLabelTransform(); |
+ } |
+ this.$.label.style.webkitTransform = this.$.label.cachedTransform; |
+ this.$.label.style.transform = this.$.label.cachedTransform; |
+ } |
+ }, |
+ |
+ keydownAction: function() { |
+ this.super(); |
+ |
+ // more type = number hacks. see core-input for more info |
+ if (this.type === 'number') { |
+ this.async(function() { |
+ if (!this.inputValue) { |
+ this.toggleLabel(!this.validity.valid); |
+ } |
+ }); |
+ } |
+ }, |
+ |
+ keypressAction: function() { |
+ if (this.animating) { |
+ this.transitionEndAction(); |
+ } |
+ }, |
+ |
+ transitionEndAction: function(e) { |
+ this.animating = false; |
+ if (this.pressed) { |
+ return; |
+ } |
+ |
+ if (this.focused) { |
+ |
+ if (this.floatingLabel || this.inputValue) { |
+ this.$.label.classList.add('hidden'); |
+ } |
+ |
+ if (this.floatingLabel) { |
+ this.$.label.classList.remove('focusedColor'); |
+ this.$.label.classList.remove('animating'); |
+ this.$.floatedLabel.classList.remove('hidden'); |
+ this.$.floatedLabel.classList.add('focused'); |
+ this.$.floatedLabel.classList.add('focusedColor'); |
+ } |
+ |
+ this.async(function() { |
+ this.$.underlineHighlight.classList.remove('animating'); |
+ this.$.caret.classList.remove('animating'); |
+ }, null, 100); |
+ |
+ } else { |
+ |
+ this.$.label.classList.remove('animating'); |
+ |
+ } |
+ } |
+ |
+ }); |
+ |
+ }()); |
+ |
+ </script> |
+ |
+</polymer-element> |