| <!DOCTYPE html> |
| <script src="../../../resources/js-test.js"></script> |
| <script> |
| |
| if (window.internals) |
| internals.settings.setLangAttributeAwareFormControlUIEnabled(true); |
| else |
| debug('Require testRunner.'); |
| </script> |
| |
| <input id="input-ar" lang="ar-eg" type="number"> |
| <input id="input-fr" lang="fr-fr" type="number"> |
| <input id="input-en" lang="en-us" type="number"> |
| |
| <script> |
| function displayValueForKeyInput(inputElement, keyInputs, optionalOldString, expectedValue) { |
| inputElement.value = ''; |
| inputElement.focus(); |
| if (optionalOldString) { |
| let caretPosition = optionalOldString.indexOf('|'); |
| if (caretPosition < 0) |
| caretPosition = optionalOldString.length; |
| else |
| optionalOldString = optionalOldString.replace("|", ""); |
| document.execCommand('InsertText', false, optionalOldString); |
| |
| // Check that the value is what we expect |
| inputElement.select(); |
| shouldBeEqualToString("window.getSelection().toString()", optionalOldString); |
| |
| // Update selection |
| internals.setSelectionRangeForNumberType(inputElement, caretPosition, caretPosition); |
| } |
| document.execCommand('InsertText', false, keyInputs); |
| inputElement.select(); |
| |
| // Check expected value |
| if (expectedValue === undefined) |
| shouldBeUndefined(inputElement.value); |
| else |
| shouldBeEqualToNumber(inputElement.value, expectedValue); |
| |
| return window.getSelection().toString(); |
| } |
| |
| // Get language formats |
| var langs = ["ar-eg", "fr-fr", "en-us"]; |
| var langSpecs = {}; |
| var numberCharMapByLang = {}; |
| // Check local formatting options |
| for (var lang of langs) |
| { |
| var formatted = Number(123456.7).toLocaleString(lang); |
| var oneFormatted = Number(1).toLocaleString(lang); |
| var negativeFormatted = Number(-1).toLocaleString(lang); |
| var oneIndex = negativeFormatted.indexOf(oneFormatted); |
| var negativePrefix = ""; |
| if (oneIndex > 0) |
| negativePrefix = negativeFormatted.substr(0, oneIndex); |
| var negativeSuffix = ""; |
| if (negativeSuffix === oneFormatted) |
| negativeSuffix = negativeFormatted.substr(oneIndex + 1); |
| var specs = { |
| "usesCommas": /123,456/.test(formatted), |
| "usesArabicDecimalSeparator": formatted.indexOf("\u066b") !== -1, |
| "latinDigits": formatted.indexOf("1") !== -1, |
| "negativePrefix": negativePrefix, |
| "negativePrefixLength": negativePrefix.length, |
| "negativeSuffix": negativeSuffix, |
| "negativeSuffixLength": negativeSuffix.length, |
| "usesE": /[eE]/.test(Number(1e2).toLocaleString(lang, {"notation": "scientific"})) |
| }; |
| specs.usesSingleCharFiltering = (specs.negativePrefixLength == 1 && specs.negativeSuffixLength == 0); |
| langSpecs[lang] = specs; |
| |
| // Get replacement digits |
| numberCharMapByLang[lang] = {}; |
| var formattedDigits = Number(1234567890.1).toLocaleString(lang, { |
| useGrouping: false |
| }); |
| for (var i = 1; i <= 10; i++) |
| { |
| var num = i % 10; |
| var index = i - 1; |
| numberCharMapByLang[lang][num] = formattedDigits[index]; |
| } |
| numberCharMapByLang[lang]["."] = formattedDigits[10]; |
| var groupingSeparator = formatted[3]; |
| if (formattedDigits.indexOf(groupingSeparator) !== -1) |
| formattedDigits = ""; |
| numberCharMapByLang[lang][","] = groupingSeparator; |
| } |
| |
| function convertLocal(enValue, lang) { |
| var value = ""; |
| var map = numberCharMapByLang[lang] || {}; |
| for (var i = 0; i < enValue.length; i++) |
| { |
| var c = enValue[i]; |
| value += (c in map) ? map[c] : c; |
| } |
| |
| // Update sign if needed |
| var specs = langSpecs[lang]; |
| if (enValue[0] === "-" && specs.negativePrefix !== "-") |
| value = specs.negativePrefix + value.substr(1); |
| if (enValue.substr(0, 2) === "|-" && specs.negativePrefix !== "-") |
| value = "|" + specs.negativePrefix + value.substr(2); |
| |
| return value; |
| } |
| |
| debug('Arabic number input should accept ASCII digits and Arabic digits, and reject others.'); |
| var input_ar = document.getElementById('input-ar'); |
| shouldBeEqualToString('displayValueForKeyInput(input_ar, "123.4", "", 123.4)', '123.4'); |
| shouldBeEqualToString('displayValueForKeyInput(input_ar, "1.23E+19", "", 12300000000000000000)', '1.23E+19'); |
| shouldBeEqualToString('displayValueForKeyInput(input_ar, "1.23e-1", "", 0.123)', '1.23e-1'); |
| shouldBeEqualToString('displayValueForKeyInput(input_ar, "\u0661\u0669\u0660", "", 190)', '\u0661\u0669\u0660'); |
| shouldBeEqualToString('displayValueForKeyInput(input_ar, "acdef", "", undefined)', 'e'); |
| |
| debug(''); |
| debug('French number input should accept ASCII digits, comma, and full stop.'); |
| var input_fr = document.getElementById('input-fr'); |
| shouldBeEqualToString('displayValueForKeyInput(input_fr, "1234.56", "", 1234.56)', '1234.56'); |
| shouldBeEqualToString('displayValueForKeyInput(input_fr, "1234,56", "", 1234.56)', '1234,56'); |
| |
| debug(''); |
| debug('English number input should accept ASCII digits and full stop, and no comma.'); |
| var input_en = document.getElementById('input-en'); |
| shouldBeEqualToString('displayValueForKeyInput(input_en, "1234.56", "", 1234.56)', '1234.56'); |
| shouldBeEqualToString('displayValueForKeyInput(input_en, "-1234,56", "", -123456)', '-123456'); |
| shouldBeEqualToString('displayValueForKeyInput(input_en, " 1234.56 ", "", 1234.56)', '1234.56'); |
| shouldBeEqualToString('displayValueForKeyInput(input_en, "e", "-1|-1", -0.1)', '-1e-1'); |
| |
| debug(''); |
| debug('Test all locales.'); |
| var tests = [ |
| ["123,456,789E+10", "", 1234567890000000000, '123456789E+10'], |
| [".", "1|e2", 100, '1.e2'], |
| [".", "1e2|", 100, '1e2'], |
| [".", "|-12", -12, '-12'], |
| [".", "|1e-12", 0.0000000000001, '.1e-12'], |
| ["e", "34|12", 34000000000000, '34e12'], |
| ["e", "12|3e4", 1230000, '123e4'], |
| ["e", "123|.4", 123.4, '123.4'], |
| ["e", "12.3|4", 123000, '12.3e4'], |
| ["+", "12|34", undefined, '12+34'], |
| ["+", "-3|4e-12", -0.000000000034, '-34e-12'], |
| ["+", "|1234", 1234, '+1234'], |
| ["-", "123e|4", 0.0123, '123e-4'], |
| ["-", "1|23e4", 1230000, '123e4'], |
| ["-", "123e4|", 1230000, '123e4'], |
| ["9", "|-1", -1, '-1'], |
| ["9", "-|1", -91, '-91'], |
| ["9", "1e|+2", 100, '1e+2'], |
| ["1", "1e+|2", 1000000000000, '1e+12'], |
| // Invalid |
| [" abcdef ", "", undefined, 'e'], |
| ["+1-2", "", undefined, '+1-2'], |
| ["+1-2+2-3", "", undefined, '+1-223'], |
| ["0-123-123+123", "", undefined, '0-123-123123'], |
| ["10e123123e1231233e", "", undefined, '10e1231231231233'], |
| ["1e2eee", "", 100, '1e2'], |
| ["1e1e1e", "", 100000000000, '1e11'], |
| ]; |
| for (var test of tests) |
| { |
| for (var lang of langs) |
| { |
| var specs = langSpecs[lang]; |
| var keyInputs = test[0]; |
| var oldString = test[1]; |
| var expectedNumericValue = test[2]; |
| var expectedStringValue = test[3]; |
| |
| // Build raw new text. |
| var rawNewText = keyInputs; |
| if (oldString !== "") |
| { |
| var pos = oldString.indexOf("|"); |
| rawNewText = oldString.substr(0, pos) + keyInputs + oldString.substr(pos + 1); |
| } |
| |
| // Skip test if there's a comma, but locale doesn't use commas. |
| // Otherwise, it will be converted to a decimal separator, breaking the expected value. |
| if (rawNewText.indexOf(",") !== -1 && !specs.usesCommas) |
| continue; |
| |
| // Skip test if scientific notation doesn't use "e". |
| if (rawNewText.toLowerCase().indexOf("e") !== -1 && !specs.usesE) |
| continue; |
| |
| // Not uses_single_char_number_filtering_, so build actual value. |
| if (!specs.usesSingleCharFiltering) |
| { |
| // Remove commas. |
| expectedStringValue = rawNewText.replace(/,/g, ""); |
| |
| // Figure out how this number will parse. |
| var cleanExpectedStringValue = expectedStringValue.replace(/[^0-9.e+-]/gi, ""); |
| var scientificMatch = /e([+-]?[0-9]+)$/i.exec(cleanExpectedStringValue); |
| var multiplier = 1; |
| if (scientificMatch !== null) |
| { |
| cleanExpectedStringValue = cleanExpectedStringValue.replace(/e([+-]?[0-9]+)$/gi, ""); |
| multiplier = Math.pow(10, parseInt(scientificMatch[1], 10)); |
| } |
| expectedNumericValue = Number(cleanExpectedStringValue); |
| if (isNaN(expectedNumericValue)) |
| expectedNumericValue = undefined; |
| else |
| expectedNumericValue *= multiplier; |
| } |
| |
| // Skip if a negative number and negative prefix is more than 1 character. |
| // For ar-eg, Windows seems to strip \u061c when setting the initial text |
| // causing results to differ. |
| if (/^\|?-/.test(oldString) && specs.negativePrefixLength > 1) |
| continue; |
| |
| // Change to locale if not in scientific notation (and valid). |
| if (/^[+-]?([0-9]+(\.[0-9]*)|\.[0-9]+)?e[+-]?[0-9]+$/i.exec(expectedStringValue) === null) |
| { |
| keyInputs = convertLocal(keyInputs, lang); |
| oldString = convertLocal(oldString, lang); |
| expectedStringValue = convertLocal(expectedStringValue, lang); |
| } |
| |
| // Skip if it includes the Arabic decimal separator. Windows differs from Mac/Linux. |
| if (expectedStringValue.indexOf("\u066b") !== -1) |
| continue; |
| |
| shouldBeEqualToString('displayValueForKeyInput(input_' + lang.replace(/-.*$/, '') + ', "' + keyInputs + '", "' + oldString + '", ' + expectedNumericValue + ')', expectedStringValue); |
| } |
| } |
| </script> |
| </body> |