diff options
Diffstat (limited to 'catapult/third_party/polymer/components/iron-input/iron-input.html')
-rw-r--r-- | catapult/third_party/polymer/components/iron-input/iron-input.html | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/catapult/third_party/polymer/components/iron-input/iron-input.html b/catapult/third_party/polymer/components/iron-input/iron-input.html new file mode 100644 index 00000000..ddb5277e --- /dev/null +++ b/catapult/third_party/polymer/components/iron-input/iron-input.html @@ -0,0 +1,311 @@ +<!-- +@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-a11y-announcer/iron-a11y-announcer.html"> +<link rel="import" href="../iron-validatable-behavior/iron-validatable-behavior.html"> + +<script> + +/* +`<iron-input>` adds two-way binding and custom validators using `Polymer.IronValidatorBehavior` +to `<input>`. + +### Two-way binding + +By default you can only get notified of changes to an `input`'s `value` due to user input: + + <input value="{{myValue::input}}"> + +`iron-input` adds the `bind-value` property that mirrors the `value` property, and can be used +for two-way data binding. `bind-value` will notify if it is changed either by user input or by script. + + <input is="iron-input" bind-value="{{myValue}}"> + +### Custom validators + +You can use custom validators that implement `Polymer.IronValidatorBehavior` with `<iron-input>`. + + <input is="iron-input" validator="my-custom-validator"> + +### Stopping invalid input + +It may be desirable to only allow users to enter certain characters. You can use the +`prevent-invalid-input` and `allowed-pattern` attributes together to accomplish this. This feature +is separate from validation, and `allowed-pattern` does not affect how the input is validated. + + <!-- only allow characters that match [0-9] --> + <input is="iron-input" prevent-invalid-input allowed-pattern="[0-9]"> + +@hero hero.svg +@demo demo/index.html +*/ + + Polymer({ + + is: 'iron-input', + + extends: 'input', + + behaviors: [ + Polymer.IronValidatableBehavior + ], + + properties: { + + /** + * Use this property instead of `value` for two-way data binding. + */ + bindValue: { + observer: '_bindValueChanged', + type: String + }, + + /** + * Set to true to prevent the user from entering invalid input. If `allowedPattern` is set, + * any character typed by the user will be matched against that pattern, and rejected if it's not a match. + * Pasted input will have each character checked individually; if any character + * doesn't match `allowedPattern`, the entire pasted string will be rejected. + * If `allowedPattern` is not set, it will use the `type` attribute (only supported for `type=number`). + */ + preventInvalidInput: { + type: Boolean + }, + + /** + * Regular expression that list the characters allowed as input. + * This pattern represents the allowed characters for the field; as the user inputs text, + * each individual character will be checked against the pattern (rather than checking + * the entire value as a whole). The recommended format should be a list of allowed characters; + * for example, `[a-zA-Z0-9.+-!;:]` + */ + allowedPattern: { + type: String, + observer: "_allowedPatternChanged" + }, + + _previousValidInput: { + type: String, + value: '' + }, + + _patternAlreadyChecked: { + type: Boolean, + value: false + } + + }, + + listeners: { + 'input': '_onInput', + 'keypress': '_onKeypress' + }, + + registered: function() { + // Feature detect whether we need to patch dispatchEvent (i.e. on FF and IE). + if (!this._canDispatchEventOnDisabled()) { + this._origDispatchEvent = this.dispatchEvent; + this.dispatchEvent = this._dispatchEventFirefoxIE; + } + }, + + created: function() { + Polymer.IronA11yAnnouncer.requestAvailability(); + }, + + _canDispatchEventOnDisabled: function() { + var input = document.createElement('input'); + var canDispatch = false; + input.disabled = true; + + input.addEventListener('feature-check-dispatch-event', function() { + canDispatch = true; + }); + + try { + input.dispatchEvent(new Event('feature-check-dispatch-event')); + } catch(e) {} + + return canDispatch; + }, + + /** + * @this {Node} + * @param {!Event} event + * @return {boolean} + */ + _dispatchEventFirefoxIE: function(event) { + // Due to Firefox bug, events fired on disabled form controls can throw + // errors; furthermore, neither IE nor Firefox will actually dispatch + // events from disabled form controls; as such, we toggle disable around + // the dispatch to allow notifying properties to notify + // See issue #47 for details + var disabled = this.disabled; + this.disabled = false; + var defaultPrevented = this._origDispatchEvent(event); + this.disabled = disabled; + return defaultPrevented + }, + + get _patternRegExp() { + var pattern; + if (this.allowedPattern) { + pattern = new RegExp(this.allowedPattern); + } else { + switch (this.type) { + case 'number': + pattern = /[0-9.,e-]/; + break; + } + } + return pattern; + }, + + ready: function() { + this.bindValue = this.value; + }, + + /** + * @suppress {checkTypes} + */ + _bindValueChanged: function() { + if (this.value !== this.bindValue) { + this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue === false) ? '' : this.bindValue; + } + // manually notify because we don't want to notify until after setting value + this.fire('bind-value-changed', {value: this.bindValue}); + }, + + _allowedPatternChanged: function() { + // Force to prevent invalid input when an `allowed-pattern` is set + this.preventInvalidInput = this.allowedPattern ? true : false; + }, + + _onInput: function() { + // Need to validate each of the characters pasted if they haven't + // been validated inside `_onKeypress` already. + if (this.preventInvalidInput && !this._patternAlreadyChecked) { + var valid = this._checkPatternValidity(); + if (!valid) { + this._announceInvalidCharacter('Invalid string of characters not entered.'); + this.value = this._previousValidInput; + } + } + + this.bindValue = this.value; + this._previousValidInput = this.value; + this._patternAlreadyChecked = false; + }, + + _isPrintable: function(event) { + // What a control/printable character is varies wildly based on the browser. + // - most control characters (arrows, backspace) do not send a `keypress` event + // in Chrome, but the *do* on Firefox + // - in Firefox, when they do send a `keypress` event, control chars have + // a charCode = 0, keyCode = xx (for ex. 40 for down arrow) + // - printable characters always send a keypress event. + // - in Firefox, printable chars always have a keyCode = 0. In Chrome, the keyCode + // always matches the charCode. + // None of this makes any sense. + + // For these keys, ASCII code == browser keycode. + var anyNonPrintable = + (event.keyCode == 8) || // backspace + (event.keyCode == 9) || // tab + (event.keyCode == 13) || // enter + (event.keyCode == 27); // escape + + // For these keys, make sure it's a browser keycode and not an ASCII code. + var mozNonPrintable = + (event.keyCode == 19) || // pause + (event.keyCode == 20) || // caps lock + (event.keyCode == 45) || // insert + (event.keyCode == 46) || // delete + (event.keyCode == 144) || // num lock + (event.keyCode == 145) || // scroll lock + (event.keyCode > 32 && event.keyCode < 41) || // page up/down, end, home, arrows + (event.keyCode > 111 && event.keyCode < 124); // fn keys + + return !anyNonPrintable && !(event.charCode == 0 && mozNonPrintable); + }, + + _onKeypress: function(event) { + if (!this.preventInvalidInput && this.type !== 'number') { + return; + } + var regexp = this._patternRegExp; + if (!regexp) { + return; + } + + // Handle special keys and backspace + if (event.metaKey || event.ctrlKey || event.altKey) + return; + + // Check the pattern either here or in `_onInput`, but not in both. + this._patternAlreadyChecked = true; + + var thisChar = String.fromCharCode(event.charCode); + if (this._isPrintable(event) && !regexp.test(thisChar)) { + event.preventDefault(); + this._announceInvalidCharacter('Invalid character ' + thisChar + ' not entered.'); + } + }, + + _checkPatternValidity: function() { + var regexp = this._patternRegExp; + if (!regexp) { + return true; + } + for (var i = 0; i < this.value.length; i++) { + if (!regexp.test(this.value[i])) { + return false; + } + } + return true; + }, + + /** + * Returns true if `value` is valid. The validator provided in `validator` will be used first, + * then any constraints. + * @return {boolean} True if the value is valid. + */ + validate: function() { + // First, check what the browser thinks. Some inputs (like type=number) + // behave weirdly and will set the value to "" if something invalid is + // entered, but will set the validity correctly. + var valid = this.checkValidity(); + + // Only do extra checking if the browser thought this was valid. + if (valid) { + // Empty, required input is invalid + if (this.required && this.value === '') { + valid = false; + } else if (this.hasValidator()) { + valid = Polymer.IronValidatableBehavior.validate.call(this, this.value); + } + } + + this.invalid = !valid; + this.fire('iron-input-validate'); + return valid; + }, + + _announceInvalidCharacter: function(message) { + this.fire('iron-announce', { text: message }); + } + }); + + /* + The `iron-input-validate` event is fired whenever `validate()` is called. + @event iron-input-validate + */ + +</script> |