| OLD | NEW | 
 | (Empty) | 
|    1 <!-- |  | 
|    2 @license |  | 
|    3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. |  | 
|    4 This code may only be used under the BSD style license found at http://polymer.g
     ithub.io/LICENSE.txt |  | 
|    5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |  | 
|    6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
     BUTORS.txt |  | 
|    7 Code distributed by Google as part of the polymer project is also |  | 
|    8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
     TS.txt |  | 
|    9 --> |  | 
|   10  |  | 
|   11 <link rel="import" href="../polymer/polymer.html"> |  | 
|   12 <link rel="import" href="../paper-styles/paper-styles.html"> |  | 
|   13  |  | 
|   14 <!-- |  | 
|   15 `<paper-input-container>` is a container for a `<label>`, an `<input is="iron-in
     put">` or |  | 
|   16 `<iron-autogrow-textarea>` and optional add-on elements such as an error message
      or character |  | 
|   17 counter, used to implement Material Design text fields. |  | 
|   18  |  | 
|   19 For example: |  | 
|   20  |  | 
|   21     <paper-input-container> |  | 
|   22       <label>Your name</label> |  | 
|   23       <input is="iron-input"> |  | 
|   24     </paper-input-container> |  | 
|   25  |  | 
|   26 ### Listening for input changes |  | 
|   27  |  | 
|   28 By default, it listens for changes on the `bind-value` attribute on its children
      nodes and perform |  | 
|   29 tasks such as auto-validating and label styling when the `bind-value` changes. Y
     ou can configure |  | 
|   30 the attribute it listens to with the `attr-for-value` attribute. |  | 
|   31  |  | 
|   32 ### Using a custom input element |  | 
|   33  |  | 
|   34 You can use a custom input element in a `<paper-input-container>`, for example t
     o implement a |  | 
|   35 compound input field like a social security number input. The custom input eleme
     nt should have the |  | 
|   36 `paper-input-input` class, have a `notify:true` value property and optionally im
     plements |  | 
|   37 `Polymer.IronValidatableBehavior` if it is validatble. |  | 
|   38  |  | 
|   39     <paper-input-container attr-for-value="ssn-value"> |  | 
|   40       <label>Social security number</label> |  | 
|   41       <ssn-input class="paper-input-input"></ssn-input> |  | 
|   42     </paper-input-container> |  | 
|   43  |  | 
|   44 ### Validation |  | 
|   45  |  | 
|   46 If the `auto-validate` attribute is set, the input container will validate the i
     nput and update |  | 
|   47 the container styling when the input value changes. |  | 
|   48  |  | 
|   49 ### Add-ons |  | 
|   50  |  | 
|   51 Add-ons are child elements of a `<paper-input-container>` with the `add-on` attr
     ibute and |  | 
|   52 implements the `Polymer.PaperInputAddonBehavior` behavior. They are notified whe
     n the input value |  | 
|   53 or validity changes, and may implement functionality such as error messages or c
     haracter counters. |  | 
|   54 They appear at the bottom of the input. |  | 
|   55  |  | 
|   56 ### Styling |  | 
|   57  |  | 
|   58 The following custom properties and mixins are available for styling: |  | 
|   59  |  | 
|   60 Custom property | Description | Default |  | 
|   61 ----------------|-------------|---------- |  | 
|   62 `--paper-input-container-color` | Label and underline color when the input is no
     t focused | `--secondary-text-color` |  | 
|   63 `--paper-input-container-focus-color` | Label and underline color when the input
      is focused | `--default-primary-color` |  | 
|   64 `--paper-input-container-invalid-color` | Label and underline color when the inp
     ut is focused | `--google-red-500` |  | 
|   65 `--paper-input-container-input-color` | Input foreground color | `--primary-text
     -color` |  | 
|   66 `--paper-input-container` | Mixin applied to the container | `{}` |  | 
|   67 `--paper-input-container-label` | Mixin applied to the label | `{}` |  | 
|   68 `--paper-input-container-label-focus` | Mixin applied to the label when the inpu
     t is focused | `{}` |  | 
|   69 `--paper-input-container-input` | Mixin applied to the input | `{}` |  | 
|   70 `--paper-input-container-underline` | Mixin applied to the underline | `{}` |  | 
|   71 `--paper-input-container-underline-focus` | Mixin applied to the underline when 
     the input is focued | `{}` |  | 
|   72 `--paper-input-container-underline-disabled` | Mixin applied to the underline wh
     en the input is disabled | `{}` |  | 
|   73  |  | 
|   74 This element is `display:block` by default, but you can set the `inline` attribu
     te to make it |  | 
|   75 `display:inline-block`. |  | 
|   76 --> |  | 
|   77 <dom-module id="paper-input-container"> |  | 
|   78  |  | 
|   79   <style> |  | 
|   80  |  | 
|   81     :host { |  | 
|   82       display: block; |  | 
|   83       padding: 8px 0; |  | 
|   84  |  | 
|   85       @apply(--paper-input-container); |  | 
|   86     } |  | 
|   87  |  | 
|   88     :host[inline] { |  | 
|   89       display: inline-block; |  | 
|   90     } |  | 
|   91  |  | 
|   92     :host([disabled]) { |  | 
|   93       pointer-events: none; |  | 
|   94       opacity: 0.33; |  | 
|   95     } |  | 
|   96  |  | 
|   97     .floated-label-placeholder { |  | 
|   98       @apply(--paper-font-caption); |  | 
|   99     } |  | 
|  100  |  | 
|  101     .underline { |  | 
|  102       position: relative; |  | 
|  103     } |  | 
|  104  |  | 
|  105     .focused-line { |  | 
|  106       height: 2px; |  | 
|  107  |  | 
|  108       -webkit-transform-origin: center center; |  | 
|  109       transform-origin: center center; |  | 
|  110       -webkit-transform: scale3d(0,1,1); |  | 
|  111       transform: scale3d(0,1,1); |  | 
|  112  |  | 
|  113       background: var(--paper-input-container-focus-color, --default-primary-col
     or); |  | 
|  114  |  | 
|  115       @apply(--paper-input-container-underline-focus); |  | 
|  116     } |  | 
|  117  |  | 
|  118     .underline.is-highlighted .focused-line { |  | 
|  119       -webkit-transform: none; |  | 
|  120       transform: none; |  | 
|  121       -webkit-transition: -webkit-transform 0.25s; |  | 
|  122       transition: transform 0.25s; |  | 
|  123  |  | 
|  124       @apply(--paper-transition-easing); |  | 
|  125     } |  | 
|  126  |  | 
|  127     .underline.is-invalid .focused-line { |  | 
|  128       background: var(--paper-input-container-invalid-color, --google-red-500); |  | 
|  129  |  | 
|  130       -webkit-transform: none; |  | 
|  131       transform: none; |  | 
|  132       -webkit-transition: -webkit-transform 0.25s; |  | 
|  133       transition: transform 0.25s; |  | 
|  134  |  | 
|  135       @apply(--paper-transition-easing); |  | 
|  136     } |  | 
|  137  |  | 
|  138     .unfocused-line { |  | 
|  139       height: 1px; |  | 
|  140       background: var(--paper-input-container-color, --secondary-text-color); |  | 
|  141  |  | 
|  142       @apply(--paper-input-container-underline); |  | 
|  143     } |  | 
|  144  |  | 
|  145     :host([disabled]) .unfocused-line { |  | 
|  146       border-bottom: 1px dashed; |  | 
|  147       border-color: var(--paper-input-container-color, --secondary-text-color); |  | 
|  148       background: transparent; |  | 
|  149  |  | 
|  150       @apply(--paper-input-container-underline-disabled); |  | 
|  151     } |  | 
|  152  |  | 
|  153     .input-content { |  | 
|  154       position: relative; |  | 
|  155     } |  | 
|  156  |  | 
|  157     .input-content ::content label, |  | 
|  158     .input-content ::content .paper-input-label { |  | 
|  159       position: absolute; |  | 
|  160       top: 0; |  | 
|  161       right: 0; |  | 
|  162       left: 0; |  | 
|  163       font: inherit; |  | 
|  164       color: var(--paper-input-container-color, --secondary-text-color); |  | 
|  165  |  | 
|  166       @apply(--paper-font-subhead); |  | 
|  167       @apply(--paper-input-container-label); |  | 
|  168     } |  | 
|  169  |  | 
|  170     .input-content.label-is-floating ::content label, |  | 
|  171     .input-content.label-is-floating ::content .paper-input-label { |  | 
|  172       -webkit-transform: translate3d(0, -75%, 0) scale(0.75); |  | 
|  173       transform: translate3d(0, -75%, 0) scale(0.75); |  | 
|  174       -webkit-transform-origin: left top; |  | 
|  175       transform-origin: left top; |  | 
|  176       -webkit-transition: -webkit-transform 0.25s; |  | 
|  177       transition: transform 0.25s; |  | 
|  178  |  | 
|  179       @apply(--paper-transition-easing); |  | 
|  180     } |  | 
|  181  |  | 
|  182     .input-content.label-is-highlighted ::content label, |  | 
|  183     .input-content.label-is-highlighted ::content .paper-input-label { |  | 
|  184       color: var(--paper-input-container-focus-color, --default-primary-color); |  | 
|  185  |  | 
|  186       @apply(--paper-input-container-label-focus); |  | 
|  187     } |  | 
|  188  |  | 
|  189     .input-content.is-invalid ::content label, |  | 
|  190     .input-content.is-invalid ::content .paper-input-label { |  | 
|  191       color: var(--paper-input-container-invalid-color, --google-red-500); |  | 
|  192     } |  | 
|  193  |  | 
|  194     .input-content.label-is-hidden ::content label, |  | 
|  195     .input-content.label-is-hidden ::content .paper-input-label { |  | 
|  196       visibility: hidden; |  | 
|  197     } |  | 
|  198  |  | 
|  199     .input-content ::content input, |  | 
|  200     .input-content ::content textarea, |  | 
|  201     .input-content ::content iron-autogrow-textarea, |  | 
|  202     .input-content ::content .paper-input-input { |  | 
|  203       position: relative; /* to make a stacking context */ |  | 
|  204       outline: none; |  | 
|  205       box-shadow: none; |  | 
|  206       padding: 0; |  | 
|  207       width: 100%; |  | 
|  208       background: transparent; |  | 
|  209       border: none; |  | 
|  210       color: var(--paper-input-container-input-color, --primary-text-color); |  | 
|  211  |  | 
|  212       @apply(--paper-font-subhead); |  | 
|  213       @apply(--paper-input-container-input); |  | 
|  214     } |  | 
|  215  |  | 
|  216     /* Firefox sets a min-width on the input, which can cause layout issues */ |  | 
|  217     .input-content ::content input { |  | 
|  218       min-width: 0; |  | 
|  219     } |  | 
|  220  |  | 
|  221     .input-content ::content textarea { |  | 
|  222       resize: none; |  | 
|  223     } |  | 
|  224  |  | 
|  225     .add-on-content.is-invalid ::content * { |  | 
|  226       color: var(--paper-input-container-invalid-color, --google-red-500); |  | 
|  227     } |  | 
|  228  |  | 
|  229     .add-on-content.is-highlighted ::content * { |  | 
|  230       color: var(--paper-input-container-focus-color, --default-primary-color); |  | 
|  231     } |  | 
|  232  |  | 
|  233   </style> |  | 
|  234  |  | 
|  235   <template> |  | 
|  236  |  | 
|  237     <template is="dom-if" if="[[!noLabelFloat]]"> |  | 
|  238       <div class="floated-label-placeholder"> </div> |  | 
|  239     </template> |  | 
|  240  |  | 
|  241     <div class$="[[_computeInputContentClass(noLabelFloat,alwaysFloatLabel,focus
     ed,invalid,_inputHasContent)]]"> |  | 
|  242       <content select=":not([add-on])"></content> |  | 
|  243     </div> |  | 
|  244  |  | 
|  245     <div class$="[[_computeUnderlineClass(focused,invalid)]]"> |  | 
|  246       <div class="unfocused-line fit"></div> |  | 
|  247       <div class="focused-line fit"></div> |  | 
|  248     </div> |  | 
|  249  |  | 
|  250     <div class$="[[_computeAddOnContentClass(focused,invalid)]]"> |  | 
|  251       <content id="addOnContent" select="[add-on]"></content> |  | 
|  252     </div> |  | 
|  253  |  | 
|  254   </template> |  | 
|  255  |  | 
|  256 </dom-module> |  | 
|  257  |  | 
|  258 <script> |  | 
|  259 (function() { |  | 
|  260  |  | 
|  261   Polymer({ |  | 
|  262  |  | 
|  263     is: 'paper-input-container', |  | 
|  264  |  | 
|  265     properties: { |  | 
|  266  |  | 
|  267       /** |  | 
|  268        * Set to true to disable the floating label. The label disappears when th
     e input value is |  | 
|  269        * not null. |  | 
|  270        */ |  | 
|  271       noLabelFloat: { |  | 
|  272         type: Boolean, |  | 
|  273         value: false |  | 
|  274       }, |  | 
|  275  |  | 
|  276       /** |  | 
|  277        * Set to true to always float the floating label. |  | 
|  278        */ |  | 
|  279       alwaysFloatLabel: { |  | 
|  280         type: Boolean, |  | 
|  281         value: false |  | 
|  282       }, |  | 
|  283  |  | 
|  284       /** |  | 
|  285        * The attribute to listen for value changes on. |  | 
|  286        */ |  | 
|  287       attrForValue: { |  | 
|  288         type: String, |  | 
|  289         value: 'bind-value' |  | 
|  290       }, |  | 
|  291  |  | 
|  292       /** |  | 
|  293        * Set to true to auto-validate the input value when it changes. |  | 
|  294        */ |  | 
|  295       autoValidate: { |  | 
|  296         type: Boolean, |  | 
|  297         value: false |  | 
|  298       }, |  | 
|  299  |  | 
|  300       /** |  | 
|  301        * True if the input is invalid. This property is set automatically when t
     he input value |  | 
|  302        * changes if auto-validating, or when the `iron-input-valid` event is hea
     rd from a child. |  | 
|  303        */ |  | 
|  304       invalid: { |  | 
|  305         observer: '_invalidChanged', |  | 
|  306         type: Boolean, |  | 
|  307         value: false |  | 
|  308       }, |  | 
|  309  |  | 
|  310       /** |  | 
|  311        * True if the input has focus. |  | 
|  312        */ |  | 
|  313       focused: { |  | 
|  314         readOnly: true, |  | 
|  315         type: Boolean, |  | 
|  316         value: false |  | 
|  317       }, |  | 
|  318  |  | 
|  319       _addons: { |  | 
|  320         type: Array |  | 
|  321         // do not set a default value here intentionally - it will be initialize
     d lazily when a |  | 
|  322         // distributed child is attached, which may occur before configuration f
     or this element |  | 
|  323         // in polyfill. |  | 
|  324       }, |  | 
|  325  |  | 
|  326       _inputHasContent: { |  | 
|  327         type: Boolean, |  | 
|  328         value: false |  | 
|  329       }, |  | 
|  330  |  | 
|  331       _inputSelector: { |  | 
|  332         type: String, |  | 
|  333         value: 'input,textarea,.paper-input-input' |  | 
|  334       }, |  | 
|  335  |  | 
|  336       _boundOnFocus: { |  | 
|  337         type: Function, |  | 
|  338         value: function() { |  | 
|  339           return this._onFocus.bind(this); |  | 
|  340         } |  | 
|  341       }, |  | 
|  342  |  | 
|  343       _boundOnBlur: { |  | 
|  344         type: Function, |  | 
|  345         value: function() { |  | 
|  346           return this._onBlur.bind(this); |  | 
|  347         } |  | 
|  348       }, |  | 
|  349  |  | 
|  350       _boundOnInput: { |  | 
|  351         type: Function, |  | 
|  352         value: function() { |  | 
|  353           return this._onInput.bind(this); |  | 
|  354         } |  | 
|  355       }, |  | 
|  356  |  | 
|  357       _boundValueChanged: { |  | 
|  358         type: Function, |  | 
|  359         value: function() { |  | 
|  360           return this._onValueChanged.bind(this); |  | 
|  361         } |  | 
|  362       } |  | 
|  363  |  | 
|  364     }, |  | 
|  365  |  | 
|  366     listeners: { |  | 
|  367       'addon-attached': '_onAddonAttached', |  | 
|  368       'iron-input-validate': '_onIronInputValidate' |  | 
|  369     }, |  | 
|  370  |  | 
|  371     get _valueChangedEvent() { |  | 
|  372       return this.attrForValue + '-changed'; |  | 
|  373     }, |  | 
|  374  |  | 
|  375     get _propertyForValue() { |  | 
|  376       return Polymer.CaseMap.dashToCamelCase(this.attrForValue); |  | 
|  377     }, |  | 
|  378  |  | 
|  379     get _inputElement() { |  | 
|  380       return Polymer.dom(this).querySelector(this._inputSelector); |  | 
|  381     }, |  | 
|  382  |  | 
|  383     ready: function() { |  | 
|  384       if (!this._addons) { |  | 
|  385         this._addons = []; |  | 
|  386       } |  | 
|  387       this.addEventListener('focus', this._boundOnFocus, true); |  | 
|  388       this.addEventListener('blur', this._boundOnBlur, true); |  | 
|  389       if (this.attrForValue) { |  | 
|  390         this._inputElement.addEventListener(this._valueChangedEvent, this._bound
     ValueChanged); |  | 
|  391       } else { |  | 
|  392         this.addEventListener('input', this._onInput); |  | 
|  393       } |  | 
|  394     }, |  | 
|  395  |  | 
|  396     attached: function() { |  | 
|  397       this._handleValue(this._inputElement); |  | 
|  398     }, |  | 
|  399  |  | 
|  400     _onAddonAttached: function(event) { |  | 
|  401       if (!this._addons) { |  | 
|  402         this._addons = []; |  | 
|  403       } |  | 
|  404       var target = event.target; |  | 
|  405       if (this._addons.indexOf(target) === -1) { |  | 
|  406         this._addons.push(target); |  | 
|  407         if (this.isAttached) { |  | 
|  408           this._handleValue(this._inputElement); |  | 
|  409         } |  | 
|  410       } |  | 
|  411     }, |  | 
|  412  |  | 
|  413     _onFocus: function() { |  | 
|  414       this._setFocused(true); |  | 
|  415     }, |  | 
|  416  |  | 
|  417     _onBlur: function() { |  | 
|  418       this._setFocused(false); |  | 
|  419     }, |  | 
|  420  |  | 
|  421     _onInput: function(event) { |  | 
|  422       this._handleValue(event.target); |  | 
|  423     }, |  | 
|  424  |  | 
|  425     _onValueChanged: function(event) { |  | 
|  426       this._handleValue(event.target); |  | 
|  427     }, |  | 
|  428  |  | 
|  429     _handleValue: function(inputElement) { |  | 
|  430       var value = inputElement[this._propertyForValue] || inputElement.value; |  | 
|  431  |  | 
|  432       if (this.autoValidate) { |  | 
|  433         var valid; |  | 
|  434         if (inputElement.validate) { |  | 
|  435           valid = inputElement.validate(value); |  | 
|  436         } else { |  | 
|  437           valid = inputElement.checkValidity(); |  | 
|  438         } |  | 
|  439         this.invalid = !valid; |  | 
|  440       } |  | 
|  441  |  | 
|  442       // type="number" hack needed because this.value is empty until it's valid |  | 
|  443       if (value || (inputElement.type === 'number' && !inputElement.checkValidit
     y())) { |  | 
|  444         this._inputHasContent = true; |  | 
|  445       } else { |  | 
|  446         this._inputHasContent = false; |  | 
|  447       } |  | 
|  448  |  | 
|  449       this.updateAddons({ |  | 
|  450         inputElement: inputElement, |  | 
|  451         value: value, |  | 
|  452         invalid: this.invalid |  | 
|  453       }); |  | 
|  454     }, |  | 
|  455  |  | 
|  456     _onIronInputValidate: function(event) { |  | 
|  457       this.invalid = this._inputElement.invalid; |  | 
|  458     }, |  | 
|  459  |  | 
|  460     _invalidChanged: function() { |  | 
|  461       if (this._addons) { |  | 
|  462         this.updateAddons({invalid: this.invalid}); |  | 
|  463       } |  | 
|  464     }, |  | 
|  465  |  | 
|  466     /** |  | 
|  467      * Call this to update the state of add-ons. |  | 
|  468      * @param {Object} state Add-on state. |  | 
|  469      */ |  | 
|  470     updateAddons: function(state) { |  | 
|  471       for (var addon, index = 0; addon = this._addons[index]; index++) { |  | 
|  472         addon.update(state); |  | 
|  473       } |  | 
|  474     }, |  | 
|  475  |  | 
|  476     _computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused,
      invalid, _inputHasContent) { |  | 
|  477       var cls = 'input-content'; |  | 
|  478       if (!noLabelFloat) { |  | 
|  479         if (alwaysFloatLabel || _inputHasContent) { |  | 
|  480           cls += ' label-is-floating'; |  | 
|  481           if (invalid) { |  | 
|  482             cls += ' is-invalid'; |  | 
|  483           } else if (focused) { |  | 
|  484             cls += " label-is-highlighted"; |  | 
|  485           } |  | 
|  486         } |  | 
|  487       } else { |  | 
|  488         if (_inputHasContent) { |  | 
|  489           cls += ' label-is-hidden'; |  | 
|  490         } |  | 
|  491       } |  | 
|  492       return cls; |  | 
|  493     }, |  | 
|  494  |  | 
|  495     _computeUnderlineClass: function(focused, invalid) { |  | 
|  496       var cls = 'underline'; |  | 
|  497       if (invalid) { |  | 
|  498         cls += ' is-invalid'; |  | 
|  499       } else if (focused) { |  | 
|  500         cls += ' is-highlighted' |  | 
|  501       } |  | 
|  502       return cls; |  | 
|  503     }, |  | 
|  504  |  | 
|  505     _computeAddOnContentClass: function(focused, invalid) { |  | 
|  506       var cls = 'add-on-content'; |  | 
|  507       if (invalid) { |  | 
|  508         cls += ' is-invalid'; |  | 
|  509       } else if (focused) { |  | 
|  510         cls += ' is-highlighted' |  | 
|  511       } |  | 
|  512       return cls; |  | 
|  513     } |  | 
|  514  |  | 
|  515   }); |  | 
|  516  |  | 
|  517 })(); |  | 
|  518 </script> |  | 
| OLD | NEW |