mirror of
https://github.com/transatoshi-mw/grin-web-wallet.git
synced 2025-10-06 15:52:47 +00:00
1952 lines
44 KiB
JavaScript
Executable File
1952 lines
44 KiB
JavaScript
Executable File
// Use strict
|
|
"use strict";
|
|
|
|
|
|
// Classes
|
|
|
|
// Common class
|
|
class Common {
|
|
|
|
// Public
|
|
|
|
// From hex string
|
|
static fromHexString(hexString, useSharedArrayBuffer = false) {
|
|
|
|
// Initialize result
|
|
var result = new Uint8Array((useSharedArrayBuffer === true && crossOriginIsolated === true) ? new SharedArrayBuffer(Common.hexStringLength(hexString)) : Common.hexStringLength(hexString));
|
|
|
|
// Go through all bytes in the result
|
|
for(var i = 0; i < result["length"]; ++i) {
|
|
|
|
// Set character as a byte in the result
|
|
result[i] = (Common.HEX_CHARACTER_TO_VALUE[hexString[i * Common.HEX_NUMBER_LENGTH]] << (Common.BITS_IN_A_BYTE / 2)) | Common.HEX_CHARACTER_TO_VALUE[hexString[i * Common.HEX_NUMBER_LENGTH + 1]];
|
|
}
|
|
|
|
// Return result
|
|
return result;
|
|
}
|
|
|
|
// To hex string
|
|
static toHexString(byteArray) {
|
|
|
|
// Initialize result
|
|
var result = "";
|
|
|
|
// Go through all bytes in the byte array
|
|
for(var i = 0; i < byteArray["length"]; ++i) {
|
|
|
|
// Get byte
|
|
var byte = byteArray[i];
|
|
|
|
// Append byte as characters to the result
|
|
result = result.concat(Common.VALUE_TO_HEX_CHARACTER[byte >>> (Common.BITS_IN_A_BYTE / 2)], Common.VALUE_TO_HEX_CHARACTER[byte & 0x0F]);
|
|
}
|
|
|
|
// Return result
|
|
return result;
|
|
}
|
|
|
|
// Is hex string
|
|
static isHexString(string) {
|
|
|
|
// Check if string isn't a string
|
|
if(typeof string !== "string")
|
|
|
|
// Return false
|
|
return false;
|
|
|
|
// Check if string's length is invalid
|
|
if(string["length"] % Common.HEX_NUMBER_LENGTH !== 0) {
|
|
|
|
// Return false
|
|
return false;
|
|
}
|
|
|
|
// Return if string is a hex string
|
|
return Common.HEX_STRING_PATTERN.test(string) === true;
|
|
}
|
|
|
|
// Hex string length
|
|
static hexStringLength(string) {
|
|
|
|
// Return hex string length
|
|
return string["length"] / Common.HEX_NUMBER_LENGTH;
|
|
}
|
|
|
|
// Is number string
|
|
static isNumberString(string) {
|
|
|
|
// Check if string isn't a string
|
|
if(typeof string !== "string")
|
|
|
|
// Return false
|
|
return false;
|
|
|
|
// Return if string is a number string
|
|
return Common.NUMBER_STRING_PATTERN.test(string) === true;
|
|
}
|
|
|
|
// Is RFC 3339 string
|
|
static isRfc3339String(string) {
|
|
|
|
// Check if string isn't a string
|
|
if(typeof string !== "string")
|
|
|
|
// Return false
|
|
return false;
|
|
|
|
// Check if string isn't an RFC 3339 string
|
|
if(Common.RFC_3339_STRING_PATTERN.test(string) === false)
|
|
|
|
// Return false
|
|
return false;
|
|
|
|
// Return if string could be converted from a RFC 3339 string to a timestamp
|
|
return Number.isNaN(Common.rfc3339StringToTimestamp(string)) === false;
|
|
}
|
|
|
|
// Is lowercase string
|
|
static isLowercaseString(string) {
|
|
|
|
// Check if string isn't a string
|
|
if(typeof string !== "string")
|
|
|
|
// Return false
|
|
return false;
|
|
|
|
// Return if string is a a lowercase string
|
|
return Common.LOWERCASE_STRING_PATTERN.test(string) === true;
|
|
}
|
|
|
|
// RFC 3339 string to timestamp
|
|
static rfc3339StringToTimestamp(string) {
|
|
|
|
// Return timestamp from string
|
|
return Date.parse(string);
|
|
}
|
|
|
|
// Merge arrays
|
|
static mergeArrays(arrays) {
|
|
|
|
// Initialize result
|
|
var result = new Uint8Array([]);
|
|
|
|
// Go through all arrays
|
|
for(var i = 0; i < arrays["length"]; ++i) {
|
|
|
|
// Get array
|
|
var array = arrays[i];
|
|
|
|
// Set updated result to be the length of the current result and the array
|
|
var updatedResult = new Uint8Array(result["length"] + array["length"]);
|
|
|
|
// Set arrays in the updated result
|
|
updatedResult.set(result);
|
|
updatedResult.set(array, result["length"]);
|
|
|
|
// Set result to the updated result
|
|
result = updatedResult;
|
|
}
|
|
|
|
// Return result
|
|
return result;
|
|
}
|
|
|
|
// Arrays are equal
|
|
static arraysAreEqual(arrayOne, arrayTwo) {
|
|
|
|
// Check if arrays have different lengths
|
|
if(arrayOne["length"] !== arrayTwo["length"])
|
|
|
|
// Return false
|
|
return false;
|
|
|
|
// Go through all values each array
|
|
for(var i = 0; i < arrayOne["length"]; ++i)
|
|
|
|
// Check if array values differ
|
|
if(arrayOne[i] !== arrayTwo[i])
|
|
|
|
// Return false
|
|
return false;
|
|
|
|
// Return true
|
|
return true;
|
|
}
|
|
|
|
// Arrays are equal timing safe
|
|
static arraysAreEqualTimingSafe(arrayOne, arrayTwo) {
|
|
|
|
// Initialize results
|
|
var result = (arrayOne["length"] === arrayTwo["length"]) ? 0 : 1;
|
|
|
|
// Go through all values in the first array
|
|
for(var i = 0; i < arrayOne["length"]; ++i) {
|
|
|
|
// Get current value from each array
|
|
var arrayOneValue = arrayOne[i];
|
|
var arrayTwoValue = (i < arrayTwo["length"]) ? arrayTwo[i] : 0;
|
|
|
|
// Update result to if current values are equal
|
|
result |= (arrayOneValue === arrayTwoValue) ? 0 : 1;
|
|
}
|
|
|
|
// Return if arrays are equal
|
|
return result === 0;
|
|
}
|
|
|
|
// Get current timestamp
|
|
static getCurrentTimestamp() {
|
|
|
|
// Return current timestamp
|
|
return Math.floor(Date.now() / Common.MILLISECONDS_IN_A_SECOND);
|
|
}
|
|
|
|
// Is extension
|
|
static isExtension() {
|
|
|
|
// Return if extension
|
|
return typeof location !== "undefined" && location["protocol"]["length"] > "-extension:"["length"] && location["protocol"].substring(location["protocol"]["length"] - "-extension:"["length"]) === "-extension:";
|
|
}
|
|
|
|
// Is popup
|
|
static isPopup() {
|
|
|
|
// Get URL parameters
|
|
var urlParameters = Common.getUrlParameters();
|
|
|
|
// Return if popup
|
|
return Common.isExtension() === true && "Is Popup" in urlParameters === true && urlParameters["Is Popup"] === "True";
|
|
}
|
|
|
|
// Is app
|
|
static isApp() {
|
|
|
|
// Return if app
|
|
return Common.isExtension() === false && ((typeof navigator === "object" && navigator !== null && "standalone" in navigator === true && navigator["standalone"] === true) || (typeof matchMedia === "function" && matchMedia("(display-mode: standalone)")["matches"] === true));
|
|
}
|
|
|
|
// HTML encode
|
|
static htmlEncode(string) {
|
|
|
|
// Return string with HTML entities encoded
|
|
return $("<div>").text(string).html().replace(Common.DOUBLE_QUOTE_PATTERN, Common.DOUBLE_QUOTE_HTML_ENTITY).replace(Common.SINGLE_QUOTE_PATTERN, Common.SINGLE_QUOTE_HTML_ENTITY).replace(Common.GRAVE_ACCENT_PATTERN, Common.GRAVE_ACCENT_HTML_ENTITY);
|
|
}
|
|
|
|
// HTML decode
|
|
static htmlDecode(htmlString) {
|
|
|
|
// Return html string with HTML entities decoded
|
|
return $("<div>").html(htmlString).text();
|
|
}
|
|
|
|
// Random number
|
|
static randomNumber(minValue, maxValue) {
|
|
|
|
// Return random number between values inclusively
|
|
return Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
|
|
}
|
|
|
|
// Escape regular expression
|
|
static escapeRegularExpression(string) {
|
|
|
|
// Return string with regular expression meta characters escaped
|
|
return string.replace(/[.*+?^${}()|[\]\\]/ug, "\\$&");
|
|
}
|
|
|
|
// Map
|
|
static map(value, inMin, inMax, outMin, outMax) {
|
|
|
|
// Return value mapped to different range
|
|
return (new BigNumber(outMax)).minus(outMin).multipliedBy((new BigNumber(value)).minus(inMin)).dividedBy((new BigNumber(inMax)).minus(inMin)).plus(outMin);
|
|
}
|
|
|
|
// Is valid URL
|
|
static isValidUrl(url) {
|
|
|
|
// Check if URL doesn't have a protocol
|
|
if(Common.urlContainsProtocol(url) === false) {
|
|
|
|
// Add protocol to URL
|
|
url = Common.HTTP_PROTOCOL + "//" + url;
|
|
}
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Parse URL as a URL
|
|
new URL(url);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Return false
|
|
return false;
|
|
}
|
|
|
|
// Return true
|
|
return true;
|
|
}
|
|
|
|
// Is iframe
|
|
static isIframe() {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Return if self isn't the top window
|
|
return window["self"] !== window["top"];
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Return true
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// On reduced data connection
|
|
static onReducedDataConnection() {
|
|
|
|
// Return if save data is enabled
|
|
return typeof navigator === "object" && navigator !== null && "connection" in navigator === true && typeof navigator["connection"] === "object" && navigator["connection"] !== null && "saveData" in navigator["connection"] === true && navigator["connection"]["saveData"] === true;
|
|
}
|
|
|
|
// Is low memory device
|
|
static isLowMemoryDevice() {
|
|
|
|
// Return if device has low memory
|
|
return typeof navigator === "object" && navigator !== null && "deviceMemory" in navigator === true && navigator["deviceMemory"] <= Common.LOW_MEMORY_THRESHOLD_GIGABYTES;
|
|
}
|
|
|
|
// Is high memory device
|
|
static isHighMemoryDevice() {
|
|
|
|
// Return if device has high memory
|
|
return typeof navigator === "object" && navigator !== null && "deviceMemory" in navigator === true && navigator["deviceMemory"] >= Common.HIGH_MEMORY_THRESHOLD_GIGABYTES;
|
|
}
|
|
|
|
// Is mobile device
|
|
static isMobileDevice() {
|
|
|
|
// Return if device is a mobile device
|
|
return typeof navigator === "object" && navigator !== null && "userAgentData" in navigator === true && "mobile" in navigator["userAgentData"] === true && navigator["userAgentData"]["mobile"] === true;
|
|
}
|
|
|
|
|
|
// Is using cellular network
|
|
static isUsingCellularNetwork() {
|
|
|
|
// Return if using cellular network
|
|
return typeof navigator === "object" && navigator !== null && "connection" in navigator === true && "type" in navigator["connection"] === true && navigator["connection"]["type"] === "cellular";
|
|
}
|
|
|
|
// Upgrade applicable insecure URL
|
|
static upgradeApplicableInsecureUrl(url) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Parse HTTPS server address as a URL
|
|
var parsedHttpsServerUrl = new URL(HTTPS_SERVER_ADDRESS);
|
|
|
|
// Parse Tor server address as a URL
|
|
var parsedTorServerUrl = new URL(TOR_SERVER_ADDRESS);
|
|
|
|
// Parse URL as a URL
|
|
var parsedUrl = new URL(url);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Return url
|
|
return url;
|
|
}
|
|
|
|
// Check if URL's protocol is HTTP, the HTTPS server address's protocol is HTTPS, and the URL is the same site as the HTTPS server address
|
|
if(parsedUrl["protocol"] === Common.HTTP_PROTOCOL && parsedHttpsServerUrl["protocol"] === Common.HTTPS_PROTOCOL && parsedUrl["hostname"] === parsedHttpsServerUrl["hostname"]) {
|
|
|
|
// Create an HTTPS URL from the URL
|
|
var httpsUrl = Common.HTTPS_PROTOCOL + Common.ltrim(url).substring(Common.HTTP_PROTOCOL["length"]);
|
|
|
|
// Return HTTPS URL
|
|
return httpsUrl;
|
|
}
|
|
|
|
// Otherwise check if URL's protocol is WebSocket, the HTTPS server address's protocol is HTTPS, and the URL is the same site as the HTTPS server address
|
|
else if(parsedUrl["protocol"] === Common.WEBSOCKET_PROTOCOL && parsedHttpsServerUrl["protocol"] === Common.HTTPS_PROTOCOL && parsedUrl["hostname"] === parsedHttpsServerUrl["hostname"]) {
|
|
|
|
// Create an WebSocket secure URL from the URL
|
|
var wssUrl = Common.WEBSOCKET_SECURE_PROTOCOL + Common.ltrim(url).substring(Common.WEBSOCKET_PROTOCOL["length"]);
|
|
|
|
// Return WebSocket secure URL
|
|
return wssUrl;
|
|
}
|
|
|
|
// Otherwise check if URL's protocol is HTTPS, the Tor server address's protocol is HTTP, and the URL is the same site as the Tor server address
|
|
else if(parsedUrl["protocol"] === Common.HTTPS_PROTOCOL && parsedTorServerUrl["protocol"] === Common.HTTP_PROTOCOL && parsedUrl["hostname"] === parsedTorServerUrl["hostname"]) {
|
|
|
|
// Create an HTTP URL from the URL
|
|
var httpUrl = Common.HTTP_PROTOCOL + Common.ltrim(url).substring(Common.HTTPS_PROTOCOL["length"]);
|
|
|
|
// Return HTTP URL
|
|
return httpUrl;
|
|
}
|
|
|
|
// Otherwise check if URL's protocol is WebSocket secure, the Tor server address's protocol is HTTP, and the URL is the same site as the Tor server address
|
|
else if(parsedUrl["protocol"] === Common.WEBSOCKET_SECURE_PROTOCOL && parsedTorServerUrl["protocol"] === Common.HTTP_PROTOCOL && parsedUrl["hostname"] === parsedTorServerUrl["hostname"]) {
|
|
|
|
// Create an WebSocket URL from the URL
|
|
var wsUrl = Common.WEBSOCKET_PROTOCOL + Common.ltrim(url).substring(Common.WEBSOCKET_SECURE_PROTOCOL["length"]);
|
|
|
|
// Return WebSocket URL
|
|
return wsUrl;
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return URL
|
|
return url;
|
|
}
|
|
}
|
|
|
|
// Get URL parmaters
|
|
static getUrlParameters() {
|
|
|
|
// Initialize result
|
|
var result = {};
|
|
|
|
// Check if URL query string exists
|
|
if(typeof URL_QUERY_STRING !== "undefined") {
|
|
|
|
// Get URL parameters from URL query string
|
|
var urlParameters = URL_QUERY_STRING.substring(Common.URL_QUERY_STRING_SEPARATOR["length"]).split(Common.URL_QUERY_STRING_PARAMETER_SEPARATOR);
|
|
|
|
// Go through all URL parameters
|
|
for(var i = 0; i < urlParameters["length"]; ++i) {
|
|
|
|
// Get URL parameter
|
|
var urlParameter = urlParameters[i].split(Common.URL_QUERY_STRING_PARAMETER_VALUE_SEPARATOR);
|
|
|
|
// Check if URL parameter is valid
|
|
if(urlParameter["length"] === 2) {
|
|
|
|
// Get URL parameter's key
|
|
var key = decodeURIComponent(urlParameter[0].replace(/\+/ug, "%20"));
|
|
|
|
// Check if key isn't already in the rersult
|
|
if(key in result === false) {
|
|
|
|
// Set URL parameter in the result
|
|
result[key] = decodeURIComponent(urlParameter[1].replace(/\+/ug, "%20"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return result
|
|
return result;
|
|
}
|
|
|
|
// URL contains protocol
|
|
static urlContainsProtocol(url) {
|
|
|
|
// Return if the URL contains protocol
|
|
return Common.URL_PROTOCOL_PATTERN.test(url) === true;
|
|
}
|
|
|
|
// URL contains top-level domain
|
|
static urlContainsTopLevelDomain(url) {
|
|
|
|
// Return if the URL contains a top-level domain
|
|
return Common.URL_TOP_LEVEL_DOMAIN_PATTERN.test(url) === true;
|
|
}
|
|
|
|
// Remove subdomain
|
|
static removeSubdomain(url) {
|
|
|
|
// Return URL's without its subdomain
|
|
return url.match(Common.URL_DOMAIN_NAME_PATTERN)[0];
|
|
}
|
|
|
|
// Remove top-level domain
|
|
static removeTopLevelDomain(url) {
|
|
|
|
// Return URL without its top-level domain
|
|
return url.match(Common.URL_WITHOUT_TOP_LEVEL_DOMAIN_PATTERN)[1];
|
|
}
|
|
|
|
// Remove trailing slashes
|
|
static removeTrailingSlashes(text) {
|
|
|
|
// Return text with its trailing slashes removed
|
|
return Common.rtrim(text).replace(Common.TRAILING_SLASHES_PATTERN, "");
|
|
}
|
|
|
|
// Remove duplicate slashes
|
|
static removeDuplicateSlashes(text) {
|
|
|
|
// Return text with its duplicate slashes removed
|
|
return text.replace(Common.DUPLICATE_SLASHES_PATTERN, "/");
|
|
}
|
|
|
|
// Split remaining
|
|
static splitRemaining(text, separator, limit) {
|
|
|
|
// Initialzie result
|
|
var result = [];
|
|
|
|
// Go through limit
|
|
for(var i = 0; i < limit; ++i) {
|
|
|
|
// Get last separator end
|
|
var lastSeparatorEnd = separator["lastIndex"];
|
|
|
|
// Get current separator start
|
|
var currentSeparatorStart = separator.exec(text);
|
|
|
|
// Check if separator start exists
|
|
if(currentSeparatorStart !== Common.NO_MATCH_FOUND) {
|
|
|
|
// Append part to result
|
|
result.push(text.slice(lastSeparatorEnd, currentSeparatorStart["index"]));
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Get last part
|
|
var lastPart = text.slice(lastSeparatorEnd);
|
|
|
|
// Check if last part exists and isn't a separator
|
|
if(lastPart["length"] !== 0 && separator.test(lastPart) === false) {
|
|
|
|
// Append last part to result
|
|
result.push(lastPart);
|
|
}
|
|
|
|
// Return result
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// Get last part
|
|
var lastPart = text.slice(separator["lastIndex"]);
|
|
|
|
// Check if last part exists and isn't a separator
|
|
if(lastPart["length"] !== 0 && separator.test(lastPart) === false) {
|
|
|
|
// Append last part to result
|
|
result.push(lastPart);
|
|
}
|
|
|
|
// Return result
|
|
return result;
|
|
}
|
|
|
|
// Remove duplicate newlines
|
|
static removeDuplicateNewlines(text) {
|
|
|
|
// Return text with duplicate newlines and trailing newlines removed from it
|
|
return text.replace(Common.DUPLICATE_NEWLINE_PATTERN, "\n").replace(Common.TRAILING_NEWLINE_PATTERN, "");
|
|
}
|
|
|
|
// Remove trailing zeros
|
|
static removeTrailingZeros(text) {
|
|
|
|
// Remove trailing zeros and ending decimal point from text
|
|
text = text.replace(Common.TRAILING_ZEROS_PATTERN, "$1").replace(Common.ENDING_DECIMAL_POINT_PATTERN, "");
|
|
|
|
// Check if text is invalid
|
|
if(Number.isNaN(parseFloat(text)) === true) {
|
|
|
|
// Return zero
|
|
return "0";
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return text
|
|
return text;
|
|
}
|
|
}
|
|
|
|
// Get number string precision
|
|
static getNumberStringPrecision(text) {
|
|
|
|
// Remove trailing zeros from text
|
|
text = Common.removeTrailingZeros(text);
|
|
|
|
// Check if text doesn't contains a fractional component
|
|
var fractionIndex = text.indexOf(".");
|
|
|
|
if(fractionIndex === Common.INDEX_NOT_FOUND) {
|
|
|
|
// Return zero
|
|
return 0;
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return number of fractional digits
|
|
return text["length"] - (fractionIndex + "."["length"]);
|
|
}
|
|
}
|
|
|
|
// Serialize object
|
|
static serializeObject(object) {
|
|
|
|
// Check if object is an array
|
|
if(Array.isArray(object) === true) {
|
|
|
|
// Return serialized object
|
|
return {
|
|
|
|
// Value
|
|
"Value": object.map(function(value) {
|
|
|
|
// Return serialized value
|
|
return Common.serializeObject(value);
|
|
})
|
|
};
|
|
}
|
|
|
|
// Otherwise check if object is an object
|
|
else if(typeof object === "object" && object !== null) {
|
|
|
|
// Check if object is a typed array
|
|
if("buffer" in object === true && object["buffer"] instanceof ArrayBuffer === true) {
|
|
|
|
// Get object's type
|
|
var type = Object["prototype"]["toString"].call(object).match(Common.OBJECT_TYPE_PATTERN);
|
|
|
|
// Return serialized object
|
|
return {
|
|
|
|
// Constructor
|
|
"Constructor": (type !== Common.NO_MATCH_FOUND) ? type[1] : object["constructor"]["name"],
|
|
|
|
// Value
|
|
"Value": Array.from(object)
|
|
};
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return serialized object
|
|
return {
|
|
|
|
// Constructor
|
|
"Constructor": (object instanceof BigNumber === true) ? "BigNumber" : object["constructor"]["name"],
|
|
|
|
// Properties
|
|
"Properties": Object.entries(object).map(function(property) {
|
|
|
|
// Return serialized property
|
|
return {
|
|
|
|
// Name
|
|
"Name": property[0],
|
|
|
|
// Value
|
|
"Value": Common.serializeObject(property[1])
|
|
};
|
|
})
|
|
};
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return serialized object
|
|
return {
|
|
|
|
// Value
|
|
"Value": object
|
|
};
|
|
}
|
|
}
|
|
|
|
// Unserialize object
|
|
static unserializeObject(serializedObject) {
|
|
|
|
// Check if serialized object contains a constructor
|
|
if("Constructor" in serializedObject === true) {
|
|
|
|
// Check if serialized object can be created
|
|
if(serializedObject["Constructor"] in globalThis === true) {
|
|
|
|
// Check if serialzed object is a typed array
|
|
if("Value" in serializedObject === true) {
|
|
|
|
// Create object
|
|
var object = new globalThis[serializedObject["Constructor"]](serializedObject["Value"]);
|
|
|
|
// Return object
|
|
return object;
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Create object
|
|
var object = Object.create(globalThis[serializedObject["Constructor"]]["prototype"]);
|
|
|
|
// Go through all of the serialized object's properties
|
|
for(var i = 0; i < serializedObject["Properties"]["length"]; ++i) {
|
|
|
|
// Get property
|
|
var property = serializedObject["Properties"][i];
|
|
|
|
// Set property in the object
|
|
object[property["Name"]] = Common.unserializeObject(property["Value"]);
|
|
}
|
|
|
|
// Return object
|
|
return object;
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return undefined
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
// Otherwise check if serialzied object is an array
|
|
else if(Array.isArray(serializedObject["Value"]) === true) {
|
|
|
|
// Return serialized object's value
|
|
return serializedObject["Value"].map(function(serializedValue) {
|
|
|
|
// Return unserializing the serialized value
|
|
return Common.unserializeObject(serializedValue);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return serialized object's value
|
|
return serializedObject["Value"];
|
|
}
|
|
}
|
|
|
|
// Request animation frame or timeout
|
|
static requestAnimationFrameOrTimeout(callback) {
|
|
|
|
// Initialize animation frame
|
|
var animationFrame;
|
|
|
|
// Set timeout
|
|
var timeout = setTimeout(function() {
|
|
|
|
// Cancel animation frame
|
|
cancelAnimationFrame(animationFrame);
|
|
|
|
// Run callback
|
|
callback(event);
|
|
|
|
}, Common.REQUEST_ANIMATION_FRAME_TIMEOUT_MILLISECONDS);
|
|
|
|
// Set animation frame
|
|
animationFrame = requestAnimationFrame(function(event) {
|
|
|
|
// Clear timeout
|
|
clearTimeout(timeout);
|
|
|
|
// Run callback
|
|
callback(event);
|
|
});
|
|
}
|
|
|
|
// Ltrim
|
|
static ltrim(text) {
|
|
|
|
// Return text with leading whitespace removed
|
|
return text.replace(Common.LEADING_WHITESPACE_PATTERN, "");
|
|
}
|
|
|
|
// Rtrim
|
|
static rtrim(text) {
|
|
|
|
// Return text with trailing whitespace removed
|
|
return text.replace(Common.TRAILING_WHITESPACE_PATTERN, "");
|
|
}
|
|
|
|
// Get preserved URL parameters
|
|
static getPreservedUrlParameters() {
|
|
|
|
// Check if is popup
|
|
if(Common.isPopup() === true) {
|
|
|
|
// Return preserved URL parameters
|
|
return Common.URL_QUERY_STRING_PARAMETER_SEPARATOR + encodeURIComponent("Is Popup").replace(/%20/ug, "+") + Common.URL_QUERY_STRING_PARAMETER_VALUE_SEPARATOR + encodeURIComponent("True").replace(/%20/ug, "+");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return nothing
|
|
return "";
|
|
}
|
|
}
|
|
|
|
// Save file
|
|
static saveFile(name, contents) {
|
|
|
|
// Create anchor
|
|
var anchor = $("<a></a>");
|
|
|
|
// Create URL from contents
|
|
var url = URL.createObjectURL(new Blob([
|
|
|
|
// Contents
|
|
contents
|
|
], {
|
|
|
|
// Type
|
|
"type": "application/octet-stream"
|
|
}));
|
|
|
|
// Set anchor's href to URL
|
|
anchor.attr("href", url);
|
|
|
|
// Set anchor's download to name
|
|
anchor.attr("download", name);
|
|
|
|
// Click on anchor
|
|
anchor.get(0).click();
|
|
|
|
// Set timeout
|
|
setTimeout(function() {
|
|
|
|
// Revoke URL
|
|
URL.revokeObjectURL(url);
|
|
}, 0);
|
|
}
|
|
|
|
// Has whitespace
|
|
static hasWhitespace(text) {
|
|
|
|
// Return if text has whitespace
|
|
return Common.HAS_WHITESPACE_PATTERN.test(text) === true;
|
|
}
|
|
|
|
// Remove whitespace
|
|
static removeWhitespace(text) {
|
|
|
|
// Return text with whitespace removed
|
|
return text.replace(Common.HAS_WHITESPACE_PATTERN, "");
|
|
}
|
|
|
|
// Milliseconds in a second
|
|
static get MILLISECONDS_IN_A_SECOND() {
|
|
|
|
// Return milliseconds in a second
|
|
return 1000;
|
|
}
|
|
|
|
// Seconds in a minute
|
|
static get SECONDS_IN_A_MINUTE() {
|
|
|
|
// Return minutes in a second
|
|
return 60;
|
|
}
|
|
|
|
// Minutes in an hour
|
|
static get MINUTES_IN_AN_HOUR() {
|
|
|
|
// Return minutes in an hour
|
|
return 60;
|
|
}
|
|
|
|
// Hours in a day
|
|
static get HOURS_IN_A_DAY() {
|
|
|
|
// Return hours in a day
|
|
return 24;
|
|
}
|
|
|
|
// Days in a week
|
|
static get DAYS_IN_A_WEEK() {
|
|
|
|
// Return days in a week
|
|
return 7;
|
|
}
|
|
|
|
// Weeks in a year
|
|
static get WEEKS_IN_A_YEAR() {
|
|
|
|
// Return weeks in a year
|
|
return 52;
|
|
}
|
|
|
|
// Byte max value
|
|
static get BYTE_MAX_VALUE() {
|
|
|
|
// Return byte max value
|
|
return Math.pow(2, Common.BITS_IN_A_BYTE) - 1;
|
|
}
|
|
|
|
// Uint16 max value
|
|
static get UINT16_MAX_VALUE() {
|
|
|
|
// Return uint16 max value
|
|
return Math.pow(2, Common.BITS_IN_A_BYTE * Uint16Array["BYTES_PER_ELEMENT"]) - 1;
|
|
}
|
|
|
|
// Uint32 max value
|
|
static get UINT32_MAX_VALUE() {
|
|
|
|
// Return uint32 max value
|
|
return Math.pow(2, Common.BITS_IN_A_BYTE * Uint32Array["BYTES_PER_ELEMENT"]) - 1;
|
|
}
|
|
|
|
// Int32 max value
|
|
static get INT32_MAX_VALUE() {
|
|
|
|
// Return int32 max value
|
|
return Math.pow(2, Common.BITS_IN_A_BYTE * Int32Array["BYTES_PER_ELEMENT"] - 1) - 1;
|
|
}
|
|
|
|
// Bytes in a uint8
|
|
static get BYTES_IN_A_UINT8() {
|
|
|
|
// Return bytes in a uint8
|
|
return 8 / Common.BITS_IN_A_BYTE;
|
|
}
|
|
|
|
// Bytes in a uint16
|
|
static get BYTES_IN_A_UINT16() {
|
|
|
|
// Return bytes in a uint16
|
|
return 16 / Common.BITS_IN_A_BYTE;
|
|
}
|
|
|
|
// Bytes in a uint32
|
|
static get BYTES_IN_A_UINT32() {
|
|
|
|
// Return bytes in a uint32
|
|
return 32 / Common.BITS_IN_A_BYTE;
|
|
}
|
|
|
|
// Bytes in a uint64
|
|
static get BYTES_IN_A_UINT64() {
|
|
|
|
// Return bytes in a uint64
|
|
return 64 / Common.BITS_IN_A_BYTE;
|
|
}
|
|
|
|
// Invalid local storage item
|
|
static get INVALID_LOCAL_STORAGE_ITEM() {
|
|
|
|
// Return invalid local storage item
|
|
return null;
|
|
}
|
|
|
|
// Index not found
|
|
static get INDEX_NOT_FOUND() {
|
|
|
|
// Return index not found
|
|
return -1;
|
|
}
|
|
|
|
// No match found
|
|
static get NO_MATCH_FOUND() {
|
|
|
|
// Return no match found
|
|
return null;
|
|
}
|
|
|
|
// No tab index
|
|
static get NO_TAB_INDEX() {
|
|
|
|
// Return no tab index
|
|
return "-1";
|
|
}
|
|
|
|
// Decimal number base
|
|
static get DECIMAL_NUMBER_BASE() {
|
|
|
|
// Return decimal number base
|
|
return 10;
|
|
}
|
|
|
|
// Hex number base
|
|
static get HEX_NUMBER_BASE() {
|
|
|
|
// Return hex number base
|
|
return 16;
|
|
}
|
|
|
|
// Hex number length
|
|
static get HEX_NUMBER_LENGTH() {
|
|
|
|
// Return hex number length
|
|
return "FF"["length"];
|
|
}
|
|
|
|
// Hex color length
|
|
static get HEX_COLOR_LENGTH() {
|
|
|
|
// Return hex color length
|
|
return "FFFFFF"["length"];
|
|
}
|
|
|
|
// Hex number padding
|
|
static get HEX_NUMBER_PADDING() {
|
|
|
|
// Return hex number padding
|
|
return "0";
|
|
}
|
|
|
|
// Focus change event
|
|
static get FOCUS_CHANGE_EVENT() {
|
|
|
|
// Return focus change event
|
|
return "FocusChangeEvent";
|
|
}
|
|
|
|
// No attribute
|
|
static get NO_ATTRIBUTE() {
|
|
|
|
// Return no attribute
|
|
return undefined;
|
|
}
|
|
|
|
// No argument
|
|
static get NO_ARGUMENT() {
|
|
|
|
// Return no argument
|
|
return undefined;
|
|
}
|
|
|
|
// URL query string separator
|
|
static get URL_QUERY_STRING_SEPARATOR() {
|
|
|
|
// Return URL query string separator
|
|
return "?";
|
|
}
|
|
|
|
// URL query string parameter separator
|
|
static get URL_QUERY_STRING_PARAMETER_SEPARATOR() {
|
|
|
|
// Return URL query string parameter separator
|
|
return "&";
|
|
}
|
|
|
|
// URL query string parameter value separator
|
|
static get URL_QUERY_STRING_PARAMETER_VALUE_SEPARATOR() {
|
|
|
|
// Return URL query string parameter value separator
|
|
return "=";
|
|
}
|
|
|
|
// Data attribute prefix
|
|
static get DATA_ATTRIBUTE_PREFIX() {
|
|
|
|
// Return data attribute prefix
|
|
return "data-";
|
|
}
|
|
|
|
// First match result index
|
|
static get FIRST_MATCH_RESULT_INDEX() {
|
|
|
|
// Return first match result index
|
|
return 1;
|
|
}
|
|
|
|
// JSON NULL value
|
|
static get JSON_NULL_VALUE() {
|
|
|
|
// Return JSON NULL value
|
|
return null;
|
|
}
|
|
|
|
// HTTP protocol
|
|
static get HTTP_PROTOCOL() {
|
|
|
|
// Return HTTP protocol
|
|
return "http:";
|
|
}
|
|
|
|
// HTTPS protocol
|
|
static get HTTPS_PROTOCOL() {
|
|
|
|
// Return HTTPS protocol
|
|
return "https:";
|
|
}
|
|
|
|
// WebSocket protocol
|
|
static get WEBSOCKET_PROTOCOL() {
|
|
|
|
// Return WebSocket protocol
|
|
return "ws:";
|
|
}
|
|
|
|
// WebSocket secure protocol
|
|
static get WEBSOCKET_SECURE_PROTOCOL() {
|
|
|
|
// Return WebSocket secure protocol
|
|
return "wss:";
|
|
}
|
|
|
|
// File protocol
|
|
static get FILE_PROTOCOL() {
|
|
|
|
// Return file protocol
|
|
return "file:";
|
|
}
|
|
|
|
// HTTP no response status
|
|
static get HTTP_NO_RESPONSE_STATUS() {
|
|
|
|
// Return HTTP no response status
|
|
return 0;
|
|
}
|
|
|
|
// HTTP ok status
|
|
static get HTTP_OK_STATUS() {
|
|
|
|
// Return HTTP ok status
|
|
return 200;
|
|
}
|
|
|
|
// HTTP bad request status
|
|
static get HTTP_BAD_REQUEST_STATUS() {
|
|
|
|
// Return HTTP bad request status
|
|
return 400;
|
|
}
|
|
|
|
// HTTP unauthorized status
|
|
static get HTTP_UNAUTHORIZED_STATUS() {
|
|
|
|
// Return HTTP unauthorized status
|
|
return 401;
|
|
}
|
|
|
|
// HTTP forbidden status
|
|
static get HTTP_FORBIDDEN_STATUS() {
|
|
|
|
// Return HTTP forbidden status
|
|
return 403;
|
|
}
|
|
|
|
// HTTP not found status
|
|
static get HTTP_NOT_FOUND_STATUS() {
|
|
|
|
// Return HTTP not found status
|
|
return 404;
|
|
}
|
|
|
|
// HTTP payload too large status
|
|
static get HTTP_PAYLOAD_TOO_LARGE_STATUS() {
|
|
|
|
// Return HTTP payload too large status
|
|
return 413;
|
|
}
|
|
|
|
// HTTP unsupported media type status
|
|
static get HTTP_UNSUPPORTED_MEDIA_TYPE_STATUS() {
|
|
|
|
// Return HTTP unsupported media type status
|
|
return 415;
|
|
}
|
|
|
|
// HTTP bad gateway status
|
|
static get HTTP_BAD_GATEWAY_STATUS() {
|
|
|
|
// Return HTTP bad gateway status
|
|
return 502;
|
|
}
|
|
|
|
// HTTP gateway timeout status
|
|
static get HTTP_GATEWAY_TIMEOUT_STATUS() {
|
|
|
|
// Return HTTP gateway timeout status
|
|
return 504;
|
|
}
|
|
|
|
// Double quote pattern
|
|
static get DOUBLE_QUOTE_PATTERN() {
|
|
|
|
// Return double quote pattern
|
|
return /"/ug;
|
|
}
|
|
|
|
// Enable event
|
|
static get ENABLE_EVENT() {
|
|
|
|
// Return enable event
|
|
return "CommonEnableEvent";
|
|
}
|
|
|
|
// Primary pointer button bitmask
|
|
static get PRIMARY_POINTER_BUTTON_BITMASK() {
|
|
|
|
// Return primary pointer button bitmask
|
|
return 1;
|
|
}
|
|
|
|
// January month index
|
|
static get JANUARY_MONTH_INDEX() {
|
|
|
|
// Return january month index
|
|
return 0;
|
|
}
|
|
|
|
// Sort equal to
|
|
static get SORT_EQUAL() {
|
|
|
|
// Return sort equal
|
|
return 0;
|
|
}
|
|
|
|
// Sort greater than
|
|
static get SORT_GREATER_THAN() {
|
|
|
|
// Return sort greater than
|
|
return Common.SORT_EQUAL + 1;
|
|
}
|
|
|
|
// Sort less than
|
|
static get SORT_LESS_THAN() {
|
|
|
|
// Return sort less than
|
|
return Common.SORT_EQUAL - 1;
|
|
}
|
|
|
|
// Visibility state visible
|
|
static get VISIBILITY_STATE_VISIBLE() {
|
|
|
|
// Return visibility state visible
|
|
return "visible";
|
|
}
|
|
|
|
// Visibility state hidden
|
|
static get VISIBILITY_STATE_HIDDEN() {
|
|
|
|
// Return visibility state hidden
|
|
return "hidden";
|
|
}
|
|
|
|
// Canceled error
|
|
static get CANCELED_ERROR() {
|
|
|
|
// Return canceled error
|
|
return "CommonCancelError";
|
|
}
|
|
|
|
// No cancel occurred
|
|
static get NO_CANCEL_OCCURRED() {
|
|
|
|
// Return no cancel occurred
|
|
return null;
|
|
}
|
|
|
|
// Hex prefix
|
|
static get HEX_PREFIX() {
|
|
|
|
// Return hex prefix
|
|
return "0x";
|
|
}
|
|
|
|
// Default HTTP port
|
|
static get DEFAULT_HTTP_PORT() {
|
|
|
|
// Return default HTTP port
|
|
return 80;
|
|
}
|
|
|
|
// Default HTTPS port
|
|
static get DEFAULT_HTTPS_PORT() {
|
|
|
|
// Return default HTTPS port
|
|
return 443;
|
|
}
|
|
|
|
// Private
|
|
|
|
// Bits in a byte
|
|
static get BITS_IN_A_BYTE() {
|
|
|
|
// Return bits in a byte
|
|
return 8;
|
|
}
|
|
|
|
// Number string pattern
|
|
static get NUMBER_STRING_PATTERN() {
|
|
|
|
// Return number string pattern
|
|
return /^[+-]?(?:0(?:\.\d+)?|[1-9]\d*(?:\.\d+)?|\.\d+)$/u;
|
|
}
|
|
|
|
// Hex string pattern
|
|
static get HEX_STRING_PATTERN() {
|
|
|
|
// Return hex string pattern
|
|
return /^(?:[0-9A-F])+$/iu;
|
|
}
|
|
|
|
// Hex character to value
|
|
static get HEX_CHARACTER_TO_VALUE() {
|
|
|
|
// Return hex character to value
|
|
return {
|
|
|
|
// Zero
|
|
"0": 0x00,
|
|
|
|
// One
|
|
"1": 0x01,
|
|
|
|
// Two
|
|
"2": 0x02,
|
|
|
|
// Three
|
|
"3": 0x03,
|
|
|
|
// Four
|
|
"4": 0x04,
|
|
|
|
// Five
|
|
"5": 0x05,
|
|
|
|
// Six
|
|
"6": 0x06,
|
|
|
|
// Seven
|
|
"7": 0x07,
|
|
|
|
// Eight
|
|
"8": 0x08,
|
|
|
|
// Nine
|
|
"9": 0x09,
|
|
|
|
// Uppercase a
|
|
"A": 0x0A,
|
|
|
|
// Uppercase b
|
|
"B": 0x0B,
|
|
|
|
// Uppercase c
|
|
"C": 0x0C,
|
|
|
|
// Uppercase d
|
|
"D": 0x0D,
|
|
|
|
// Uppercase e
|
|
"E": 0x0E,
|
|
|
|
// Uppercase f
|
|
"F": 0x0F,
|
|
|
|
// Lowercase a
|
|
"a": 0x0A,
|
|
|
|
// Lowercase b
|
|
"b": 0x0B,
|
|
|
|
// Lowercase c
|
|
"c": 0x0C,
|
|
|
|
// Lowercase d
|
|
"d": 0x0D,
|
|
|
|
// Lowercase e
|
|
"e": 0x0E,
|
|
|
|
// Lowercase f
|
|
"f": 0x0F
|
|
};
|
|
}
|
|
|
|
// Value to hex character
|
|
static get VALUE_TO_HEX_CHARACTER() {
|
|
|
|
// Return value to hex character
|
|
return [
|
|
|
|
// Zero
|
|
"0",
|
|
|
|
// One
|
|
"1",
|
|
|
|
// Two
|
|
"2",
|
|
|
|
// Three
|
|
"3",
|
|
|
|
// Four
|
|
"4",
|
|
|
|
// Five
|
|
"5",
|
|
|
|
// Six
|
|
"6",
|
|
|
|
// Seven
|
|
"7",
|
|
|
|
// Eight
|
|
"8",
|
|
|
|
// Nine
|
|
"9",
|
|
|
|
// A
|
|
"a",
|
|
|
|
// B
|
|
"b",
|
|
|
|
// C
|
|
"c",
|
|
|
|
// D
|
|
"d",
|
|
|
|
// E
|
|
"e",
|
|
|
|
// F
|
|
"f"
|
|
];
|
|
}
|
|
|
|
// RFC 3339 string pattern
|
|
static get RFC_3339_STRING_PATTERN() {
|
|
|
|
// Return RFC 3339 string pattern
|
|
return /^(?:\d+)-(?:0[1-9]|1[012])-(?:0[1-9]|[12]\d|3[01])[Tt](?:[01]\d|2[0-3]):(?:[0-5]\d):(?:[0-5]\d|60)(?:\.\d+)?(?:(?:[Zz])|(?:[\+|\-](?:[01]\d|2[0-3]):[0-5]\d))$/u;
|
|
}
|
|
|
|
// Lowercase string pattern
|
|
static get LOWERCASE_STRING_PATTERN() {
|
|
|
|
// Return lowercase string pattern
|
|
return /^[a-z0-9]+$/u;
|
|
}
|
|
|
|
// Single quote HTML entity
|
|
static get SINGLE_QUOTE_HTML_ENTITY() {
|
|
|
|
// Return single quote HTML entity
|
|
return "'";
|
|
}
|
|
|
|
// Double quote HTML entity
|
|
static get DOUBLE_QUOTE_HTML_ENTITY() {
|
|
|
|
// Return double quote HTML entity
|
|
return """;
|
|
}
|
|
|
|
// Grave accent HTML entity
|
|
static get GRAVE_ACCENT_HTML_ENTITY() {
|
|
|
|
// Return grave accent HTML entity
|
|
return "`";
|
|
}
|
|
|
|
// Single quote pattern
|
|
static get SINGLE_QUOTE_PATTERN() {
|
|
|
|
// Return single quote pattern
|
|
return /'/ug;
|
|
}
|
|
|
|
// Grave accent pattern
|
|
static get GRAVE_ACCENT_PATTERN() {
|
|
|
|
// Return grave accent pattern
|
|
return /`/ug;
|
|
}
|
|
|
|
// Return low memory threshold gigabytes
|
|
static get LOW_MEMORY_THRESHOLD_GIGABYTES() {
|
|
|
|
// Return low memory threshold gigabytes
|
|
return 2;
|
|
}
|
|
|
|
// Return high memory threshold gigabytes
|
|
static get HIGH_MEMORY_THRESHOLD_GIGABYTES() {
|
|
|
|
// Return high memory threshold gigabytes
|
|
return 8;
|
|
}
|
|
|
|
// URL protocol pattern
|
|
static get URL_PROTOCOL_PATTERN() {
|
|
|
|
// Return URL protocol pattern
|
|
return /^[^:]+:\/\/.+/u;
|
|
}
|
|
|
|
// URL top-level domain pattern
|
|
static get URL_TOP_LEVEL_DOMAIN_PATTERN() {
|
|
|
|
// Return URL top-level domain pattern
|
|
return /[^\.]+\.[^\/?:#\s]+(?:[\/?:#\s]|$)/u;
|
|
}
|
|
|
|
// URL domain name pattern
|
|
static get URL_DOMAIN_NAME_PATTERN() {
|
|
|
|
// Return URL domain name pattern
|
|
return /[^\.]+\.[^\.]+$/u;
|
|
}
|
|
|
|
// URL without top-level domain pattern
|
|
static get URL_WITHOUT_TOP_LEVEL_DOMAIN_PATTERN() {
|
|
|
|
// Return URL without top-level domain pattern
|
|
return /([^\.]+)\.[^\.]+$/u;
|
|
}
|
|
|
|
// Trailing slashes pattern
|
|
static get TRAILING_SLASHES_PATTERN() {
|
|
|
|
// Return trailing slashes pattern
|
|
return /\/+$/u;
|
|
}
|
|
|
|
// Duplicate slashes pattern
|
|
static get DUPLICATE_SLASHES_PATTERN() {
|
|
|
|
// Return duplicate slashes pattern
|
|
return /\/+/ug;
|
|
}
|
|
|
|
// Duplicate newline pattern
|
|
static get DUPLICATE_NEWLINE_PATTERN() {
|
|
|
|
// Return duplicate newline pattern
|
|
return /\n+/ug;
|
|
}
|
|
|
|
// Trailing zeros pattern
|
|
static get TRAILING_ZEROS_PATTERN() {
|
|
|
|
// Return trailing zeros pattern
|
|
return /(\.\d*?)0+$/u;
|
|
}
|
|
|
|
// Ending decimal point pattern
|
|
static get ENDING_DECIMAL_POINT_PATTERN() {
|
|
|
|
// Return ending decimal point pattern
|
|
return /\.$/u;
|
|
}
|
|
|
|
// Trailing newline pattern
|
|
static get TRAILING_NEWLINE_PATTERN() {
|
|
|
|
// Return trailing newline pattern
|
|
return /\n$/u;
|
|
}
|
|
|
|
// Object type pattern
|
|
static get OBJECT_TYPE_PATTERN() {
|
|
|
|
// Return object type pattern
|
|
return /^\[object\s*(.*)\]$/u;
|
|
}
|
|
|
|
// Request animation frame timeout milliseconds
|
|
static get REQUEST_ANIMATION_FRAME_TIMEOUT_MILLISECONDS() {
|
|
|
|
// Return request animation frame timeout milliseconds
|
|
return 100;
|
|
}
|
|
|
|
// Leading whitespace pattern
|
|
static get LEADING_WHITESPACE_PATTERN() {
|
|
|
|
// Return leading whitespace pattern
|
|
return /^\s+/u;
|
|
}
|
|
|
|
// Trailing whitespace pattern
|
|
static get TRAILING_WHITESPACE_PATTERN() {
|
|
|
|
// Return leading whitespace pattern
|
|
return /\s+$/u;
|
|
}
|
|
|
|
// Has whitespace pattern
|
|
static get HAS_WHITESPACE_PATTERN() {
|
|
|
|
// Return has whitespace pattern
|
|
return /\s/ug;
|
|
}
|
|
}
|
|
|
|
|
|
// Main function
|
|
|
|
// Set global object's common
|
|
globalThis["Common"] = Common;
|
|
|
|
// Check if jQuery exists
|
|
if(typeof jQuery === "function") {
|
|
|
|
// Disable tab
|
|
$["prototype"].disableTab = function() {
|
|
|
|
// Go through each element
|
|
this.each(function() {
|
|
|
|
// Add no tab index to element
|
|
$(this).attr("tabindex", Common.NO_TAB_INDEX);
|
|
});
|
|
|
|
// Return elements
|
|
return this;
|
|
};
|
|
|
|
// Enable tab
|
|
$["prototype"].enableTab = function() {
|
|
|
|
// Go through each element
|
|
this.each(function() {
|
|
|
|
// Remove tab index from element
|
|
$(this).removeAttr("tabindex");
|
|
});
|
|
|
|
// Return elements
|
|
return this;
|
|
};
|
|
|
|
// Disable
|
|
$["prototype"].disable = function() {
|
|
|
|
// Go through each element
|
|
this.each(function() {
|
|
|
|
// Disable the element
|
|
$(this).prop("disabled", true);
|
|
});
|
|
|
|
// Return elements
|
|
return this;
|
|
};
|
|
|
|
// Enable
|
|
$["prototype"].enable = function() {
|
|
|
|
// Go through each element
|
|
this.each(function() {
|
|
|
|
// Enable the element and trigger an enable event on the element
|
|
$(this).prop("disabled", false).trigger(Common.ENABLE_EVENT);
|
|
});
|
|
|
|
// Return elements
|
|
return this;
|
|
};
|
|
|
|
// Outer Html
|
|
$["prototype"].outerHtml = function() {
|
|
|
|
// Return element's outer HTML
|
|
return this.wrap("<div>").parent().html();
|
|
};
|
|
|
|
// Scroll idle duration milliseconds
|
|
var SCROLL_IDLE_DURATION_MILLISECONDS = 250;
|
|
|
|
// Scroll stopped
|
|
$["fn"].scrollStopped = function(callback) {
|
|
|
|
// Go through each element
|
|
this.each(function() {
|
|
|
|
// Set self
|
|
var self = $(this);
|
|
|
|
// Get index
|
|
var index = (typeof self.data("scrollStoppedIndex") === "undefined") ? 0 : self.data("scrollStoppedIndex");
|
|
|
|
// Self scroll scroll stopped index event
|
|
self.on("scroll.scrollStopped" + index.toFixed(), function(event) {
|
|
|
|
// Check if scroll stopped timeout index exists
|
|
if(typeof self.data("scrollStoppedTimeout" + index.toFixed()) !== "undefined") {
|
|
|
|
// Clear scroll stopped timeout index
|
|
clearTimeout(self.data("scrollStoppedTimeout" + index.toFixed()));
|
|
}
|
|
|
|
// Set scroll stopped timeout index
|
|
self.data("scrollStoppedTimeout" + index.toFixed(), setTimeout(function() {
|
|
|
|
// Remove scroll stopped timeout index
|
|
self.removeData("scrollStoppedTimeout" + index.toFixed());
|
|
|
|
// Run callback
|
|
callback.bind(self)(event);
|
|
|
|
}, SCROLL_IDLE_DURATION_MILLISECONDS));
|
|
});
|
|
|
|
// Increment index
|
|
self.data("scrollStoppedIndex", (index === Number.MAX_SAFE_INTEGER) ? 0 : index + 1);
|
|
});
|
|
|
|
// Return elements
|
|
return this;
|
|
};
|
|
|
|
// Transition end timeout milliseconds
|
|
var TRANSITION_END_TIMEOUT_MILLISECONDS = 100;
|
|
|
|
// Transition end or timeout
|
|
$["fn"].transitionEndOrTimeout = function(callback, property) {
|
|
|
|
// Go through each element
|
|
this.each(function() {
|
|
|
|
// Set self
|
|
var self = $(this);
|
|
|
|
// Set timeout
|
|
var timeout = TRANSITION_END_TIMEOUT_MILLISECONDS;
|
|
|
|
// Go through all of the element's transition properties
|
|
var properties = self.css("transition-property").split(",");
|
|
for(var i = 0; i < properties["length"]; ++i) {
|
|
|
|
// Check if property was found
|
|
if(properties[i].trim() === property) {
|
|
|
|
// Get transition's duration
|
|
var duration = self.css("transition-duration").split(",")[i].trim();
|
|
|
|
// Get transition's delay
|
|
var delay = self.css("transition-delay").split(",")[i].trim();
|
|
|
|
// Set timeout to the duration
|
|
timeout = parseFloat(duration) * ((duration.indexOf("ms") !== Common.INDEX_NOT_FOUND) ? 1 : Common.MILLISECONDS_IN_A_SECOND) + parseFloat(delay) * ((delay.indexOf("ms") !== Common.INDEX_NOT_FOUND) ? 1 : Common.MILLISECONDS_IN_A_SECOND) + TRANSITION_END_TIMEOUT_MILLISECONDS;
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Get index
|
|
var index = (typeof self.data("transitionEndOrTimeoutIndex") === "undefined") ? 0 : self.data("transitionEndOrTimeoutIndex");
|
|
|
|
// Set transition end or timeout timeout index
|
|
self.data("transitionEndOrTimeoutTimeout" + index.toFixed(), setTimeout(function() {
|
|
|
|
// Turn off transition end transition end or timeout index event
|
|
self.off("transitionend.transitionEndOrTimeout" + index.toFixed());
|
|
|
|
// Remove transition end or timeout timeout index
|
|
self.removeData("transitionEndOrTimeoutTimeout" + index.toFixed());
|
|
|
|
// Run callback
|
|
callback.bind(self)();
|
|
|
|
}, timeout));
|
|
|
|
// Self transition end transition end or timeout index event
|
|
self.one("transitionend.transitionEndOrTimeout" + index.toFixed(), function(event) {
|
|
|
|
// Clear transition end or timeout timeout index
|
|
clearTimeout(self.data("transitionEndOrTimeoutTimeout" + index.toFixed()));
|
|
|
|
// Remove transition end or timeout timeout index
|
|
self.removeData("transitionEndOrTimeoutTimeout" + index.toFixed());
|
|
|
|
// Run callback
|
|
callback.bind(self)(event);
|
|
});
|
|
|
|
// Increment index
|
|
self.data("transitionEndOrTimeoutIndex", (index === Number.MAX_SAFE_INTEGER) ? 0 : index + 1);
|
|
});
|
|
|
|
// Return elements
|
|
return this;
|
|
};
|
|
|
|
// Off transition end or timeout
|
|
$["fn"].offTransitionEndOrTimeout = function() {
|
|
|
|
// Go through each element
|
|
this.each(function() {
|
|
|
|
// Set self
|
|
var self = $(this);
|
|
|
|
// Turn off transition end event
|
|
self.off("transitionend");
|
|
|
|
// Get data
|
|
var data = self.data();
|
|
|
|
// Go through all data
|
|
for(var key in data) {
|
|
|
|
if(data.hasOwnProperty(key) === true) {
|
|
|
|
// Check if data is a transition end or timeout timeout index
|
|
if(key.indexOf("transitionEndOrTimeoutTimeout") === 0) {
|
|
|
|
// Clear transition end or timeout timeout index
|
|
clearTimeout(self.data(key));
|
|
|
|
// Remove transition end or timeout timeout index
|
|
self.removeData(key);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Return elements
|
|
return this;
|
|
};
|
|
}
|
|
|
|
// Check if BigNumber exists
|
|
if(typeof BigNumber === "function") {
|
|
|
|
// Big endian
|
|
BigNumber.BIG_ENDIAN = 0;
|
|
|
|
// Little endian
|
|
BigNumber.LITTLE_ENDIAN = 1;
|
|
|
|
// Any length
|
|
BigNumber.ANY_LENGTH = -1;
|
|
|
|
// To bytes
|
|
BigNumber.prototype.toBytes = function(endianness = BigNumber.LITTLE_ENDIAN, length = BigNumber.ANY_LENGTH) {
|
|
|
|
// Check if is number isn't supported
|
|
if(this.isFinite() === false || this.isNaN() === true || this.isNegative() === true || this.isInteger() === false) {
|
|
|
|
// Throw error
|
|
throw "Unsupported number.";
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Create bytes
|
|
var bytes = new Array((length === BigNumber.ANY_LENGTH) ? 1 : length).fill(0);
|
|
|
|
// Make number a whole number
|
|
var temp = this.dividedToIntegerBy(1);
|
|
|
|
// Go through all bytes in the whole number
|
|
for(var i = 0; temp.isGreaterThan(0); ++i) {
|
|
|
|
// Get byte from the whole number
|
|
var byte = temp.modulo(Common.BYTE_MAX_VALUE + 1).toNumber();
|
|
|
|
// Remove byte from the whole number
|
|
temp = temp.dividedToIntegerBy(Common.BYTE_MAX_VALUE + 1);
|
|
|
|
// Check if space exists in bytes for the byte
|
|
if(i < bytes["length"]) {
|
|
|
|
// Set byte in bytes
|
|
bytes[i] = byte;
|
|
}
|
|
|
|
// Otherwise check if length is Constrained
|
|
else if(length !== BigNumber.ANY_LENGTH) {
|
|
|
|
// Throw error
|
|
throw "Insufficient length.";
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Append byte to bytes
|
|
bytes.push(byte);
|
|
}
|
|
}
|
|
|
|
// Check if endianness is big endian
|
|
if(endianness === BigNumber.BIG_ENDIAN) {
|
|
|
|
// Reverse bytes order
|
|
bytes = bytes.reverse();
|
|
}
|
|
|
|
// Return bytes
|
|
return new Uint8Array(bytes);
|
|
}
|
|
};
|
|
}
|
|
|
|
// Check if object exists
|
|
if(typeof Object === "function") {
|
|
|
|
// Is object
|
|
Object.isObject = function(variable) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Return if variable is an object
|
|
return Object.getPrototypeOf(variable)["constructor"]["name"] === "Object";
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Return false
|
|
return false;
|
|
}
|
|
};
|
|
}
|
|
|
|
// Check if Uint8Array exist
|
|
if(typeof Uint8Array === "function") {
|
|
|
|
// Read uint32 little endian
|
|
Uint8Array["prototype"].readUInt32LE = function(index) {
|
|
|
|
// Return value at index as a uint32 in little endian
|
|
return this[index] | (this[index + 1] << Common.BITS_IN_A_BYTE) | (this[index + 2] << (Common.BITS_IN_A_BYTE * 2)) | (this[index + 3] << (Common.BITS_IN_A_BYTE * 3));
|
|
};
|
|
|
|
// Read uint16 little endian
|
|
Uint8Array["prototype"].readUInt16LE = function(index) {
|
|
|
|
// Return value at index as a uint16 in little endian
|
|
return this[index] | (this[index + 1] << Common.BITS_IN_A_BYTE);
|
|
};
|
|
}
|
|
|
|
// Check if cross-origin isolated doesn't exist
|
|
if(typeof crossOriginIsolated === "undefined") {
|
|
|
|
// Set cross-origin isolated to false
|
|
var crossOriginIsolated = false;
|
|
}
|