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