summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/unitconverters/UnitConverterTemperature.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/urlbar/unitconverters/UnitConverterTemperature.sys.mjs')
-rw-r--r--browser/components/urlbar/unitconverters/UnitConverterTemperature.sys.mjs124
1 files changed, 124 insertions, 0 deletions
diff --git a/browser/components/urlbar/unitconverters/UnitConverterTemperature.sys.mjs b/browser/components/urlbar/unitconverters/UnitConverterTemperature.sys.mjs
new file mode 100644
index 0000000000..5a78d20577
--- /dev/null
+++ b/browser/components/urlbar/unitconverters/UnitConverterTemperature.sys.mjs
@@ -0,0 +1,124 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const ABSOLUTE = ["celsius", "kelvin", "fahrenheit"];
+const ALIAS = ["c", "k", "f"];
+const UNITS = [...ABSOLUTE, ...ALIAS];
+
+const NUMBER_REGEX = "-?\\d+(?:\\.\\d+)?\\s*";
+const UNIT_REGEX = "\\w+";
+
+// NOTE: This regex need to be localized upon supporting multi locales
+// since it supports en-US input format only.
+const QUERY_REGEX = new RegExp(
+ `^(${NUMBER_REGEX})(${UNIT_REGEX})(?:\\s+in\\s+|\\s+to\\s+|\\s*=\\s*)(${UNIT_REGEX})`,
+ "i"
+);
+
+const DECIMAL_PRECISION = 10;
+
+/**
+ * This module converts temperature unit.
+ */
+export class UnitConverterTemperature {
+ /**
+ * Convert the given search string.
+ *
+ * @param {string} searchString
+ * The string to be converted
+ * @returns {string} conversion result.
+ */
+ convert(searchString) {
+ const regexResult = QUERY_REGEX.exec(searchString);
+ if (!regexResult) {
+ return null;
+ }
+
+ const target = findUnits(regexResult[2], regexResult[3]);
+
+ if (!target) {
+ return null;
+ }
+
+ const { inputUnit, outputUnit } = target;
+ const inputNumber = Number(regexResult[1]);
+ const inputChar = inputUnit.charAt(0);
+ const outputChar = outputUnit.charAt(0);
+
+ let outputNumber;
+ if (inputChar === outputChar) {
+ outputNumber = inputNumber;
+ } else {
+ outputNumber = this[`${inputChar}2${outputChar}`](inputNumber);
+ }
+
+ outputNumber = parseFloat(outputNumber.toPrecision(DECIMAL_PRECISION));
+
+ try {
+ return new Intl.NumberFormat("en-US", {
+ style: "unit",
+ unit: outputUnit,
+ maximumFractionDigits: DECIMAL_PRECISION,
+ }).format(outputNumber);
+ } catch (e) {}
+
+ return `${outputNumber} ${outputUnit}`;
+ }
+
+ c2k(t) {
+ return t + 273.15;
+ }
+
+ c2f(t) {
+ return t * 1.8 + 32;
+ }
+
+ k2c(t) {
+ return t - 273.15;
+ }
+
+ k2f(t) {
+ return this.c2f(this.k2c(t));
+ }
+
+ f2c(t) {
+ return (t - 32) / 1.8;
+ }
+
+ f2k(t) {
+ return this.c2k(this.f2c(t));
+ }
+}
+
+/**
+ * Returns the suitable units for the given two values.
+ * If could not found suitable unit, returns null.
+ *
+ * @param {string} inputUnit
+ * A set of units to convert, mapped to the `inputUnit` value on the return
+ * @param {string} outputUnit
+ * A set of units to convert, mapped to the `outputUnit` value on the return
+ * @returns {{ inputUnit: string, outputUnit: string }} The suitable units.
+ */
+function findUnits(inputUnit, outputUnit) {
+ inputUnit = inputUnit.toLowerCase();
+ outputUnit = outputUnit.toLowerCase();
+
+ if (!UNITS.includes(inputUnit) || !UNITS.includes(outputUnit)) {
+ return null;
+ }
+
+ return {
+ inputUnit: toAbsoluteUnit(inputUnit),
+ outputUnit: toAbsoluteUnit(outputUnit),
+ };
+}
+
+function toAbsoluteUnit(unit) {
+ if (unit.length !== 1) {
+ return unit;
+ }
+
+ return ABSOLUTE.find(a => a.startsWith(unit));
+}