blob: 271da23f585d2e794fb6a3ced455932b338c191d [file] [log] [blame]
Copybara botbe50d492023-11-30 00:16:42 +01001'use strict';
2
3var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
4
5var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
6
7var _createClass2 = require('babel-runtime/helpers/createClass');
8
9var _createClass3 = _interopRequireDefault(_createClass2);
10
11var _jsonUtils = require('../utils/json-utils');
12
13var _constants = require('../utils/constants');
14
15function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
17/**
18 * @license
19 * Copyright 2016-2017 Leif Olsen. All Rights Reserved.
20 *
21 * Licensed under the Apache License, Version 2.0 (the "License");
22 * you may not use this file except in compliance with the License.
23 * You may obtain a copy of the License at
24 *
25 * http://www.apache.org/licenses/LICENSE-2.0
26 *
27 * Unless required by applicable law or agreed to in writing, software
28 * distributed under the License is distributed on an "AS IS" BASIS,
29 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30 * See the License for the specific language governing permissions and
31 * limitations under the License.
32 *
33 * This code is built with Google Material Design Lite,
34 * which is Licensed under the Apache License, Version 2.0
35 */
36
37var JS_FORMAT_FIELD = 'mdlext-js-formatfield';
38var FORMAT_FIELD_COMPONENT = 'MaterialExtFormatfield';
39
40/**
41 * Detect browser locale
42 * @returns {string} the locale
43 * @see http://stackoverflow.com/questions/1043339/javascript-for-detecting-browser-language-preference
44 */
45var browserLanguage = function browserLanguage() {
46 return navigator.languages ? navigator.languages[0] : navigator.language || navigator.userLanguage;
47};
48
49/**
50 * The formatfield formats an input field using language sensitive number formatting.
51 */
52
53var FormatField = function () {
54 function FormatField(element) {
55 var _this = this;
56
57 (0, _classCallCheck3.default)(this, FormatField);
58 this.options_ = {};
59
60 this.clickHandler = function () {
61 clearTimeout(FormatField.timer);
62 };
63
64 this.focusInHandler = function () {
65 if (!(_this.input.readOnly || _this.input.disabled)) {
66 _this.input.value = _this.unformatInput();
67 //setTimeout(() => this.input.setSelectionRange(0, this.input.value.length), 20);
68 FormatField.timer = setTimeout(function () {
69 return _this.input.select();
70 }, 200);
71 }
72 };
73
74 this.focusOutHandler = function () {
75 clearTimeout(FormatField.timer);
76
77 if (!(_this.input.readOnly || _this.input.disabled)) {
78 _this.formatValue();
79 }
80 };
81
82 this.element_ = element;
83 this.init();
84 }
85
86 (0, _createClass3.default)(FormatField, [{
87 key: 'stripSeparatorsFromValue',
88 value: function stripSeparatorsFromValue() {
89 var _this2 = this;
90
91 var doReplace = function doReplace() {
92 return _this2.input.value.replace(/\s/g, '').replace(new RegExp(_this2.options.groupSeparator, 'g'), '').replace(_this2.options.decimalSeparator, '.');
93 };
94 //.replace(this.intlGroupSeparator_, ''),
95 //.replace(this.intlDecimalSeparator_, '.');
96
97 return this.input.value ? doReplace() : this.input.value;
98 }
99 }, {
100 key: 'fixSeparators',
101 value: function fixSeparators(value) {
102 var _this3 = this;
103
104 var doReplace = function doReplace() {
105 return value.replace(new RegExp(_this3.intlGroupSeparator_, 'g'), _this3.options.groupSeparator).replace(_this3.intlDecimalSeparator_, _this3.options.decimalSeparator);
106 };
107
108 return value ? doReplace() : value;
109 }
110 }, {
111 key: 'formatValue',
112 value: function formatValue() {
113 if (this.input.value) {
114 var v = new Intl.NumberFormat(this.options.locales, this.options).format(this.stripSeparatorsFromValue());
115
116 if ('NaN' !== v) {
117 this.input.value = this.fixSeparators(v);
118 }
119 }
120 }
121 }, {
122 key: 'unformat',
123 value: function unformat() {
124 var _this4 = this;
125
126 var doReplace = function doReplace() {
127 return _this4.input.value.replace(/\s/g, '').replace(new RegExp(_this4.options.groupSeparator, 'g'), '').replace(_this4.options.decimalSeparator, '.');
128 };
129
130 return this.input.value ? doReplace() : this.input.value;
131 }
132 }, {
133 key: 'unformatInput',
134 value: function unformatInput() {
135 var _this5 = this;
136
137 var doReplace = function doReplace() {
138 return _this5.input.value.replace(/\s/g, '').replace(new RegExp(_this5.options.groupSeparator, 'g'), '');
139 };
140
141 return this.input.value ? doReplace() : this.input.value;
142 }
143 }, {
144 key: 'removeListeners',
145 value: function removeListeners() {
146 this.input.removeEventListener('click', this.clickHandler);
147 this.input.removeEventListener('focusin', this.focusInHandler);
148 this.input.removeEventListener('focusout', this.focusOutHandler);
149 }
150 }, {
151 key: 'init',
152 value: function init() {
153 var _this6 = this;
154
155 var addListeners = function addListeners() {
156 _this6.input.addEventListener('click', _this6.clickHandler);
157 _this6.input.addEventListener('focusin', _this6.focusInHandler);
158 _this6.input.addEventListener('focusout', _this6.focusOutHandler);
159 };
160
161 var addOptions = function addOptions() {
162 var opts = _this6.element.getAttribute('data-formatfield-options') || _this6.input.getAttribute('data-formatfield-options');
163 if (opts) {
164 _this6.options_ = (0, _jsonUtils.jsonStringToObject)(opts, _this6.options);
165 }
166 };
167
168 var addLocale = function addLocale() {
169 if (!_this6.options.locales) {
170 _this6.options.locales = browserLanguage() || 'en-US'; //'nb-NO', //'en-US',
171 }
172 };
173
174 var addGrouping = function addGrouping() {
175 var s = 1234.5.toLocaleString(_this6.options.locales, {
176 style: 'decimal',
177 useGrouping: true,
178 minimumFractionDigits: 1,
179 maximumFractionDigits: 1
180 });
181
182 _this6.intlGroupSeparator_ = s.charAt(1);
183 _this6.intlDecimalSeparator_ = s.charAt(s.length - 2);
184 _this6.options.groupSeparator = _this6.options.groupSeparator || _this6.intlGroupSeparator_;
185 _this6.options.decimalSeparator = _this6.options.decimalSeparator || _this6.intlDecimalSeparator_;
186
187 if (_this6.options.groupSeparator === _this6.options.decimalSeparator) {
188 var e = 'Error! options.groupSeparator, "' + _this6.options.groupSeparator + '" ' + 'and options.decimalSeparator, ' + ('"' + _this6.options.decimalSeparator + '" should not be equal');
189 throw new Error(e);
190 }
191 };
192
193 this.input_ = this.element.querySelector('input') || this.element;
194
195 addOptions();
196 addLocale();
197 addGrouping();
198 this.formatValue();
199 addListeners();
200 }
201 }, {
202 key: 'downgrade',
203 value: function downgrade() {
204 this.removeListeners();
205 }
206 }, {
207 key: 'element',
208 get: function get() {
209 return this.element_;
210 }
211 }, {
212 key: 'input',
213 get: function get() {
214 return this.input_;
215 }
216 }, {
217 key: 'options',
218 get: function get() {
219 return this.options_;
220 }
221 }]);
222 return FormatField;
223}();
224
225FormatField.timer = null;
226
227
228(function () {
229 'use strict';
230
231 /**
232 * @constructor
233 * @param {HTMLElement} element The element that will be upgraded.
234 */
235
236 var MaterialExtFormatfield = function MaterialExtFormatfield(element) {
237 this.element_ = element;
238 this.formatField_ = null;
239
240 // Initialize instance.
241 this.init();
242 };
243 window['MaterialExtFormatfield'] = MaterialExtFormatfield;
244
245 /**
246 * Initialize component
247 */
248 MaterialExtFormatfield.prototype.init = function () {
249 if (this.element_) {
250 this.element_.classList.add(_constants.IS_UPGRADED);
251 this.formatField_ = new FormatField(this.element_);
252
253 // Listen to 'mdl-componentdowngraded' event
254 this.element_.addEventListener('mdl-componentdowngraded', this.mdlDowngrade_.bind(this));
255 }
256 };
257
258 /**
259 * Get options object
260 *
261 * @public
262 *
263 * @returns {Object} the options object
264 */
265 MaterialExtFormatfield.prototype.getOptions = function () {
266 return this.formatField_.options;
267 };
268 MaterialExtFormatfield.prototype['getOptions'] = MaterialExtFormatfield.prototype.getOptions;
269
270 /**
271 * A unformatted value is a string value where the locale specific decimal separator
272 * is replaced with a '.' separator and group separators are stripped.
273 * The returned value is suitable for parsing to a JavaScript numerical value.
274 *
275 * @example
276 * input.value = '1 234,5';
277 * inputElement.MaterialExtFormatfield.getUnformattedValue();
278 * // Returns '1234.5'
279 *
280 * @public
281 *
282 * @returns {String} the unformatted value
283 */
284 MaterialExtFormatfield.prototype.getUnformattedValue = function () {
285 return this.formatField_.unformat();
286 };
287 MaterialExtFormatfield.prototype['getUnformattedValue'] = MaterialExtFormatfield.prototype.getUnformattedValue;
288
289 /*
290 * Downgrade component
291 * E.g remove listeners and clean up resources
292 */
293 MaterialExtFormatfield.prototype.mdlDowngrade_ = function () {
294 this.formatField_.downgrade();
295 };
296
297 // The component registers itself. It can assume componentHandler is available
298 // in the global scope.
299 /* eslint no-undef: 0 */
300 componentHandler.register({
301 constructor: MaterialExtFormatfield,
302 classAsString: FORMAT_FIELD_COMPONENT,
303 cssClass: JS_FORMAT_FIELD,
304 widget: true
305 });
306})();