| 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>
|
|
|