UNPKG

npm-polymer-elements

Version:

Polymer Elements package for npm

246 lines (201 loc) 7.03 kB
<!-- @license Copyright (c) 2015 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.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt 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.txt --> <link rel="import" href="../polymer/polymer.html"> <link rel="import" href="../iron-flex-layout/iron-flex-layout.html"> <link rel="import" href="../paper-input/paper-input-behavior.html"> <link rel="import" href="../paper-input/paper-input-container.html"> <link rel="import" href="../paper-input/paper-input-error.html"> <link rel="import" href="../iron-input/iron-input.html"> <link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html"> <link rel="import" href="../iron-icon/iron-icon.html"> <script src="cc-validator.js"></script> <!-- `gold-cc-input` is a single-line text field with Material Design styling for entering a credit card number. As the user types, the number will be formatted by adding a space every 4 digits. <gold-cc-input></gold-cc-input> It may include an optional label, which by default is "Card number". <gold-cc-input label="CC"></gold-cc-input> ### Validation The input can detect whether a credit card number is valid, and the type of credit card it is, using the Luhn checksum. See `http://jquerycreditcardvalidator.com/` for more information. The input can be automatically validated as the user is typing by using the `auto-validate` and `required` attributes. For manual validation, the element also has a `validate()` method, which returns the validity of the input as well sets any appropriate error messages and styles. See `Polymer.PaperInputBehavior` for more API docs. ### Styling See `Polymer.PaperInputContainer` for a list of custom properties used to style this element. @group Gold Elements @hero hero.svg @demo demo/index.html @class gold-cc-input --> <dom-module id="gold-cc-input"> <style> :host { display: block; } /* Use a container so that when hiding the icon, the layout doesn't jump around. */ .icon-container { margin-left: 10px; height: 27px; } iron-icon { --iron-icon-width: 40px; --iron-icon-height: 24px; } .container { @apply(--layout-horizontal); } </style> <template> <paper-input-container id="container" disabled$="[[disabled]]" no-label-float="[[noLabelFloat]]" always-float-label="[[_computeAlwaysFloatLabel(alwaysFloatLabel,placeholder)]]" invalid="[[invalid]]"> <label hidden$="[[!label]]">[[label]]</label> <div class="container"> <input is="iron-input" id="input" aria-labelledby$="[[_ariaLabelledBy]]" aria-describedby$="[[_ariaDescribedBy]]" bind-value="{{value}}" type="tel" maxlength="30" required$="[[required]]" allowed-pattern="[0-9 ]" prevent-invalid-input autocomplete="cc-number" name$="[[name]]" disabled$="[[disabled]]" invalid="{{invalid}}" autofocus$="[[autofocus]]" inputmode$="[[inputmode]]" placeholder$="[[placeholder]]" readonly$="[[readonly]]" size$="[[size]]"> <div class="icon-container"><iron-icon id="icon"></iron-icon></div> </div> <template is="dom-if" if="[[errorMessage]]"> <paper-input-error>[[errorMessage]]</paper-input-error> </template> </paper-input-container> </template> </dom-module> <script> (function() { Polymer({ is: 'gold-cc-input', behaviors: [ Polymer.PaperInputBehavior, Polymer.IronValidatableBehavior, Polymer.IronFormElementBehavior ], properties: { /** * The label for this input. */ label: { type: String, value: "Card number" }, /** * The type of the credit card, if it is valid. Empty otherwise. */ cardType: { type: String, notify: true }, value: { observer: '_onValueChanged' } }, observers: [ '_onFocusedChanged(focused)' ], ready: function() { // If there's an initial input, validate it. if (this.value) this._handleAutoValidate(); }, /** * A handler that is called on input */ _onValueChanged: function(value, oldValue) { // The initial property assignment is handled by `ready`. if (oldValue == undefined) return; var start = this.$.input.selectionStart; var previousCharASpace = value ? this.value.charAt(start - 1) == ' ' : false; var value = value.replace(/\s+/g, ''); var formattedValue = ''; for (var i = 0; i < value.length; i++) { // Add a space after every 4 characters. if ((i != 0) && (i % 4 == 0)) { formattedValue += ' '; } formattedValue += value[i]; } this.updateValueAndPreserveCaret(formattedValue.trim()); // If the character right before the selection is a newly inserted // space, we need to advance the selection to maintain the caret position. if (!previousCharASpace && this.value.charAt(start - 1) == ' ') { this.$.input.selectionStart = start+1; this.$.input.selectionEnd = start+1; } this._handleAutoValidate(); }, /** * Returns true if the element has a valid value, and sets the visual * error state. * * @return {boolean} Whether the input is currently valid or not. */ validate: function() { // Empty, non-required input is valid. if (!this.required && this.value == '') { return true; } var result = CreditCardValidator.validate(this.value); var valid = result.valid && result.length_valid; this.cardType = valid ? result.card_type.name : ''; // Update the container and its addons (i.e. the custom error-message). this.$.container.invalid = !valid; this.$.container.updateAddons({ inputElement: this.$.input, value: this.value, invalid: !valid }); // We don't have icons for all the card types. if (valid && result.card_type.icon) { this.$.icon.src = this.resolveUrl(result.card_type.icon); this.$.icon.alt = this.cardType; this.$.icon.hidden = false; } else { this.$.icon.src = null; this.$.icon.alt = ''; this.$.icon.hidden = true; } return valid; }, /** * Overidden from Polymer.IronControlState. */ _onFocusedChanged: function(focused) { if (!focused) { this._handleAutoValidate(); } } }) })(); </script>