Project import generated by Copybara.
GitOrigin-RevId: 63746295f1a5ab5a619056791995793d65529e62
diff --git a/node_modules/mdl-ext/src/formatfield/formatfield.js b/node_modules/mdl-ext/src/formatfield/formatfield.js
new file mode 100644
index 0000000..0b84819
--- /dev/null
+++ b/node_modules/mdl-ext/src/formatfield/formatfield.js
@@ -0,0 +1,280 @@
+/**
+ * @license
+ * Copyright 2016-2017 Leif Olsen. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This code is built with Google Material Design Lite,
+ * which is Licensed under the Apache License, Version 2.0
+ */
+
+
+import {jsonStringToObject} from '../utils/json-utils';
+import {
+ IS_UPGRADED,
+} from '../utils/constants';
+
+const JS_FORMAT_FIELD = 'mdlext-js-formatfield';
+const FORMAT_FIELD_COMPONENT = 'MaterialExtFormatfield';
+
+/**
+ * Detect browser locale
+ * @returns {string} the locale
+ * @see http://stackoverflow.com/questions/1043339/javascript-for-detecting-browser-language-preference
+ */
+const browserLanguage = () => {
+ return navigator.languages
+ ? navigator.languages[0]
+ : navigator.language || navigator.userLanguage;
+};
+
+/**
+ * The formatfield formats an input field using language sensitive number formatting.
+ */
+
+class FormatField {
+ static timer = null;
+
+ element_;
+ input_;
+ options_ = {};
+ intlGroupSeparator_;
+ intlDecimalSeparator_;
+
+ constructor(element) {
+ this.element_ = element;
+ this.init();
+ }
+
+ clickHandler = () => {
+ clearTimeout(FormatField.timer);
+ };
+
+ focusInHandler = () => {
+ if(!(this.input.readOnly || this.input.disabled)) {
+ this.input.value = this.unformatInput();
+ //setTimeout(() => this.input.setSelectionRange(0, this.input.value.length), 20);
+ FormatField.timer = setTimeout(() => this.input.select(), 200);
+ }
+ };
+
+ focusOutHandler = () => {
+ clearTimeout(FormatField.timer);
+
+ if(!(this.input.readOnly || this.input.disabled)) {
+ this.formatValue();
+ }
+ };
+
+ get element() {
+ return this.element_;
+ }
+
+ get input() {
+ return this.input_;
+ }
+
+ get options() {
+ return this.options_;
+ }
+
+ stripSeparatorsFromValue() {
+ const doReplace = () => this.input.value
+ .replace(/\s/g, '')
+ .replace(new RegExp(this.options.groupSeparator, 'g'), '')
+ .replace(this.options.decimalSeparator, '.');
+ //.replace(this.intlGroupSeparator_, ''),
+ //.replace(this.intlDecimalSeparator_, '.');
+
+ return this.input.value ? doReplace() : this.input.value;
+ }
+
+ fixSeparators(value) {
+ const doReplace = () => value
+ .replace(new RegExp(this.intlGroupSeparator_, 'g'), this.options.groupSeparator)
+ .replace(this.intlDecimalSeparator_, this.options.decimalSeparator);
+
+ return value ? doReplace() : value;
+ }
+
+ formatValue() {
+ if(this.input.value) {
+ const v = new Intl.NumberFormat(this.options.locales, this.options)
+ .format(this.stripSeparatorsFromValue());
+
+ if('NaN' !== v) {
+ this.input.value = this.fixSeparators(v);
+ }
+ }
+ }
+
+ unformat() {
+ const doReplace = () => this.input.value
+ .replace(/\s/g, '')
+ .replace(new RegExp(this.options.groupSeparator, 'g'), '')
+ .replace(this.options.decimalSeparator, '.');
+
+ return this.input.value ? doReplace() : this.input.value;
+ }
+
+ unformatInput() {
+ const doReplace = () => this.input.value
+ .replace(/\s/g, '')
+ .replace(new RegExp(this.options.groupSeparator, 'g'), '');
+
+ return this.input.value ? doReplace() : this.input.value;
+ }
+
+ removeListeners() {
+ this.input.removeEventListener('click', this.clickHandler);
+ this.input.removeEventListener('focusin', this.focusInHandler);
+ this.input.removeEventListener('focusout', this.focusOutHandler);
+ }
+
+ init() {
+ const addListeners = () => {
+ this.input.addEventListener('click', this.clickHandler);
+ this.input.addEventListener('focusin', this.focusInHandler);
+ this.input.addEventListener('focusout', this.focusOutHandler);
+ };
+
+ const addOptions = () => {
+ const opts = this.element.getAttribute('data-formatfield-options') ||
+ this.input.getAttribute('data-formatfield-options');
+ if(opts) {
+ this.options_ = jsonStringToObject(opts, this.options);
+ }
+ };
+
+ const addLocale = () => {
+ if(!this.options.locales) {
+ this.options.locales = browserLanguage() || 'en-US'; //'nb-NO', //'en-US',
+ }
+ };
+
+ const addGrouping = () => {
+ const s = (1234.5).toLocaleString(this.options.locales, {
+ style: 'decimal',
+ useGrouping: true,
+ minimumFractionDigits: 1,
+ maximumFractionDigits: 1
+ });
+
+ this.intlGroupSeparator_ = s.charAt(1);
+ this.intlDecimalSeparator_ = s.charAt(s.length-2);
+ this.options.groupSeparator = this.options.groupSeparator || this.intlGroupSeparator_;
+ this.options.decimalSeparator = this.options.decimalSeparator || this.intlDecimalSeparator_;
+
+ if(this.options.groupSeparator === this.options.decimalSeparator) {
+ const e = `Error! options.groupSeparator, "${this.options.groupSeparator}" ` +
+ 'and options.decimalSeparator, ' +
+ `"${this.options.decimalSeparator}" should not be equal`;
+ throw new Error(e);
+ }
+ };
+
+ this.input_ = this.element.querySelector('input') || this.element;
+
+ addOptions();
+ addLocale();
+ addGrouping();
+ this.formatValue();
+ addListeners();
+ }
+
+ downgrade() {
+ this.removeListeners();
+ }
+
+}
+
+(function() {
+ 'use strict';
+
+ /**
+ * @constructor
+ * @param {HTMLElement} element The element that will be upgraded.
+ */
+ const MaterialExtFormatfield = function MaterialExtFormatfield(element) {
+ this.element_ = element;
+ this.formatField_ = null;
+
+ // Initialize instance.
+ this.init();
+ };
+ window['MaterialExtFormatfield'] = MaterialExtFormatfield;
+
+ /**
+ * Initialize component
+ */
+ MaterialExtFormatfield.prototype.init = function() {
+ if (this.element_) {
+ this.element_.classList.add(IS_UPGRADED);
+ this.formatField_ = new FormatField(this.element_);
+
+ // Listen to 'mdl-componentdowngraded' event
+ this.element_.addEventListener('mdl-componentdowngraded', this.mdlDowngrade_.bind(this));
+ }
+ };
+
+ /**
+ * Get options object
+ *
+ * @public
+ *
+ * @returns {Object} the options object
+ */
+ MaterialExtFormatfield.prototype.getOptions = function() {
+ return this.formatField_.options;
+ };
+ MaterialExtFormatfield.prototype['getOptions'] = MaterialExtFormatfield.prototype.getOptions;
+
+
+ /**
+ * A unformatted value is a string value where the locale specific decimal separator
+ * is replaced with a '.' separator and group separators are stripped.
+ * The returned value is suitable for parsing to a JavaScript numerical value.
+ *
+ * @example
+ * input.value = '1 234,5';
+ * inputElement.MaterialExtFormatfield.getUnformattedValue();
+ * // Returns '1234.5'
+ *
+ * @public
+ *
+ * @returns {String} the unformatted value
+ */
+ MaterialExtFormatfield.prototype.getUnformattedValue = function() {
+ return this.formatField_.unformat();
+ };
+ MaterialExtFormatfield.prototype['getUnformattedValue'] = MaterialExtFormatfield.prototype.getUnformattedValue;
+
+ /*
+ * Downgrade component
+ * E.g remove listeners and clean up resources
+ */
+ MaterialExtFormatfield.prototype.mdlDowngrade_ = function() {
+ this.formatField_.downgrade();
+ };
+
+ // The component registers itself. It can assume componentHandler is available
+ // in the global scope.
+ /* eslint no-undef: 0 */
+ componentHandler.register({
+ constructor: MaterialExtFormatfield,
+ classAsString: FORMAT_FIELD_COMPONENT,
+ cssClass: JS_FORMAT_FIELD,
+ widget: true
+ });
+
+})();
diff --git a/node_modules/mdl-ext/src/formatfield/readme.md b/node_modules/mdl-ext/src/formatfield/readme.md
new file mode 100644
index 0000000..c3737eb
--- /dev/null
+++ b/node_modules/mdl-ext/src/formatfield/readme.md
@@ -0,0 +1,103 @@
+#Formatfield
+![Formatfield](../../etc/formatfield.png)
+
+The formatfield component formats an input field using language sensitive
+**number formatting**. It acts as a "pluggable" component and can be added to a
+`mdl-textfield` component or to a `<input>` element.
+
+## To include a MDLEXT formatfield component:
+ 1. Code a [single-line `mdl-textfield`](https://getmdl.io/components/index.html#textfields-section)
+component.
+```html
+<div class="mdl-textfield mdl-js-textfield">
+ <input class="mdl-textfield__input" type="text"
+ pattern="-?[0-9 ]*([\.,][0-9]+)?" value="1234.5">
+ <label class="mdl-textfield__label">Number...</label>
+ <span class="mdl-textfield__error">Input is not a number!</span>
+</div>
+```
+
+ 2. Add the `mdlext-js-formatfield` class to define the element as a formatfield component.
+```html
+<div class="mdl-textfield mdl-js-textfield mdlext-js-formatfield">
+ <input class="mdl-textfield__input" type="text"
+ pattern="-?[0-9 ]*([\.,][0-9]+)?" value="1234.5">
+ <label class="mdl-textfield__label">Number...</label>
+ <span class="mdl-textfield__error">Input is not a number!</span>
+</div>
+```
+
+ 3. Optionally add a `data-formatfield-options` attribute with the given
+[locale](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation).
+If this step is omitted, the formatfield component uses the browser language as it's locale.
+```html
+<div class="mdl-textfield mdl-js-textfield mdlext-js-formatfield"
+ data-formatfield-options="{'locales': 'nb-NO'}">
+ <input class="mdl-textfield__input" type="text"
+ pattern="-?[0-9 ]*([\.,][0-9]+)?" value="1234.5">
+ <label class="mdl-textfield__label">Number...</label>
+ <span class="mdl-textfield__error">Input is not a number!</span>
+</div>
+```
+
+### Examples
+* The [snippets/formatfield.html](./snippets/formatfield.html) and the
+[tests](../../test/formatfield/formatfield.spec.js) provides more detailed examples.
+* Try out the [live demo](http://leifoolsen.github.io/mdl-ext/demo/formatfield.html)
+
+## Public methods
+
+### getOptions()
+Get component configuration options object.
+```
+var options = inputElement.MaterialExtFormatfield.getOptions();
+console.log('locales', options.locales);
+```
+
+### getUnformattedValue()
+An unformatted value is a string value where the locale specific decimal separator
+is replaced with a '.' separator and group separators are stripped.
+The returned value is suitable for parsing to a JavaScript numerical value.
+
+Example
+```javascript
+input.value = '1 234,5';
+inputElement.MaterialExtFormatfield.getUnformattedValue();
+// Returns '1234.5'
+```
+
+## Configuration options
+The MDLEXT CSS classes apply various predefined visual and behavioral enhancements
+to the formatfield.
+
+### Available classes and their effects.
+
+| MDLEXT class | Effect | Remarks |
+|--------------|--------|---------|
+|`mdlext-js-formatfield`| Assigns basic MDL behavior to formatfield. | Required. |
+
+
+### Options
+The component can be configured using the `data-formatfield-options` attribute.
+The attribute value is a JSON string with properties defined by the
+[Intl.NumberFormat object](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat).
+
+The `data-formatfield-options` attribute must be a valid JSON string.
+You can use single or double quotes for the JSON properties.
+
+Example 1, single quotes in JSON options string:
+```html
+<input class=" mdlext-js-formatfield" type="text"
+ data-formatfield-options="{'locales': 'nb-NO', 'minimumFractionDigits': 0, 'maximumFractionDigits': 0}">
+```
+
+Example 2, double quotes in JSON options string:
+```html
+<input class=" mdlext-js-formatfield" type="text"
+ data-formatfield-options='{"locales": "nb-NO", "minimumFractionDigits": 0, "maximumFractionDigits": 0}'>
+```
+
+## How to use the component programmatically
+The [tests](../../test/formatfield/formatfield.spec.js) and the
+[snippets/formatfield.html](./snippets/formatfield.html)
+provides examples on how to use the component programmatically.
diff --git a/node_modules/mdl-ext/src/formatfield/snippets/formatfield.html b/node_modules/mdl-ext/src/formatfield/snippets/formatfield.html
new file mode 100644
index 0000000..177a367
--- /dev/null
+++ b/node_modules/mdl-ext/src/formatfield/snippets/formatfield.html
@@ -0,0 +1,114 @@
+<p>The formatfield component formats an input field using
+ language sensitive number formatting. It acts as a "pluggable"
+ component. It can be added to a <code>mdl-textfield</code> component or to
+ a <code><input></code> element.
+</p>
+
+<style>
+ .mdl-data-table .mdl-textfield {
+ width: auto;
+ }
+</style>
+<table class="mdl-data-table mdl-js-data-table mdl-shadow--2dp" style="margin-top: 16px;">
+<thead>
+<tr>
+ <th class="mdl-data-table__cell--non-numeric">Language</th>
+ <th class="mdl-data-table__cell--non-numeric">Input</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td class="mdl-data-table__cell--non-numeric" id="browser-lang">Browser language</td>
+ <td class="mdl-data-table__cell--non-numeric">
+ <div class="mdl-textfield mdl-js-textfield mdlext-js-formatfield" id="sample2-component">
+ <input class="mdl-textfield__input" type="text" pattern="-?[0-9, ]*([\.,][0-9]+)?"
+ id="sample2-input" value="1234.5">
+ <label class="mdl-textfield__label" for="sample2-input">Number...</label>
+ <span class="mdl-textfield__error">Input is not a number!</span>
+ </div>
+ <div id="sample2-unformatted"></div>
+ </td>
+</tr>
+<tr>
+ <td class="mdl-data-table__cell--non-numeric">nb-NO</td>
+ <td class="mdl-data-table__cell--non-numeric">
+ <div class="mdl-textfield mdl-js-textfield mdlext-js-formatfield"
+ data-formatfield-options="{'locales': 'nb-NO'}">
+
+ <input class="mdl-textfield__input" type="text" pattern="-?[0-9 ]*([\.,][0-9]+)?" value="1234.5">
+ <label class="mdl-textfield__label">Number...</label>
+ <span class="mdl-textfield__error">Input is not a number!</span>
+ </div>
+ </td>
+</tr>
+<tr>
+ <td class="mdl-data-table__cell--non-numeric">en-GB</td>
+ <td class="mdl-data-table__cell--non-numeric">
+ <div class="mdl-textfield mdl-js-textfield mdlext-js-formatfield" data-formatfield-options="{'locales': 'en-GB'}">
+ <input class="mdl-textfield__input" type="text" pattern="-?[0-9]*(\.[0-9]+)?" value="1234.5">
+ <label class="mdl-textfield__label">Number...</label>
+ <span class="mdl-textfield__error">Input is not a number!</span>
+ </div>
+ </td>
+</tr>
+<tr>
+ <td class="mdl-data-table__cell--non-numeric">nb-NO, integer</td>
+ <td class="mdl-data-table__cell--non-numeric">
+ <div class="mdl-textfield mdl-js-textfield mdlext-js-formatfield">
+ <input class="mdl-textfield__input" type="text" pattern="-?[0-9]*(\.[0-9]+)?"
+ data-formatfield-options="{'locales': 'nb-NO', 'minimumFractionDigits': 0,'maximumFractionDigits': 0}" value="1234.5">
+
+ <label class="mdl-textfield__label">Number...</label>
+ <span class="mdl-textfield__error">Input is not a number!</span>
+ </div>
+ </td>
+</tr>
+<tr>
+ <td class="mdl-data-table__cell--non-numeric">Percent. Input not supported</td>
+ <td class="mdl-data-table__cell--non-numeric">
+ <div class="mdl-textfield mdl-js-textfield mdlext-js-formatfield">
+ <input class="mdl-textfield__input" type="text" readonly
+ data-formatfield-options="{'locales': 'en-GB', 'style': 'percent'}" value="0.20">
+ <label class="mdl-textfield__label">Number...</label>
+ </div>
+ </td>
+</tr>
+<tr>
+ <td class="mdl-data-table__cell--non-numeric">Currency. Input not supported</td>
+ <td class="mdl-data-table__cell--non-numeric">
+ <div class="mdl-textfield mdl-js-textfield mdlext-js-formatfield">
+ <input class="mdl-textfield__input" type="text" readonly
+ data-formatfield-options="{'locales': 'nb-NO', 'style': 'currency', 'currency': 'NOK'}" value="1234.5">
+ <label class="mdl-textfield__label">Number...</label>
+ </div>
+ </td>
+</tr>
+<tr>
+ <td class="mdl-data-table__cell--non-numeric">Input</td>
+ <td class="mdl-data-table__cell--non-numeric">
+ <input class=" mdlext-js-formatfield" type="text"
+ data-formatfield-options="{'locales': 'nb-NO'}" value="1234.5">
+ </td>
+</tr>
+</tbody>
+</table>
+
+<script>
+ (function() {
+ 'use strict';
+ window.addEventListener('load', function() {
+ var lang = navigator.languages
+ ? navigator.languages[0]
+ : navigator.language || navigator.userLanguage;
+
+ document.querySelector('#browser-lang').innerText = 'Browser language (' + lang + ')';
+
+ var formatfieldComponent = document.querySelector('#sample2-component');
+ formatfieldComponent.querySelector('input').addEventListener('blur', function () {
+ var unformatted = document.querySelector('#sample2-unformatted');
+ unformatted.innerText = 'Unformatted: ' + formatfieldComponent.MaterialExtFormatfield.getUnformattedValue();
+ });
+ });
+ }());
+</script>
+