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
+  });
+
+})();