8257 lines
193 KiB
Plaintext
8257 lines
193 KiB
Plaintext
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\crypto-js.d.ts
|
|
|
|
// Type definitions for crypto-js v4.0.0
|
|
// Project: https://github.com/brix/crypto-js
|
|
// Definitions by: Michael Zabka <https://github.com/misak113>
|
|
// Max Lysenko <https://github.com/maximlysenko>
|
|
// Brendan Early <https://github.com/mymindstorm>
|
|
// Doma <https://github.com/SevenOutman>
|
|
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
|
|
type WordArray = CryptoJS.lib.WordArray;
|
|
type CipherParams = CryptoJS.lib.CipherParams;
|
|
type X64Word = CryptoJS.x64.Word;
|
|
|
|
/**
|
|
* Encoding strategy.
|
|
*/
|
|
interface Encoder {
|
|
/**
|
|
* Converts a word array to a hex string.
|
|
*
|
|
* @param wordArray The word array.
|
|
*
|
|
* @return The hex string.
|
|
*
|
|
* @example
|
|
*
|
|
* var hexString = CryptoJS.enc.Hex.stringify(wordArray);
|
|
*/
|
|
stringify(wordArray: WordArray): string;
|
|
/**
|
|
* Converts a hex string to a word array.
|
|
*
|
|
* @param hexStr The hex string.
|
|
*
|
|
* @return The word array.
|
|
*
|
|
* @example
|
|
*
|
|
* var wordArray = CryptoJS.enc.Hex.parse(hexString);
|
|
*/
|
|
parse(str: string): WordArray;
|
|
}
|
|
|
|
/**
|
|
* Abstract buffered block algorithm template.
|
|
*
|
|
* The property blockSize must be implemented in a concrete subtype.
|
|
*/
|
|
interface BufferedBlockAlgorithm {
|
|
/**
|
|
* The number of blocks that should be kept unprocessed in the buffer. Default: 0
|
|
*/
|
|
_minBufferSize: number;
|
|
/**
|
|
* Resets this block algorithm's data buffer to its initial state.
|
|
*
|
|
* @example
|
|
*
|
|
* bufferedBlockAlgorithm.reset();
|
|
*/
|
|
reset(): void;
|
|
/**
|
|
* Adds new data to this block algorithm's buffer.
|
|
*
|
|
* @param data The data to append. Strings are converted to a WordArray using UTF-8.
|
|
*
|
|
* @example
|
|
*
|
|
* bufferedBlockAlgorithm._append('data');
|
|
* bufferedBlockAlgorithm._append(wordArray);
|
|
*/
|
|
_append(data: WordArray | string): void;
|
|
/**
|
|
* Processes available data blocks.
|
|
*
|
|
* This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
|
|
*
|
|
* @param doFlush Whether all blocks and partial blocks should be processed.
|
|
*
|
|
* @return The processed data.
|
|
*
|
|
* @example
|
|
*
|
|
* var processedData = bufferedBlockAlgorithm._process();
|
|
* var processedData = bufferedBlockAlgorithm._process(!!'flush');
|
|
*/
|
|
_process(doFlush?: boolean): WordArray;
|
|
/**
|
|
* Creates a copy of this object.
|
|
*
|
|
* @return The clone.
|
|
*
|
|
* @example
|
|
*
|
|
* var clone = bufferedBlockAlgorithm.clone();
|
|
*/
|
|
clone(): BufferedBlockAlgorithm;
|
|
}
|
|
|
|
/**
|
|
* Abstract hasher template.
|
|
*/
|
|
interface Hasher {
|
|
/**
|
|
* The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
|
|
*/
|
|
blockSize: number;
|
|
/**
|
|
* Resets this hasher to its initial state.
|
|
*
|
|
* @example
|
|
*
|
|
* hasher.reset();
|
|
*/
|
|
reset(): void;
|
|
/**
|
|
* Updates this hasher with a message.
|
|
*
|
|
* @param messageUpdate The message to append.
|
|
*
|
|
* @return This hasher.
|
|
*
|
|
* @example
|
|
*
|
|
* hasher.update('message');
|
|
* hasher.update(wordArray);
|
|
*/
|
|
update(messageUpdate: WordArray | string): this;
|
|
/**
|
|
* Finalizes the hash computation.
|
|
* Note that the finalize operation is effectively a destructive, read-once operation.
|
|
*
|
|
* @param messageUpdate (Optional) A final message update.
|
|
*
|
|
* @return The hash.
|
|
*
|
|
* @example
|
|
*
|
|
* var hash = hasher.finalize();
|
|
* var hash = hasher.finalize('message');
|
|
* var hash = hasher.finalize(wordArray);
|
|
*/
|
|
finalize(messaegUpdate?: WordArray | string): WordArray;
|
|
}
|
|
|
|
interface HasherStatic {
|
|
/**
|
|
* Initializes a newly created hasher.
|
|
*
|
|
* @param cfg (Optional) The configuration options to use for this hash computation.
|
|
*
|
|
* @example
|
|
*
|
|
* var hasher = CryptoJS.algo.SHA256.create();
|
|
*/
|
|
create(cfg?: object): Hasher;
|
|
}
|
|
|
|
interface HasherHelper {
|
|
(message: WordArray | string, cfg?: object): WordArray;
|
|
}
|
|
|
|
interface HmacHasherHelper {
|
|
(message: WordArray | string, key: WordArray | string): WordArray;
|
|
}
|
|
|
|
/**
|
|
* Abstract base cipher template.
|
|
*/
|
|
interface Cipher {
|
|
/**
|
|
* This cipher's key size. Default: 4 (128 bits)
|
|
*/
|
|
keySize: number;
|
|
/**
|
|
* This cipher's IV size. Default: 4 (128 bits)
|
|
*/
|
|
ivSize: number;
|
|
/**
|
|
* A constant representing encryption mode.
|
|
*/
|
|
readonly _ENC_XFORM_MODE: number;
|
|
/**
|
|
* A constant representing decryption mode.
|
|
*/
|
|
readonly _DEV_XFORM_MODE: number;
|
|
|
|
/**
|
|
* Resets this cipher to its initial state.
|
|
*
|
|
* @example
|
|
*
|
|
* cipher.reset();
|
|
*/
|
|
reset(): void;
|
|
|
|
/**
|
|
* Adds data to be encrypted or decrypted.
|
|
*
|
|
* @param dataUpdate The data to encrypt or decrypt.
|
|
*
|
|
* @return The data after processing.
|
|
*
|
|
* @example
|
|
*
|
|
* var encrypted = cipher.process('data');
|
|
* var encrypted = cipher.process(wordArray);
|
|
*/
|
|
process(dataUpdate: WordArray | string): WordArray;
|
|
|
|
/**
|
|
* Finalizes the encryption or decryption process.
|
|
* Note that the finalize operation is effectively a destructive, read-once operation.
|
|
*
|
|
* @param dataUpdate The final data to encrypt or decrypt.
|
|
*
|
|
* @return The data after final processing.
|
|
*
|
|
* @example
|
|
*
|
|
* var encrypted = cipher.finalize();
|
|
* var encrypted = cipher.finalize('data');
|
|
* var encrypted = cipher.finalize(wordArray);
|
|
*/
|
|
finalize(dataUpdate?: WordArray | string): WordArray;
|
|
}
|
|
|
|
interface CipherStatic {
|
|
/**
|
|
* Creates this cipher in encryption mode.
|
|
*
|
|
* @param key The key.
|
|
* @param cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return A cipher instance.
|
|
*
|
|
* @example
|
|
*
|
|
* var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray });
|
|
*/
|
|
createEncryptor(key: WordArray, cfg?: CipherOption): Cipher;
|
|
|
|
/**
|
|
* Creates this cipher in decryption mode.
|
|
*
|
|
* @param key The key.
|
|
* @param cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return A cipher instance.
|
|
*
|
|
* @example
|
|
*
|
|
* var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray });
|
|
*/
|
|
createDecryptor(key: WordArray, cfg?: CipherOption): Cipher;
|
|
|
|
/**
|
|
* Initializes a newly created cipher.
|
|
*
|
|
* @param xformMode Either the encryption or decryption transormation mode constant.
|
|
* @param key The key.
|
|
* @param cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @example
|
|
*
|
|
* var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray });
|
|
*/
|
|
create(xformMode: number, key: WordArray, cfg?: CipherOption): Cipher;
|
|
}
|
|
|
|
interface CipherHelper {
|
|
encrypt(
|
|
message: WordArray | string,
|
|
key: WordArray | string,
|
|
cfg?: CipherOption
|
|
): CipherParams;
|
|
decrypt(
|
|
ciphertext: CipherParams | string,
|
|
key: WordArray | string,
|
|
cfg?: CipherOption
|
|
): WordArray;
|
|
}
|
|
|
|
/**
|
|
* Configuration options.
|
|
*/
|
|
interface CipherOption {
|
|
/**
|
|
* The IV to use for this operation.
|
|
*/
|
|
iv?: WordArray | undefined;
|
|
format?: Format | undefined;
|
|
[key: string]: any;
|
|
}
|
|
|
|
interface Mode {
|
|
/**
|
|
* Processes the data block at offset.
|
|
*
|
|
* @param words The data words to operate on.
|
|
* @param offset The offset where the block starts.
|
|
*
|
|
* @example
|
|
*
|
|
* mode.processBlock(data.words, offset);
|
|
*/
|
|
processBlock(words: number[], offset: number): void;
|
|
}
|
|
|
|
interface ModeStatic {
|
|
/**
|
|
* Initializes a newly created mode.
|
|
*
|
|
* @param cipher A block cipher instance.
|
|
* @param iv The IV words.
|
|
*
|
|
* @example
|
|
*
|
|
* var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words);
|
|
*/
|
|
create(cipher: Cipher, iv: number[]): Mode;
|
|
}
|
|
|
|
/**
|
|
* Abstract base block cipher mode template.
|
|
*/
|
|
interface BlockCipherMode {
|
|
Encryptor: ModeStatic;
|
|
Decryptor: ModeStatic;
|
|
/**
|
|
* Creates this mode for encryption.
|
|
*
|
|
* @param cipher A block cipher instance.
|
|
* @param iv The IV words.
|
|
*
|
|
* @example
|
|
*
|
|
* var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words);
|
|
*/
|
|
createEncryptor(cipher: Cipher, iv: number[]): Mode;
|
|
|
|
/**
|
|
* Creates this mode for decryption.
|
|
*
|
|
* @param cipher A block cipher instance.
|
|
* @param iv The IV words.
|
|
*
|
|
* @example
|
|
*
|
|
* var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words);
|
|
*/
|
|
createDecryptor(cipher: Cipher, iv: number[]): Mode;
|
|
}
|
|
|
|
/**
|
|
* Abstract base block cipher mode template.
|
|
*/
|
|
interface BlockCipherMode {
|
|
/**
|
|
* Creates this mode for encryption.
|
|
*
|
|
* @param cipher A block cipher instance.
|
|
* @param iv The IV words.
|
|
*
|
|
* @example
|
|
*
|
|
* var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words);
|
|
*/
|
|
createEncryptor(cipher: Cipher): Mode;
|
|
}
|
|
|
|
/**
|
|
* Padding strategy.
|
|
*/
|
|
interface Padding {
|
|
/**
|
|
* Pads data using the algorithm defined in PKCS #5/7.
|
|
*
|
|
* @param data The data to pad.
|
|
* @param blockSize The multiple that the data should be padded to.
|
|
*
|
|
* @example
|
|
*
|
|
* CryptoJS.pad.Pkcs7.pad(wordArray, 4);
|
|
*/
|
|
pad(data: WordArray, blockSize: number): void;
|
|
|
|
/**
|
|
* Unpads data that had been padded using the algorithm defined in PKCS #5/7.
|
|
*
|
|
* @param data The data to unpad.
|
|
*
|
|
* @example
|
|
*
|
|
* CryptoJS.pad.Pkcs7.unpad(wordArray);
|
|
*/
|
|
unpad(data: WordArray): void;
|
|
}
|
|
|
|
/**
|
|
* Abstract base block cipher template.
|
|
*/
|
|
interface BlockCipher {
|
|
/**
|
|
* The number of 32-bit words this cipher operates on. Default: 4 (128 bits)
|
|
*/
|
|
blockSize: number;
|
|
}
|
|
|
|
/**
|
|
* Configuration options.
|
|
*/
|
|
interface BlockCipherOption {
|
|
/**
|
|
* The block mode to use. Default: CBC
|
|
*/
|
|
mode: Mode;
|
|
/**
|
|
* The padding strategy to use. Default: Pkcs7
|
|
*/
|
|
padding: Padding;
|
|
}
|
|
/**
|
|
* Formatting strategy.
|
|
*/
|
|
interface Format {
|
|
/**
|
|
* Converts a cipher params object to an OpenSSL-compatible string.
|
|
*
|
|
* @param cipherParams The cipher params object.
|
|
*
|
|
* @return The OpenSSL-compatible string.
|
|
*
|
|
* @example
|
|
*
|
|
* var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams);
|
|
*/
|
|
stringify(cipherParams: CipherParams): string;
|
|
|
|
/**
|
|
* Converts an OpenSSL-compatible string to a cipher params object.
|
|
*
|
|
* @param openSSLStr The OpenSSL-compatible string.
|
|
*
|
|
* @return The cipher params object.
|
|
*
|
|
* @example
|
|
*
|
|
* var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString);
|
|
*/
|
|
parse(str: string): CipherParams;
|
|
}
|
|
|
|
/**
|
|
* An array of 64-bit words.
|
|
*/
|
|
interface X64WordArray {
|
|
/**
|
|
* The array of CryptoJS.x64.Word objects.
|
|
*/
|
|
words: number[];
|
|
/**
|
|
* The number of significant bytes in this word array.
|
|
*/
|
|
sigBytes: number;
|
|
|
|
/**
|
|
* Converts this 64-bit word array to a 32-bit word array.
|
|
*
|
|
* @return This word array's data as a 32-bit word array.
|
|
*
|
|
* @example
|
|
*
|
|
* var x32WordArray = x64WordArray.toX32();
|
|
*/
|
|
toX32(): WordArray;
|
|
|
|
/**
|
|
* Creates a copy of this word array.
|
|
*
|
|
* @return The clone.
|
|
*
|
|
* @example
|
|
*
|
|
* var clone = x64WordArray.clone();
|
|
*/
|
|
clone(): X64WordArray;
|
|
}
|
|
|
|
/**
|
|
* Base object for prototypal inheritance.
|
|
*/
|
|
interface Base {
|
|
/**
|
|
* Creates a copy of this object.
|
|
*
|
|
* @return The clone.
|
|
*
|
|
* @example
|
|
*
|
|
* var clone = instance.clone();
|
|
*/
|
|
clone(): this;
|
|
}
|
|
|
|
/**
|
|
* Configuration options.
|
|
*/
|
|
interface KDFOption {
|
|
/**
|
|
* The key size in words to generate.
|
|
*/
|
|
keySize?: number | undefined;
|
|
/**
|
|
* The hasher to use.
|
|
*/
|
|
hasher?: HasherStatic | undefined;
|
|
/**
|
|
* The number of iterations to perform.
|
|
*/
|
|
iterations?: number | undefined;
|
|
}
|
|
|
|
declare namespace CryptoJS {
|
|
/**
|
|
* Library namespace.
|
|
*/
|
|
export namespace lib {
|
|
/**
|
|
* Base object for prototypal inheritance.
|
|
*/
|
|
const Base: {
|
|
/**
|
|
* Creates a new object that inherits from this object.
|
|
*
|
|
* @param overrides Properties to copy into the new object.
|
|
*
|
|
* @return The new object.
|
|
*
|
|
* @example
|
|
*
|
|
* var MyType = CryptoJS.lib.Base.extend({
|
|
* field: 'value',
|
|
*
|
|
* method: function () {
|
|
* }
|
|
* });
|
|
*/
|
|
extend(overrides: object): any;
|
|
|
|
/**
|
|
* Extends this object and runs the init method.
|
|
* Arguments to create() will be passed to init().
|
|
*
|
|
* @return The new object.
|
|
*
|
|
* @example
|
|
*
|
|
* var instance = MyType.create();
|
|
*/
|
|
create(...args: any[]): any;
|
|
|
|
/**
|
|
* Copies properties into this object.
|
|
*
|
|
* @param properties The properties to mix in.
|
|
*
|
|
* @example
|
|
*
|
|
* MyType.mixIn({
|
|
* field: 'value'
|
|
* });
|
|
*/
|
|
mixIn(properties: object): any;
|
|
};
|
|
|
|
/**
|
|
* An array of 32-bit words.
|
|
*/
|
|
interface WordArray {
|
|
/**
|
|
* The array of 32-bit words.
|
|
*/
|
|
words: number[];
|
|
/**
|
|
* The number of significant bytes in this word array.
|
|
*/
|
|
sigBytes: number;
|
|
/**
|
|
* Converts this word array to a string.
|
|
*
|
|
* @param encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
|
|
*
|
|
* @return The stringified word array.
|
|
*
|
|
* @example
|
|
*
|
|
* var string = wordArray + '';
|
|
* var string = wordArray.toString();
|
|
* var string = wordArray.toString(CryptoJS.enc.Utf8);
|
|
*/
|
|
toString(encoder?: Encoder): string;
|
|
|
|
/**
|
|
* Concatenates a word array to this word array.
|
|
*
|
|
* @param wordArray The word array to append.
|
|
*
|
|
* @return This word array.
|
|
*
|
|
* @example
|
|
*
|
|
* wordArray1.concat(wordArray2);
|
|
*/
|
|
concat(wordArray: WordArray): this;
|
|
|
|
/**
|
|
* Removes insignificant bits.
|
|
*
|
|
* @example
|
|
*
|
|
* wordArray.clamp();
|
|
*/
|
|
clamp(): void;
|
|
|
|
/**
|
|
* Creates a copy of this word array.
|
|
*
|
|
* @return The clone.
|
|
*
|
|
* @example
|
|
*
|
|
* var clone = wordArray.clone();
|
|
*/
|
|
clone(): WordArray;
|
|
}
|
|
const WordArray: {
|
|
/**
|
|
* Initializes a newly created word array.
|
|
*
|
|
* @param words (Optional) An array of 32-bit words.
|
|
* @param sigBytes (Optional) The number of significant bytes in the words.
|
|
*
|
|
* @example
|
|
*
|
|
* var wordArray = CryptoJS.lib.WordArray.create();
|
|
* var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
|
|
* var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
|
|
*/
|
|
create(words?: number[], sigBytes?: number): WordArray;
|
|
/**
|
|
* Creates a word array filled with random bytes.
|
|
*
|
|
* @param nBytes The number of random bytes to generate.
|
|
*
|
|
* @return The random word array.
|
|
*
|
|
* @example
|
|
*
|
|
* var wordArray = CryptoJS.lib.WordArray.random(16);
|
|
*/
|
|
random(nBytes: number): WordArray;
|
|
};
|
|
|
|
const BufferedBlockAlgorithm: any;
|
|
|
|
const Hasher: {
|
|
/**
|
|
* Creates a shortcut function to a hasher's object interface.
|
|
*
|
|
* @param hasher The hasher to create a helper for.
|
|
*
|
|
* @return The shortcut function.
|
|
*
|
|
* @example
|
|
*
|
|
* var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
|
|
*/
|
|
_createHelper(hasher: HasherStatic): HasherHelper;
|
|
/**
|
|
* Creates a shortcut function to the HMAC's object interface.
|
|
*
|
|
* @param hasher The hasher to use in this HMAC helper.
|
|
*
|
|
* @return The shortcut function.
|
|
*
|
|
* @example
|
|
*
|
|
* var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
|
|
*/
|
|
_createHmacHelper(hasher: HasherStatic): HmacHasherHelper;
|
|
};
|
|
|
|
const Cipher: {
|
|
/**
|
|
* Creates shortcut functions to a cipher's object interface.
|
|
*
|
|
* @param cipher The cipher to create a helper for.
|
|
*
|
|
* @return An object with encrypt and decrypt shortcut functions.
|
|
*
|
|
* @example
|
|
*
|
|
* var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES);
|
|
*/
|
|
_createHelper(cipher: Cipher): CipherHelper;
|
|
};
|
|
|
|
interface CipherOption {
|
|
/**
|
|
* The IV to use for this operation.
|
|
*/
|
|
iv?: WordArray | undefined;
|
|
format?: Format | undefined;
|
|
[key: string]: any;
|
|
}
|
|
|
|
/**
|
|
* A collection of cipher parameters.
|
|
*/
|
|
interface CipherParams {
|
|
/**
|
|
* The raw ciphertext.
|
|
*/
|
|
ciphertext: WordArray;
|
|
/**
|
|
* The key to this ciphertext.
|
|
*/
|
|
key: WordArray;
|
|
/**
|
|
* The IV used in the ciphering operation.
|
|
*/
|
|
iv: WordArray;
|
|
/**
|
|
* The salt used with a key derivation function.
|
|
*/
|
|
salt: WordArray;
|
|
/**
|
|
* The cipher algorithm.
|
|
*/
|
|
algorithm: CipherStatic;
|
|
/**
|
|
* The block mode used in the ciphering operation.
|
|
*/
|
|
mode: Mode;
|
|
/**
|
|
* The padding scheme used in the ciphering operation.
|
|
*/
|
|
padding: Padding;
|
|
/**
|
|
* The block size of the cipher.
|
|
*/
|
|
blockSize: number;
|
|
/**
|
|
* The default formatting strategy to convert this cipher params object to a string.
|
|
*/
|
|
formatter: Format;
|
|
/**
|
|
* Converts this cipher params object to a string.
|
|
*
|
|
* @param formatter (Optional) The formatting strategy to use.
|
|
*
|
|
* @return The stringified cipher params.
|
|
*
|
|
* @throws Error If neither the formatter nor the default formatter is set.
|
|
*
|
|
* @example
|
|
*
|
|
* var string = cipherParams + '';
|
|
* var string = cipherParams.toString();
|
|
* var string = cipherParams.toString(CryptoJS.format.OpenSSL);
|
|
*/
|
|
toString(formatter?: Format): string;
|
|
}
|
|
const CipherParams: {
|
|
/**
|
|
* Initializes a newly created cipher params object.
|
|
*
|
|
* @param cipherParams An object with any of the possible cipher parameters.
|
|
*
|
|
* @example
|
|
*
|
|
* var cipherParams = CryptoJS.lib.CipherParams.create({
|
|
* ciphertext: ciphertextWordArray,
|
|
* key: keyWordArray,
|
|
* iv: ivWordArray,
|
|
* salt: saltWordArray,
|
|
* algorithm: CryptoJS.algo.AES,
|
|
* mode: CryptoJS.mode.CBC,
|
|
* padding: CryptoJS.pad.PKCS7,
|
|
* blockSize: 4,
|
|
* formatter: CryptoJS.format.OpenSSL
|
|
* });
|
|
*/
|
|
create(cipherParams: Partial<CipherParams>): CipherParams;
|
|
};
|
|
|
|
/**
|
|
* Abstract base stream cipher template.
|
|
*/
|
|
interface StreamCipher extends Cipher {
|
|
/**
|
|
* The number of 32-bit words this cipher operates on. Default: 1 (32 bits)
|
|
*/
|
|
blockSize: number;
|
|
}
|
|
|
|
/**
|
|
* Abstract base block cipher mode template.
|
|
*/
|
|
const BlockCipherMode: any;
|
|
|
|
/**
|
|
* A cipher wrapper that returns ciphertext as a serializable cipher params object.
|
|
*/
|
|
const SerializableCipher: {
|
|
/**
|
|
* Encrypts a message.
|
|
*
|
|
* @param cipher The cipher algorithm to use.
|
|
* @param message The message to encrypt.
|
|
* @param key The key.
|
|
* @param cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return A cipher params object.
|
|
*
|
|
* @example
|
|
*
|
|
* var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key);
|
|
* var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv });
|
|
* var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL });
|
|
*/
|
|
encrypt(
|
|
cipher: CipherStatic,
|
|
message: WordArray | string,
|
|
key: WordArray,
|
|
cfg?: CipherOption
|
|
): CipherParams;
|
|
|
|
/**
|
|
* Decrypts serialized ciphertext.
|
|
*
|
|
* @param cipher The cipher algorithm to use.
|
|
* @param ciphertext The ciphertext to decrypt.
|
|
* @param key The key.
|
|
* @param cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return The plaintext.
|
|
*
|
|
* @example
|
|
*
|
|
* var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL });
|
|
* var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL });
|
|
*/
|
|
decrypt(
|
|
cipher: CipherStatic,
|
|
ciphertext: WordArray | string,
|
|
key: WordArray,
|
|
cfg?: CipherOption
|
|
): CipherParams;
|
|
|
|
/**
|
|
* Converts serialized ciphertext to CipherParams,
|
|
* else assumed CipherParams already and returns ciphertext unchanged.
|
|
*
|
|
* @param ciphertext The ciphertext.
|
|
* @param format The formatting strategy to use to parse serialized ciphertext.
|
|
*
|
|
* @return The unserialized ciphertext.
|
|
*
|
|
* @example
|
|
*
|
|
* var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format);
|
|
*/
|
|
_parse(ciphertext: CipherParams | string, format: Format): CipherParams;
|
|
};
|
|
|
|
/**
|
|
* A serializable cipher wrapper that derives the key from a password,
|
|
* and returns ciphertext as a serializable cipher params object.
|
|
*/
|
|
const PasswordBasedCipher: {
|
|
/**
|
|
* Encrypts a message using a password.
|
|
*
|
|
* @param cipher The cipher algorithm to use.
|
|
* @param message The message to encrypt.
|
|
* @param password The password.
|
|
* @param cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return A cipher params object.
|
|
*
|
|
* @example
|
|
*
|
|
* var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password');
|
|
* var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL });
|
|
*/
|
|
encrypt(
|
|
cipher: CipherStatic,
|
|
message: WordArray | string,
|
|
password: string,
|
|
cfg?: CipherOption
|
|
): CipherParams;
|
|
|
|
/**
|
|
* Decrypts serialized ciphertext using a password.
|
|
*
|
|
* @param cipher The cipher algorithm to use.
|
|
* @param ciphertext The ciphertext to decrypt.
|
|
* @param password The password.
|
|
* @param cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return The plaintext.
|
|
*
|
|
* @example
|
|
*
|
|
* var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL });
|
|
* var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL });
|
|
*/
|
|
decrypt(
|
|
cipher: CipherStatic,
|
|
ciphertext: CipherParams | string,
|
|
password: string,
|
|
cfg?: CipherOption
|
|
): WordArray;
|
|
};
|
|
}
|
|
/**
|
|
* Padding namespace.
|
|
*/
|
|
export namespace pad {
|
|
/**
|
|
* PKCS #5/7 padding strategy.
|
|
*/
|
|
const Pkcs7: Padding;
|
|
|
|
/**
|
|
* ANSI X.923 padding strategy.
|
|
*/
|
|
const AnsiX923: Padding;
|
|
|
|
/**
|
|
* ISO 10126 padding strategy.
|
|
*/
|
|
const Iso10126: Padding;
|
|
|
|
/**
|
|
* ISO/IEC 9797-1 Padding Method 2.
|
|
*/
|
|
const Iso97971: Padding;
|
|
|
|
/**
|
|
* Zero padding strategy.
|
|
*/
|
|
const ZeroPadding: Padding;
|
|
|
|
/**
|
|
* A noop padding strategy.
|
|
*/
|
|
const NoPadding: Padding;
|
|
}
|
|
|
|
/**
|
|
* Key derivation function namespace.
|
|
*/
|
|
export namespace kdf {
|
|
/**
|
|
* OpenSSL key derivation function.
|
|
*/
|
|
const OpenSSL: {
|
|
/**
|
|
* Derives a key and IV from a password.
|
|
*
|
|
* @param password The password to derive from.
|
|
* @param keySize The size in words of the key to generate.
|
|
* @param ivSize The size in words of the IV to generate.
|
|
* @param salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly.
|
|
*
|
|
* @return A cipher params object with the key, IV, and salt.
|
|
*
|
|
* @example
|
|
*
|
|
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
|
|
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
|
|
*/
|
|
execute(
|
|
password: string,
|
|
keySize: number,
|
|
ivSize: number,
|
|
salt?: WordArray | string
|
|
): CipherParams;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Mode namespace.
|
|
*/
|
|
export namespace mode {
|
|
/**
|
|
* Cipher Block Chaining mode.
|
|
*/
|
|
const CBC: BlockCipherMode;
|
|
|
|
/**
|
|
* Cipher Feedback block mode.
|
|
*/
|
|
const CFB: BlockCipherMode;
|
|
/**
|
|
* Counter block mode.
|
|
*/
|
|
const CTR: BlockCipherMode;
|
|
/**
|
|
* @preserve
|
|
* Counter block mode compatible with Dr Brian Gladman fileenc.c
|
|
* derived from CryptoJS.mode.CTR
|
|
* Jan Hruby jhruby.web@gmail.com
|
|
*/
|
|
const CTRGladman: BlockCipherMode;
|
|
/**
|
|
* Output Feedback block mode.
|
|
*/
|
|
const OFB: BlockCipherMode;
|
|
|
|
/**
|
|
* Electronic Codebook block mode.
|
|
*/
|
|
const ECB: BlockCipherMode;
|
|
}
|
|
|
|
/**
|
|
* Format namespace.
|
|
*/
|
|
export namespace format {
|
|
/**
|
|
* OpenSSL formatting strategy.
|
|
*/
|
|
const OpenSSL: Format;
|
|
const Hex: Format;
|
|
}
|
|
|
|
/**
|
|
* Encoder namespace.
|
|
*/
|
|
export namespace enc {
|
|
/**
|
|
* Hex encoding strategy.
|
|
*/
|
|
const Hex: Encoder;
|
|
/**
|
|
* Latin1 encoding strategy.
|
|
*/
|
|
const Latin1: Encoder;
|
|
/**
|
|
* UTF-8 encoding strategy.
|
|
*/
|
|
const Utf8: Encoder;
|
|
/**
|
|
* UTF-16 BE encoding strategy.
|
|
*/
|
|
const Utf16: Encoder;
|
|
const Utf16BE: Encoder;
|
|
|
|
/**
|
|
* UTF-16 LE encoding strategy.
|
|
*/
|
|
const Utf16LE: Encoder;
|
|
/**
|
|
* Base64 encoding strategy.
|
|
*/
|
|
const Base64: Encoder;
|
|
}
|
|
|
|
/**
|
|
* Algorithm namespace.
|
|
*/
|
|
export namespace algo {
|
|
/**
|
|
* MD5 hash algorithm.
|
|
*/
|
|
const MD5: HasherStatic;
|
|
|
|
/**
|
|
* SHA-1 hash algorithm.
|
|
*/
|
|
const SHA1: HasherStatic;
|
|
|
|
/**
|
|
* SHA-256 hash algorithm.
|
|
*/
|
|
const SHA256: HasherStatic;
|
|
/**
|
|
* SHA-224 hash algorithm.
|
|
*/
|
|
const SHA224: HasherStatic;
|
|
/**
|
|
* SHA-512 hash algorithm.
|
|
*/
|
|
const SHA512: HasherStatic;
|
|
|
|
/**
|
|
* SHA-384 hash algorithm.
|
|
*/
|
|
const SHA384: HasherStatic;
|
|
/**
|
|
* SHA-3 hash algorithm.
|
|
*/
|
|
const SHA3: HasherStatic;
|
|
/**
|
|
* RIPEMD160 hash algorithm.
|
|
*/
|
|
const RIPEMD160: HasherStatic;
|
|
/**
|
|
* HMAC algorithm.
|
|
*/
|
|
abstract class HMAC {
|
|
/**
|
|
* Initializes a newly created HMAC.
|
|
*
|
|
* @param hasher The hash algorithm to use.
|
|
* @param key The secret key.
|
|
*
|
|
* @example
|
|
*
|
|
* var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);
|
|
*/
|
|
static create(hasher: HasherStatic, key: WordArray | string): HMAC;
|
|
/**
|
|
* Resets this HMAC to its initial state.
|
|
*
|
|
* @example
|
|
*
|
|
* hmacHasher.reset();
|
|
*/
|
|
reset(): void;
|
|
|
|
/**
|
|
* Updates this HMAC with a message.
|
|
*
|
|
* @param messageUpdate The message to append.
|
|
*
|
|
* @return This HMAC instance.
|
|
*
|
|
* @example
|
|
*
|
|
* hmacHasher.update('message');
|
|
* hmacHasher.update(wordArray);
|
|
*/
|
|
update(messageUpdate: WordArray | string): this;
|
|
|
|
/**
|
|
* Finalizes the HMAC computation.
|
|
* Note that the finalize operation is effectively a destructive, read-once operation.
|
|
*
|
|
* @param messageUpdate (Optional) A final message update.
|
|
*
|
|
* @return The HMAC.
|
|
*
|
|
* @example
|
|
*
|
|
* var hmac = hmacHasher.finalize();
|
|
* var hmac = hmacHasher.finalize('message');
|
|
* var hmac = hmacHasher.finalize(wordArray);
|
|
*/
|
|
finalize(messageUpdate?: WordArray | string): WordArray;
|
|
}
|
|
/**
|
|
* Password-Based Key Derivation Function 2 algorithm.
|
|
*/
|
|
abstract class PBKDF2 {
|
|
/**
|
|
* Initializes a newly created key derivation function.
|
|
*
|
|
* @param cfg (Optional) The configuration options to use for the derivation.
|
|
*
|
|
* @example
|
|
*
|
|
* var kdf = CryptoJS.algo.PBKDF2.create();
|
|
* var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8 });
|
|
* var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8, iterations: 1000 });
|
|
*/
|
|
static create(cfg?: KDFOption): PBKDF2;
|
|
|
|
/**
|
|
* Computes the Password-Based Key Derivation Function 2.
|
|
*
|
|
* @param password The password.
|
|
* @param salt A salt.
|
|
*
|
|
* @return The derived key.
|
|
*
|
|
* @example
|
|
*
|
|
* var key = kdf.compute(password, salt);
|
|
*/
|
|
compute(password: WordArray | string, salt: WordArray): WordArray;
|
|
}
|
|
/**
|
|
* This key derivation function is meant to conform with EVP_BytesToKey.
|
|
* www.openssl.org/docs/crypto/EVP_BytesToKey.html
|
|
*/
|
|
abstract class EvpKDF {
|
|
/**
|
|
* Initializes a newly created key derivation function.
|
|
*
|
|
* @param cfg (Optional) The configuration options to use for the derivation.
|
|
*
|
|
* @example
|
|
*
|
|
* var kdf = CryptoJS.algo.EvpKDF.create();
|
|
* var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 });
|
|
* var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 });
|
|
*/
|
|
static create(cfg?: {
|
|
keySize: number;
|
|
hasher?: HasherStatic | undefined;
|
|
iterations: number;
|
|
}): EvpKDF;
|
|
|
|
/**
|
|
* Derives a key from a password.
|
|
*
|
|
* @param password The password.
|
|
* @param salt A salt.
|
|
*
|
|
* @return The derived key.
|
|
*
|
|
* @example
|
|
*
|
|
* var key = kdf.compute(password, salt);
|
|
*/
|
|
compute(password: WordArray | string, salt: WordArray): WordArray;
|
|
}
|
|
|
|
/**
|
|
* AES block cipher algorithm.
|
|
*/
|
|
const AES: CipherStatic;
|
|
|
|
/**
|
|
* DES block cipher algorithm.
|
|
*/
|
|
const DES: CipherStatic;
|
|
|
|
/**
|
|
* Triple-DES block cipher algorithm.
|
|
*/
|
|
const TripleDES: CipherStatic;
|
|
|
|
/**
|
|
* RC4 stream cipher algorithm.
|
|
*/
|
|
const RC4: CipherStatic;
|
|
|
|
/**
|
|
* Modified RC4 stream cipher algorithm.
|
|
*/
|
|
const RC4Drop: CipherStatic;
|
|
|
|
/**
|
|
* Rabbit stream cipher algorithm
|
|
*/
|
|
const Rabbit: CipherStatic;
|
|
|
|
/**
|
|
* Rabbit stream cipher algorithm.
|
|
*
|
|
* This is a legacy version that neglected to convert the key to little-endian.
|
|
* This error doesn't affect the cipher's security,
|
|
* but it does affect its compatibility with other implementations.
|
|
*/
|
|
const RabbitLegacy: CipherStatic;
|
|
}
|
|
|
|
/**
|
|
* x64 namespace.
|
|
*/
|
|
export namespace x64 {
|
|
/**
|
|
* A 64-bit word.
|
|
*/
|
|
interface Word {
|
|
/**
|
|
* Bitwise NOTs this word.
|
|
*
|
|
* @return A new x64-Word object after negating.
|
|
*
|
|
* @example
|
|
*
|
|
* var negated = x64Word.not();
|
|
*/
|
|
not(): X64Word;
|
|
/**
|
|
* Bitwise ANDs this word with the passed word.
|
|
*
|
|
* @param word The x64-Word to AND with this word.
|
|
*
|
|
* @return A new x64-Word object after ANDing.
|
|
*
|
|
* @example
|
|
*
|
|
* var anded = x64Word.and(anotherX64Word);
|
|
*/
|
|
and(word: X64Word): X64Word;
|
|
|
|
/**
|
|
* Bitwise ORs this word with the passed word.
|
|
*
|
|
* @param word The x64-Word to OR with this word.
|
|
*
|
|
* @return A new x64-Word object after ORing.
|
|
*
|
|
* @example
|
|
*
|
|
* var ored = x64Word.or(anotherX64Word);
|
|
*/
|
|
or(word: X64Word): X64Word;
|
|
|
|
/**
|
|
* Bitwise XORs this word with the passed word.
|
|
*
|
|
* @param word The x64-Word to XOR with this word.
|
|
*
|
|
* @return A new x64-Word object after XORing.
|
|
*
|
|
* @example
|
|
*
|
|
* var xored = x64Word.xor(anotherX64Word);
|
|
*/
|
|
xor(word: X64Word): X64Word;
|
|
/**
|
|
* Shifts this word n bits to the left.
|
|
*
|
|
* @param n The number of bits to shift.
|
|
*
|
|
* @return A new x64-Word object after shifting.
|
|
*
|
|
* @example
|
|
*
|
|
* var shifted = x64Word.shiftL(25);
|
|
*/
|
|
shiftL(n: number): X64Word;
|
|
/**
|
|
* Shifts this word n bits to the right.
|
|
*
|
|
* @param n The number of bits to shift.
|
|
*
|
|
* @return A new x64-Word object after shifting.
|
|
*
|
|
* @example
|
|
*
|
|
* var shifted = x64Word.shiftR(7);
|
|
*/
|
|
shiftR(n: number): X64Word;
|
|
/**
|
|
* Rotates this word n bits to the left.
|
|
*
|
|
* @param n The number of bits to rotate.
|
|
*
|
|
* @return A new x64-Word object after rotating.
|
|
*
|
|
* @example
|
|
*
|
|
* var rotated = x64Word.rotL(25);
|
|
*/
|
|
rotL(n: number): X64Word;
|
|
|
|
/**
|
|
* Rotates this word n bits to the right.
|
|
*
|
|
* @param n The number of bits to rotate.
|
|
*
|
|
* @return A new x64-Word object after rotating.
|
|
*
|
|
* @example
|
|
*
|
|
* var rotated = x64Word.rotR(7);
|
|
*/
|
|
rotR(n: number): X64Word;
|
|
/**
|
|
* Adds this word with the passed word.
|
|
*
|
|
* @param word The x64-Word to add with this word.
|
|
*
|
|
* @return A new x64-Word object after adding.
|
|
*
|
|
* @example
|
|
*
|
|
* var added = x64Word.add(anotherX64Word);
|
|
*/
|
|
add(word: X64Word): X64Word;
|
|
}
|
|
|
|
const Word: {
|
|
/**
|
|
* Initializes a newly created 64-bit word.
|
|
*
|
|
* @param high The high 32 bits.
|
|
* @param low The low 32 bits.
|
|
*
|
|
* @example
|
|
*
|
|
* var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607);
|
|
*/
|
|
create(high: number, low: number): X64Word;
|
|
};
|
|
|
|
/**
|
|
* Initializes a newly created word array.
|
|
*
|
|
* @param words (Optional) An array of CryptoJS.x64.Word objects.
|
|
* @param sigBytes (Optional) The number of significant bytes in the words.
|
|
*
|
|
* @example
|
|
*
|
|
* var wordArray = CryptoJS.x64.WordArray.create();
|
|
*
|
|
* var wordArray = CryptoJS.x64.WordArray.create([
|
|
* CryptoJS.x64.Word.create(0x00010203, 0x04050607),
|
|
* CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)
|
|
* ]);
|
|
*
|
|
* var wordArray = CryptoJS.x64.WordArray.create([
|
|
* CryptoJS.x64.Word.create(0x00010203, 0x04050607),
|
|
* CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)
|
|
* ], 10);
|
|
*/
|
|
const WordArray: {
|
|
create(words?: X64WordArray[], sigBytes?: number): X64WordArray;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Shortcut function to the hasher's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
*
|
|
* @return The hash.
|
|
*
|
|
* @example
|
|
*
|
|
* var hash = CryptoJS.MD5('message');
|
|
* var hash = CryptoJS.MD5(wordArray);
|
|
*/
|
|
export const MD5: HasherHelper;
|
|
/**
|
|
* Shortcut function to the HMAC's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
* @param key The secret key.
|
|
*
|
|
* @return The HMA'C.
|
|
*
|
|
* @example
|
|
*
|
|
* var hmac = CryptoJS.HmacMD5(message, key);
|
|
*/
|
|
export const HmacMD5: HmacHasherHelper;
|
|
/**
|
|
* Shortcut function to the hasher's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
*
|
|
* @return The hash.
|
|
*
|
|
* @example
|
|
*
|
|
* var hash = CryptoJS.SHA1('message');
|
|
* var hash = CryptoJS.SHA1(wordArray);
|
|
*/
|
|
export const SHA1: HasherHelper;
|
|
/**
|
|
* Shortcut function to the HMAC's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
* @param key The secret key.
|
|
*
|
|
* @return The HMAC.
|
|
*
|
|
* @example
|
|
*
|
|
* var hmac = CryptoJS.HmacSHA1(message, key);
|
|
*/
|
|
export const HmacSHA1: HmacHasherHelper;
|
|
|
|
/**
|
|
* Shortcut function to the hasher's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
*
|
|
* @return The hash.
|
|
*
|
|
* @example
|
|
*
|
|
* var hash = CryptoJS.SHA256('message');
|
|
* var hash = CryptoJS.SHA256(wordArray);
|
|
*/
|
|
export const SHA256: HasherHelper;
|
|
/**
|
|
* Shortcut function to the HMAC's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
* @param key The secret key.
|
|
*
|
|
* @return The HMAC.
|
|
*
|
|
* @example
|
|
*
|
|
* var hmac = CryptoJS.HmacSHA256(message, key);
|
|
*/
|
|
export const HmacSHA256: HmacHasherHelper;
|
|
/**
|
|
* Shortcut function to the hasher's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
*
|
|
* @return The hash.
|
|
*
|
|
* @example
|
|
*
|
|
* var hash = CryptoJS.SHA224('message');
|
|
* var hash = CryptoJS.SHA224(wordArray);
|
|
*/
|
|
export const SHA224: HasherHelper;
|
|
/**
|
|
* Shortcut function to the HMAC's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
* @param key The secret key.
|
|
*
|
|
* @return The HMAC.
|
|
*
|
|
* @example
|
|
*
|
|
* var hmac = CryptoJS.HmacSHA224(message, key);
|
|
*/
|
|
export const HmacSHA224: HmacHasherHelper;
|
|
/**
|
|
* Shortcut function to the hasher's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
*
|
|
* @return The hash.
|
|
*
|
|
* @example
|
|
*
|
|
* var hash = CryptoJS.SHA512('message');
|
|
* var hash = CryptoJS.SHA512(wordArray);
|
|
*/
|
|
export const SHA512: HasherHelper;
|
|
/**
|
|
* Shortcut function to the HMAC's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
* @param key The secret key.
|
|
*
|
|
* @return The HMAC.
|
|
*
|
|
* @example
|
|
*
|
|
* var hmac = CryptoJS.HmacSHA512(message, key);
|
|
*/
|
|
export const HmacSHA512: HmacHasherHelper;
|
|
/**
|
|
* Shortcut function to the hasher's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
*
|
|
* @return The hash.
|
|
*
|
|
* @example
|
|
*
|
|
* var hash = CryptoJS.SHA384('message');
|
|
* var hash = CryptoJS.SHA384(wordArray);
|
|
*/
|
|
export const SHA384: HasherHelper;
|
|
/**
|
|
* Shortcut function to the HMAC's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
* @param key The secret key.
|
|
*
|
|
* @return The HMAC.
|
|
*
|
|
* @example
|
|
*
|
|
* var hmac = CryptoJS.HmacSHA384(message, key);
|
|
*/
|
|
export const HmacSHA384: HmacHasherHelper;
|
|
|
|
/**
|
|
* Shortcut function to the hasher's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
*
|
|
* @return The hash.
|
|
*
|
|
* @example
|
|
*
|
|
* var hash = CryptoJS.SHA3('message');
|
|
* var hash = CryptoJS.SHA3(wordArray);
|
|
*/
|
|
export const SHA3: HasherHelper;
|
|
/**
|
|
* Shortcut function to the HMAC's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
* @param key The secret key.
|
|
*
|
|
* @return The HMAC.
|
|
*
|
|
* @example
|
|
*
|
|
* var hmac = CryptoJS.HmacSHA3(message, key);
|
|
*/
|
|
export const HmacSHA3: HmacHasherHelper;
|
|
|
|
/**
|
|
* Shortcut function to the hasher's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
*
|
|
* @return The hash.
|
|
*
|
|
* @example
|
|
*
|
|
* var hash = CryptoJS.RIPEMD160('message');
|
|
* var hash = CryptoJS.RIPEMD160(wordArray);
|
|
*/
|
|
export const RIPEMD160: HasherHelper;
|
|
/**
|
|
* Shortcut function to the HMAC's object interface.
|
|
*
|
|
* @param message The message to hash.
|
|
* @param key The secret key.
|
|
*
|
|
* @return The HMAC.
|
|
*
|
|
* @example
|
|
*
|
|
* var hmac = CryptoJS.HmacRIPEMD160(message, key);
|
|
*/
|
|
export const HmacRIPEMD160: HmacHasherHelper;
|
|
/**
|
|
* Computes the Password-Based Key Derivation Function 2.
|
|
*
|
|
* @param password The password.
|
|
* @param salt A salt.
|
|
* @param cfg (Optional) The configuration options to use for this computation.
|
|
*
|
|
* @return The derived key.
|
|
*
|
|
* @example
|
|
*
|
|
* var key = CryptoJS.PBKDF2(password, salt);
|
|
* var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 });
|
|
* var key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 });
|
|
*/
|
|
export function PBKDF2(
|
|
password: WordArray | string,
|
|
salt: WordArray | string,
|
|
cfg?: KDFOption
|
|
): WordArray;
|
|
|
|
/**
|
|
* Shortcut functions to the cipher's object interface.
|
|
*
|
|
* @example
|
|
*
|
|
* var ciphertext = CryptoJS.AES.encrypt(message, key, cfg);
|
|
* var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg);
|
|
*/
|
|
export const AES: CipherHelper;
|
|
|
|
/**
|
|
* Shortcut functions to the cipher's object interface.
|
|
*
|
|
* @example
|
|
*
|
|
* var ciphertext = CryptoJS.DES.encrypt(message, key, cfg);
|
|
* var plaintext = CryptoJS.DES.decrypt(ciphertext, key, cfg);
|
|
*/
|
|
export const DES: CipherHelper;
|
|
|
|
/**
|
|
* Shortcut functions to the cipher's object interface.
|
|
*
|
|
* @example
|
|
*
|
|
* var ciphertext = CryptoJS.TripleDES.encrypt(message, key, cfg);
|
|
* var plaintext = CryptoJS.TripleDES.decrypt(ciphertext, key, cfg);
|
|
*/
|
|
export const TripleDES: CipherHelper;
|
|
|
|
/**
|
|
* Shortcut functions to the cipher's object interface.
|
|
*
|
|
* @example
|
|
*
|
|
* var ciphertext = CryptoJS.RC4.encrypt(message, key, cfg);
|
|
* var plaintext = CryptoJS.RC4.decrypt(ciphertext, key, cfg);
|
|
*/
|
|
export const RC4: CipherHelper;
|
|
|
|
/**
|
|
* Shortcut functions to the cipher's object interface.
|
|
*
|
|
* @example
|
|
*
|
|
* var ciphertext = CryptoJS.RC4Drop.encrypt(message, key, cfg);
|
|
* var plaintext = CryptoJS.RC4Drop.decrypt(ciphertext, key, cfg);
|
|
*/
|
|
export const RC4Drop: CipherHelper;
|
|
|
|
/**
|
|
* Shortcut functions to the cipher's object interface.
|
|
*
|
|
* @example
|
|
*
|
|
* var ciphertext = CryptoJS.Rabbit.encrypt(message, key, cfg);
|
|
* var plaintext = CryptoJS.Rabbit.decrypt(ciphertext, key, cfg);
|
|
*/
|
|
export const Rabbit: CipherHelper;
|
|
|
|
/**
|
|
* Shortcut functions to the cipher's object interface.
|
|
*
|
|
* @example
|
|
*
|
|
* var ciphertext = CryptoJS.RabbitLegacy.encrypt(message, key, cfg);
|
|
* var plaintext = CryptoJS.RabbitLegacy.decrypt(ciphertext, key, cfg);
|
|
*/
|
|
export const RabbitLegacy: CipherHelper;
|
|
|
|
/**
|
|
* Derives a key from a password.
|
|
*
|
|
* @param password The password.
|
|
* @param salt A salt.
|
|
* @param cfg (Optional) The configuration options to use for this computation.
|
|
*
|
|
* @return The derived key.
|
|
*
|
|
* @example
|
|
*
|
|
* var key = CryptoJS.EvpKDF(password, salt);
|
|
* var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 });
|
|
* var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 });
|
|
*/
|
|
export function EvpKDF(
|
|
password: WordArray | string,
|
|
salt: WordArray | string,
|
|
cfg?: {
|
|
keySize: number;
|
|
hasher?: HasherStatic | undefined;
|
|
iterations: number;
|
|
}
|
|
): WordArray;
|
|
}
|
|
|
|
export = CryptoJS;
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\public-api.ts
|
|
|
|
/*
|
|
* Public API Surface of x-framework-services
|
|
*/
|
|
|
|
//
|
|
//#region Export Services ...
|
|
export * from './lib/x-dialog.service';
|
|
export * from './lib/x-manager.service';
|
|
export * from './lib/x-storage.service';
|
|
export * from './lib/x-security.service';
|
|
export * from './lib/x-settings.service';
|
|
export * from './lib/x-identifier.service';
|
|
export * from './lib/x-geolocation.service';
|
|
export * from './lib/x-localization.service';
|
|
export * from './lib/x-notification.service';
|
|
export * from './lib/x-task-manager.service';
|
|
export * from './lib/x-theme-manager.service';
|
|
export * from './lib/x-secure-storage.service';
|
|
export * from './lib/x-http-interceptor.service';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Export Directives ...
|
|
export * from './lib/directives/x-swipable.directive';
|
|
export * from './lib/directives/x-date-presenter.directive';
|
|
export * from './lib/directives/x-currency-formatter.directive';
|
|
export * from './lib/directives/x-from-input-formatter.directive';
|
|
export * from './lib/directives/x-locale-input-formatter.directive';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Export Pipes ...
|
|
export * from './lib/pipes/x-translate.pipe';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Tokens ...
|
|
export * from './lib/tokens/x-injectable-tokens';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Export Config ...
|
|
export * from './lib/config/x-framework-services.config';
|
|
//#endregion
|
|
|
|
//
|
|
//#region Export Modules ...
|
|
export * from './lib/modules/x-directives.module';
|
|
export * from './lib/x-framework-services.module';
|
|
//#endregion
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\test.ts
|
|
|
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
|
|
|
import 'zone.js';
|
|
import 'zone.js/testing';
|
|
import { getTestBed } from '@angular/core/testing';
|
|
import {
|
|
BrowserDynamicTestingModule,
|
|
platformBrowserDynamicTesting
|
|
} from '@angular/platform-browser-dynamic/testing';
|
|
|
|
declare const require: {
|
|
context(path: string, deep?: boolean, filter?: RegExp): {
|
|
keys(): string[];
|
|
<T>(id: string): T;
|
|
};
|
|
};
|
|
|
|
// First, initialize the Angular testing environment.
|
|
getTestBed().initTestEnvironment(
|
|
BrowserDynamicTestingModule,
|
|
platformBrowserDynamicTesting()
|
|
);
|
|
// Then we find all the tests.
|
|
const context = require.context('./', true, /\.spec\.ts$/);
|
|
// And load the modules.
|
|
context.keys().map(context);
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-dialog.service.ts
|
|
|
|
import {
|
|
NavController,
|
|
AlertController,
|
|
ModalController,
|
|
PickerController,
|
|
PopoverController,
|
|
LoadingController,
|
|
ActionSheetController,
|
|
} from '@ionic/angular';
|
|
import {
|
|
toArray,
|
|
hasChild,
|
|
XActionType,
|
|
XModalInput,
|
|
XBaseService,
|
|
XResourceIDs,
|
|
XModalButton,
|
|
XPickerColumn,
|
|
XAlertOptions,
|
|
XModalOptions,
|
|
XPickerOptions,
|
|
XPopoverOptions,
|
|
XLoadingOptions,
|
|
XModalButtonRole,
|
|
XActionModalOptions,
|
|
XPickerColumnOption,
|
|
XModalButtonRoleIdentifier,
|
|
} from 'x-framework-core';
|
|
import { Observable, of } from 'rxjs';
|
|
import { Injectable, Inject } from '@angular/core';
|
|
import { MatDialog } from '@angular/material/dialog';
|
|
import { XLocalizationService } from './x-localization.service';
|
|
import { XNotificationService } from './x-notification.service';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XDialogService extends XBaseService {
|
|
//
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG) config: XFrameworkServicesConfig,
|
|
public matDialogService: MatDialog,
|
|
public modalController: ModalController,
|
|
public alertController: AlertController,
|
|
public pickerController: PickerController,
|
|
public navigationController: NavController,
|
|
public popoverController: PopoverController,
|
|
public loadingController: LoadingController,
|
|
private notificationService: XNotificationService,
|
|
private localizationService: XLocalizationService,
|
|
public actionSheetController: ActionSheetController
|
|
) {
|
|
super(config);
|
|
}
|
|
|
|
//
|
|
//#region Service Actions ...
|
|
nativeAlert(message?: string | XResourceIDs): Observable<void> {
|
|
//
|
|
message = !message ? XResourceIDs.are_you_sure : message;
|
|
|
|
//
|
|
const mMessage = this.localizationService.getValue(message);
|
|
const confirmation = window.alert(mMessage);
|
|
|
|
//
|
|
return of(confirmation);
|
|
}
|
|
|
|
nativeConfirm(message?: string | XResourceIDs): Observable<boolean> {
|
|
//
|
|
message = !message ? XResourceIDs.are_you_sure : message;
|
|
|
|
//
|
|
const mMessage = this.localizationService.getValue(message);
|
|
const confirmation = window.confirm(mMessage);
|
|
|
|
//
|
|
return of(confirmation);
|
|
}
|
|
|
|
async presentActionModal(props: XActionModalOptions) {
|
|
//
|
|
const options = await this.toActionSheetOptions(props);
|
|
const actionModal = await this.actionSheetController.create(options);
|
|
|
|
//
|
|
if (props.playSound) {
|
|
this.notificationService.playSound(props.type || XActionType.System);
|
|
}
|
|
|
|
//
|
|
await actionModal.present();
|
|
return actionModal;
|
|
}
|
|
|
|
async presentModal(props: XModalOptions) {
|
|
//
|
|
if (props.fullScreen) {
|
|
//
|
|
const mFullscreen = 'fullscreen';
|
|
if (hasChild(props.cssClass)) {
|
|
props.cssClass = [...toArray(props.cssClass), mFullscreen];
|
|
} else {
|
|
props.cssClass = [mFullscreen];
|
|
}
|
|
} else if (props.autoHeight) {
|
|
//
|
|
const mAutoHeight = 'autoHeight';
|
|
if (hasChild(props.cssClass)) {
|
|
props.cssClass = [...toArray(props.cssClass), mAutoHeight];
|
|
} else {
|
|
props.cssClass = [mAutoHeight];
|
|
}
|
|
}
|
|
|
|
//
|
|
const modal = await this.modalController.create(props);
|
|
await modal.present();
|
|
return modal;
|
|
}
|
|
|
|
async presentPopover(props: XPopoverOptions) {
|
|
//
|
|
const popover = await this.popoverController.create(props);
|
|
await popover.present();
|
|
return popover;
|
|
}
|
|
|
|
async presentLoading(props: XLoadingOptions) {
|
|
//
|
|
const loading = await this.loadingController.create(props);
|
|
await loading.present();
|
|
return loading;
|
|
}
|
|
|
|
async presentAlert(props: XAlertOptions) {
|
|
//
|
|
const options = await this.prepareAlertOptions(props);
|
|
const alert = await this.alertController.create(options);
|
|
|
|
//
|
|
await alert.present();
|
|
return alert;
|
|
}
|
|
|
|
async presentPicker(props: XPickerOptions) {
|
|
//
|
|
const options = await this.preparePickerOptions(props);
|
|
const picker = await this.pickerController.create(options);
|
|
|
|
//
|
|
await picker.present();
|
|
return picker;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Commonly Used dialogs ...
|
|
async presentAreYouSureOkCancleDialog(
|
|
okHandler: () => void,
|
|
okRole?: XModalButtonRoleIdentifier,
|
|
cancelHandler?: () => void,
|
|
cancelRole?: XModalButtonRoleIdentifier
|
|
) {
|
|
await this.presentActionModal({
|
|
header: XResourceIDs.are_you_sure,
|
|
buttons: [],
|
|
keyboardClose: true,
|
|
backdropDismiss: true,
|
|
hasOk: true,
|
|
okRole,
|
|
okHandler,
|
|
hasCancel: true,
|
|
cancelRole,
|
|
cancelHandler,
|
|
});
|
|
}
|
|
|
|
async presentAreYouSureYesNoDialog(
|
|
yesHandler: () => void,
|
|
yesRole?: XModalButtonRoleIdentifier,
|
|
noHandler?: () => void,
|
|
noRole?: XModalButtonRoleIdentifier
|
|
) {
|
|
await this.presentActionModal({
|
|
header: XResourceIDs.are_you_sure,
|
|
buttons: [],
|
|
keyboardClose: true,
|
|
backdropDismiss: true,
|
|
hasNo: true,
|
|
noRole,
|
|
noHandler,
|
|
hasYes: true,
|
|
yesRole,
|
|
yesHandler,
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//
|
|
//#region Button Preparer ...
|
|
getButton(
|
|
text?: XResourceIDs | string,
|
|
icon?: string,
|
|
role?: XModalButtonRoleIdentifier,
|
|
handler?: () => boolean | void | Promise<boolean>
|
|
) {
|
|
//
|
|
if (!role) {
|
|
role = XModalButtonRole.Selected;
|
|
}
|
|
|
|
//
|
|
const mText = this.getPreparedMessage(text);
|
|
return {
|
|
text: mText,
|
|
icon,
|
|
role,
|
|
handler,
|
|
};
|
|
}
|
|
|
|
getYesButton(
|
|
role?: XModalButtonRoleIdentifier,
|
|
handler?: () => boolean | void | Promise<boolean>
|
|
) {
|
|
//
|
|
if (!role) {
|
|
role = XModalButtonRole.Selected;
|
|
}
|
|
|
|
//
|
|
const mText = this.getPreparedMessage(XResourceIDs.yes);
|
|
const mIcon = 'checkmark';
|
|
|
|
return {
|
|
text: mText,
|
|
icon: mIcon,
|
|
role,
|
|
handler,
|
|
};
|
|
}
|
|
|
|
getNoButton(
|
|
role?: XModalButtonRoleIdentifier,
|
|
handler?: () => boolean | void | Promise<boolean>
|
|
) {
|
|
//
|
|
if (!role) {
|
|
role = XModalButtonRole.Selected;
|
|
}
|
|
|
|
//
|
|
const mText = this.getPreparedMessage(XResourceIDs.no);
|
|
const mIcon = 'close';
|
|
|
|
return {
|
|
text: mText,
|
|
icon: mIcon,
|
|
role,
|
|
handler,
|
|
};
|
|
}
|
|
|
|
getOkButton(
|
|
role?: XModalButtonRoleIdentifier,
|
|
handler?: () => boolean | void | Promise<boolean>
|
|
) {
|
|
//
|
|
if (!role) {
|
|
role = XModalButtonRole.Selected;
|
|
}
|
|
|
|
//
|
|
const mText = this.getPreparedMessage(XResourceIDs.ok);
|
|
const mIcon = 'checkmark';
|
|
|
|
return {
|
|
text: mText,
|
|
icon: mIcon,
|
|
role,
|
|
handler,
|
|
};
|
|
}
|
|
|
|
getCancelButton(
|
|
role?: XModalButtonRoleIdentifier,
|
|
handler?: () => boolean | void | Promise<boolean>
|
|
) {
|
|
//
|
|
if (!role) {
|
|
role = XModalButtonRole.Selected;
|
|
}
|
|
|
|
//
|
|
const mText = this.getPreparedMessage(XResourceIDs.cancel);
|
|
const mIcon = 'close';
|
|
|
|
return {
|
|
text: mText,
|
|
icon: mIcon,
|
|
role,
|
|
handler,
|
|
};
|
|
}
|
|
|
|
getAcceptButton(
|
|
role?: XModalButtonRoleIdentifier,
|
|
handler?: () => boolean | void | Promise<boolean>
|
|
) {
|
|
//
|
|
if (!role) {
|
|
role = XModalButtonRole.Selected;
|
|
}
|
|
|
|
//
|
|
const mText = this.getPreparedMessage(XResourceIDs.accept);
|
|
const mIcon = 'checkmark';
|
|
|
|
return {
|
|
text: mText,
|
|
icon: mIcon,
|
|
role,
|
|
handler,
|
|
};
|
|
}
|
|
|
|
getRetryButton(
|
|
role?: XModalButtonRoleIdentifier,
|
|
handler?: () => boolean | void | Promise<boolean>
|
|
) {
|
|
//
|
|
if (!role) {
|
|
role = XModalButtonRole.Selected;
|
|
}
|
|
|
|
//
|
|
const mText = this.getPreparedMessage(XResourceIDs.retry);
|
|
const mIcon = 'refresh';
|
|
|
|
return {
|
|
text: mText,
|
|
icon: mIcon,
|
|
role,
|
|
handler,
|
|
};
|
|
}
|
|
|
|
getDismissButton(
|
|
role?: XModalButtonRoleIdentifier,
|
|
handler?: () => boolean | void | Promise<boolean>
|
|
) {
|
|
//
|
|
if (!role) {
|
|
role = XModalButtonRole.Destructive;
|
|
}
|
|
|
|
//
|
|
const mText = this.getPreparedMessage(XResourceIDs.dismiss);
|
|
const mIcon = 'remove-circle-outline';
|
|
|
|
return {
|
|
text: mText,
|
|
icon: mIcon,
|
|
role,
|
|
handler,
|
|
};
|
|
}
|
|
//#endregion
|
|
|
|
private prepareModalButton(button?: XModalButton) {
|
|
//
|
|
const alertButton = {
|
|
...button,
|
|
text: button.text ? this.getPreparedMessage(button.text) : '',
|
|
};
|
|
|
|
//
|
|
return alertButton;
|
|
}
|
|
|
|
private async prepareModalButtons(buttons?: XModalButton[]) {
|
|
//
|
|
if (!hasChild(buttons)) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
return buttons.map((b) => this.prepareModalButton(b));
|
|
}
|
|
|
|
private prepareModalInput(input?: XModalInput) {
|
|
//
|
|
const alertInput = {
|
|
...input,
|
|
label: input.label ? this.getPreparedMessage(input.label) : '',
|
|
placeholder: input.placeholder
|
|
? this.getPreparedMessage(input.placeholder)
|
|
: '',
|
|
};
|
|
|
|
//
|
|
return alertInput;
|
|
}
|
|
|
|
private async prepareModalInputs(inputs?: XModalInput[]) {
|
|
//
|
|
if (!hasChild(inputs)) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
return inputs.map((i) => this.prepareModalInput(i));
|
|
}
|
|
|
|
private async prepareAlertOptions(options?: XAlertOptions) {
|
|
//
|
|
const alertOptions = {
|
|
...options,
|
|
header: options.header ? this.getPreparedMessage(options.header) : '',
|
|
subHeader: options.subHeader
|
|
? this.getPreparedMessage(options.subHeader)
|
|
: '',
|
|
message: options.message ? this.getPreparedMessage(options.message) : '',
|
|
inputs: hasChild(options.inputs)
|
|
? await this.prepareModalInputs(options.inputs)
|
|
: [],
|
|
buttons: hasChild(options.buttons)
|
|
? await this.prepareModalButtons(options.buttons)
|
|
: [],
|
|
};
|
|
|
|
//
|
|
return alertOptions;
|
|
}
|
|
|
|
private preparePickerColumnOption(columnOption?: XPickerColumnOption) {
|
|
//
|
|
const pickerColumnOption = {
|
|
...columnOption,
|
|
text: this.getPreparedMessage(columnOption.text),
|
|
};
|
|
|
|
//
|
|
return pickerColumnOption;
|
|
}
|
|
|
|
private async preparePickerColumnOptions(
|
|
columnOptions?: XPickerColumnOption[]
|
|
) {
|
|
//
|
|
if (!hasChild(columnOptions)) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
return columnOptions.map((co) => this.preparePickerColumnOption(co));
|
|
}
|
|
|
|
private async preparePickerColumn(column?: XPickerColumn) {
|
|
//
|
|
const pickerColumn = {
|
|
...column,
|
|
options: await this.preparePickerColumnOptions(column.options),
|
|
};
|
|
|
|
//
|
|
return pickerColumn;
|
|
}
|
|
|
|
private async preparePickerColumns(columns: XPickerColumn[]) {
|
|
//
|
|
if (!hasChild(columns)) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
return columns.map((c) => this.preparePickerColumn(c));
|
|
}
|
|
|
|
private async preparePickerOptions(options?: XPickerOptions) {
|
|
//
|
|
const pickerOptions = {
|
|
...options,
|
|
buttons: (await this.prepareModalButtons(options.buttons)) || [],
|
|
columns:
|
|
(await Promise.all(await this.preparePickerColumns(options.columns))) ||
|
|
[],
|
|
};
|
|
|
|
//
|
|
return pickerOptions;
|
|
}
|
|
|
|
private async toActionSheetOptions(options?: XActionModalOptions) {
|
|
//
|
|
let buttons: any[] = [];
|
|
|
|
//
|
|
const optButtons = (await this.prepareModalButtons(options.buttons)) || [];
|
|
buttons = [...buttons, ...optButtons];
|
|
|
|
//
|
|
//#region Handle Preserved Buttons ...
|
|
if (options.hasRetry) {
|
|
buttons.push(
|
|
this.getRetryButton(options.retryRole, options.retryHandler)
|
|
);
|
|
}
|
|
|
|
//
|
|
if (options.hasAccept) {
|
|
buttons.push(
|
|
this.getAcceptButton(options.acceptRole, options.acceptHandler)
|
|
);
|
|
}
|
|
|
|
//
|
|
if (options.hasOk) {
|
|
buttons.push(this.getOkButton(options.okRole, options.okHandler));
|
|
}
|
|
|
|
//
|
|
if (options.hasCancel) {
|
|
buttons.push(
|
|
this.getCancelButton(options.cancelRole, options.cancelHandler)
|
|
);
|
|
}
|
|
|
|
//
|
|
if (options.hasYes) {
|
|
buttons.push(this.getYesButton(options.yesRole, options.yesHandler));
|
|
}
|
|
|
|
//
|
|
if (options.hasNo) {
|
|
buttons.push(this.getNoButton(options.noRole, options.noHandler));
|
|
}
|
|
|
|
//
|
|
if (options.hasDismiss) {
|
|
buttons.push(
|
|
this.getDismissButton(options.dismissRole, options.dismissHandler)
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
const actionModalOptions = {
|
|
...options,
|
|
header: options.header ? this.getPreparedMessage(options.header) : '',
|
|
subHeader: options.subHeader
|
|
? this.getPreparedMessage(options.subHeader)
|
|
: '',
|
|
backdropDismiss: options.backdropDismiss || true,
|
|
buttons,
|
|
};
|
|
|
|
//
|
|
return actionModalOptions;
|
|
}
|
|
|
|
private getPreparedMessage(key: string | number) {
|
|
return this.localizationService.isExistsId(key)
|
|
? this.localizationService.getValue(key)
|
|
: key
|
|
? key.toString()
|
|
: '';
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-framework-services.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { IonicModule } from '@ionic/angular';
|
|
import { CommonModule } from '@angular/common';
|
|
import { RouterModule } from '@angular/router';
|
|
import { XDialogService } from './x-dialog.service';
|
|
import { XHistoryService } from './x-history.service';
|
|
import { XManagerService } from './x-manager.service';
|
|
import { XStorageService } from './x-storage.service';
|
|
import { HttpClientModule } from '@angular/common/http';
|
|
import { XSecurityService } from './x-security.service';
|
|
import { XSettingsService } from './x-settings.service';
|
|
import { XGeolocationService } from './x-geolocation.service';
|
|
import { XTaskManagerService } from './x-task-manager.service';
|
|
import { XLocalizationService } from './x-localization.service';
|
|
import { XNotificationService } from './x-notification.service';
|
|
import { XThemeManagerService } from './x-theme-manager.service';
|
|
import { XDirectivesModule } from './modules/x-directives.module';
|
|
import { XSecureStorageService } from './x-secure-storage.service';
|
|
|
|
@NgModule({
|
|
declarations: [],
|
|
imports: [
|
|
IonicModule,
|
|
CommonModule,
|
|
RouterModule,
|
|
HttpClientModule,
|
|
XDirectivesModule,
|
|
],
|
|
exports: [
|
|
CommonModule,
|
|
HttpClientModule,
|
|
XDirectivesModule,
|
|
],
|
|
providers: [
|
|
//
|
|
XDialogService,
|
|
XStorageService,
|
|
XManagerService,
|
|
XHistoryService,
|
|
XSettingsService,
|
|
XSecurityService,
|
|
XGeolocationService,
|
|
XTaskManagerService,
|
|
XLocalizationService,
|
|
XNotificationService,
|
|
XThemeManagerService,
|
|
XSecureStorageService,
|
|
]
|
|
})
|
|
export class XFrameworkServicesModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-geolocation.service.ts
|
|
|
|
import {
|
|
getError,
|
|
Exceptions,
|
|
XException,
|
|
XBaseService,
|
|
} from 'x-framework-core';
|
|
import { Observable } from 'rxjs';
|
|
import { Injectable, Output, EventEmitter, Inject } from '@angular/core';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XGeolocationService extends XBaseService {
|
|
//
|
|
private IS_SUPPORT = false;
|
|
private NAVIGATION_WATCHER: any;
|
|
|
|
//
|
|
options: PositionOptions;
|
|
|
|
//
|
|
@Output()
|
|
changeLoading: EventEmitter<boolean> = new EventEmitter<boolean>();
|
|
|
|
//
|
|
isLoading = false;
|
|
|
|
//
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG) config: XFrameworkServicesConfig
|
|
) {
|
|
super(config);
|
|
|
|
//
|
|
// Check Service is Supported or not ...
|
|
if (navigator.geolocation) {
|
|
this.IS_SUPPORT = true;
|
|
}
|
|
|
|
//
|
|
this.options = {
|
|
...config.geoLocationConfig,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* determines service is Supported or not
|
|
*/
|
|
get isSupport() {
|
|
return this.IS_SUPPORT;
|
|
}
|
|
|
|
/**
|
|
* get given position link for open on Google Maps ...
|
|
*/
|
|
getGoogleMapLink(position: GeolocationPosition) {
|
|
return `https://maps.google.com/?q=${position.coords.latitude},${position.coords.longitude}`;
|
|
}
|
|
|
|
/**
|
|
* get given position Lat,Long string ...
|
|
*/
|
|
getLatLong(position: GeolocationPosition) {
|
|
return `${position.coords.latitude},${position.coords.longitude}`;
|
|
}
|
|
|
|
/**
|
|
* get current location ...
|
|
*/
|
|
getCurrentLocation(): Observable<GeolocationPosition> {
|
|
//
|
|
this.startLoading();
|
|
|
|
return new Observable((observer) => {
|
|
//
|
|
if (!this.IS_SUPPORT) {
|
|
//
|
|
this.stopLoading();
|
|
observer.error(getError(Exceptions.UnsupportedBrowser));
|
|
}
|
|
|
|
//
|
|
navigator.geolocation.getCurrentPosition(
|
|
(position) => {
|
|
//
|
|
this.stopLoading();
|
|
|
|
//
|
|
observer.next(position);
|
|
observer.complete();
|
|
},
|
|
(error) => {
|
|
//
|
|
this.stopLoading();
|
|
|
|
//
|
|
let exception: XException;
|
|
switch (error.code) {
|
|
case 1:
|
|
exception = Exceptions.PermissionDenied;
|
|
break;
|
|
|
|
case 2:
|
|
exception = Exceptions.PositionUnavailable;
|
|
break;
|
|
|
|
case 3:
|
|
default:
|
|
exception = Exceptions.Timeout;
|
|
break;
|
|
}
|
|
|
|
//
|
|
observer.error(getError(exception));
|
|
},
|
|
{
|
|
...this.options,
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* start Watching Location Changes ...
|
|
*/
|
|
watchLocation(): Observable<GeolocationPosition> {
|
|
//
|
|
this.startLoading();
|
|
|
|
//
|
|
return new Observable((observer) => {
|
|
this.NAVIGATION_WATCHER = navigator.geolocation.watchPosition(
|
|
(position) => {
|
|
//
|
|
if (!this.IS_SUPPORT) {
|
|
//
|
|
this.stopLoading();
|
|
observer.error(getError(Exceptions.UnsupportedBrowser));
|
|
observer.complete();
|
|
}
|
|
|
|
//
|
|
observer.next(position);
|
|
},
|
|
(error) => {
|
|
//
|
|
this.stopLoading();
|
|
let exception: XException;
|
|
switch (error.code) {
|
|
case 1:
|
|
exception = Exceptions.PermissionDenied;
|
|
break;
|
|
|
|
case 2:
|
|
exception = Exceptions.PositionUnavailable;
|
|
break;
|
|
|
|
case 3:
|
|
default:
|
|
exception = Exceptions.Timeout;
|
|
break;
|
|
}
|
|
|
|
//
|
|
observer.error(getError(exception));
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Stop Watching Location Changes ...
|
|
*/
|
|
stopWatchingLocation() {
|
|
//
|
|
this.stopLoading();
|
|
navigator.geolocation.clearWatch(this.NAVIGATION_WATCHER);
|
|
}
|
|
|
|
private startLoading() {
|
|
//
|
|
this.isLoading = true;
|
|
this.changeLoading.emit(true);
|
|
}
|
|
|
|
private stopLoading() {
|
|
//
|
|
this.isLoading = false;
|
|
this.changeLoading.emit(false);
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-history.service.ts
|
|
|
|
import { Subject } from 'rxjs';
|
|
import { Injectable } from '@angular/core';
|
|
import { Location, PlatformLocation } from '@angular/common';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XHistoryService {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
public readonly backHandler = new Subject();
|
|
|
|
//
|
|
//#region Getters ...
|
|
//
|
|
get href() {
|
|
return this.platformLocation.href;
|
|
}
|
|
|
|
get protocol() {
|
|
return this.platformLocation.protocol;
|
|
}
|
|
|
|
get hostname() {
|
|
return this.platformLocation.hostname;
|
|
}
|
|
|
|
get port() {
|
|
return this.platformLocation.port;
|
|
}
|
|
|
|
get pathname() {
|
|
return this.platformLocation.pathname;
|
|
}
|
|
|
|
get search() {
|
|
return this.platformLocation.search;
|
|
}
|
|
|
|
get hash() {
|
|
return this.platformLocation.hash;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
public location: Location,
|
|
public platformLocation: PlatformLocation
|
|
) {
|
|
//
|
|
// Prevent from Back Button ...
|
|
this.platformLocation.onPopState(() => {
|
|
this.backHandler.next();
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
pushEmptyState() {
|
|
this.pushState(null, null, this.platformLocation.href);
|
|
}
|
|
|
|
replaceEmptyState() {
|
|
this.replaceState(null, null, this.platformLocation.href);
|
|
}
|
|
|
|
getBaseHrefFromDOM() {
|
|
return this.platformLocation.getBaseHrefFromDOM();
|
|
}
|
|
|
|
getState() {
|
|
return this.platformLocation.getState();
|
|
}
|
|
|
|
replaceState(state: any, title: string, url: string) {
|
|
this.platformLocation.replaceState(state, title, url);
|
|
}
|
|
|
|
pushState(state: any, title: string, url: string) {
|
|
this.platformLocation.pushState(state, title, url);
|
|
}
|
|
|
|
forward() {
|
|
this.location.forward();
|
|
}
|
|
|
|
back() {
|
|
this.location.back();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-http-interceptor.service.ts
|
|
|
|
import {
|
|
HttpEvent,
|
|
HttpRequest,
|
|
HttpHandler,
|
|
HttpInterceptor,
|
|
HttpErrorResponse,
|
|
} from '@angular/common/http';
|
|
import { Observable, throwError } from 'rxjs';
|
|
import { Injectable, Inject } from '@angular/core';
|
|
import { finalize, catchError } from 'rxjs/operators';
|
|
import { XManagerService } from './x-manager.service';
|
|
import { XBaseService, getErrorException } from 'x-framework-core';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XHttpInterceptorService
|
|
extends XBaseService
|
|
implements HttpInterceptor {
|
|
//
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG) config: XFrameworkServicesConfig,
|
|
private managerService: XManagerService
|
|
) {
|
|
super(config);
|
|
}
|
|
|
|
intercept(
|
|
req: HttpRequest<any>,
|
|
next: HttpHandler
|
|
): Observable<HttpEvent<any>> {
|
|
return this.handleInterceptRequest(req, next);
|
|
}
|
|
|
|
handleInterceptRequest(
|
|
req: HttpRequest<any>,
|
|
next: HttpHandler
|
|
): Observable<HttpEvent<any>> {
|
|
//
|
|
// Apply Error Handler ...
|
|
const handledErrors = this.applyErrorHandler(next.handle(req));
|
|
|
|
//
|
|
// Apply Finally Handler ...
|
|
const handledFinally = this.applyFinally(handledErrors);
|
|
|
|
//
|
|
// Final Level ...
|
|
const result = handledFinally;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//#region Actions / Handlers ...
|
|
applyFinally(current: Observable<HttpEvent<any>>) {
|
|
//
|
|
return current.pipe(
|
|
finalize(() => {
|
|
//
|
|
// Collection of instructions after finish or error ...
|
|
this.managerService.loading = false;
|
|
})
|
|
);
|
|
}
|
|
|
|
applyErrorHandler(current: Observable<HttpEvent<any>>) {
|
|
return current.pipe(
|
|
catchError((error: HttpErrorResponse) => {
|
|
//
|
|
this.managerService.loading = true;
|
|
const mException = getErrorException(error.error);
|
|
|
|
//
|
|
this.managerService.error = mException;
|
|
|
|
//
|
|
return throwError(error);
|
|
})
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-identifier.service.ts
|
|
|
|
import { Injectable } from '@angular/core';
|
|
import { XBaseService } from 'x-framework-core';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XIdentifierService extends XBaseService {
|
|
//
|
|
//#region Props ...
|
|
private readonly idStartKey = '_[';
|
|
private readonly idEndKey = ']';
|
|
//#endregion
|
|
|
|
/**
|
|
* check if task name contains id ...
|
|
*
|
|
* @param key the task name ...
|
|
*/
|
|
hasIdentifier(key: string | any, forceAppName = false) {
|
|
//
|
|
if (!key) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const mKey = key.toString() as string;
|
|
const result =
|
|
mKey.includes(this.idStartKey) && mKey.includes(this.idEndKey);
|
|
|
|
//
|
|
return forceAppName
|
|
? result && mKey.includes(this.config.appInstanceName)
|
|
: result;
|
|
}
|
|
|
|
/**
|
|
* retrieve and extract the raw task name from a task name ...
|
|
*
|
|
* @param key the task name ...
|
|
*/
|
|
getName(key: string | any) {
|
|
//
|
|
if (!key) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
const mKey = key.toString() as string;
|
|
|
|
//
|
|
if (!this.hasIdentifier(mKey)) {
|
|
return mKey;
|
|
}
|
|
|
|
//
|
|
const startIndex = mKey.indexOf(this.idStartKey);
|
|
let result = mKey.substr(0, startIndex);
|
|
result = result.replace(this.idStartKey, '');
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* retrieve and extract the id inside a task name ...
|
|
*
|
|
* @param key the task name ...
|
|
*/
|
|
getIdentifier(key: string | any, cleanAppName = true) {
|
|
//
|
|
// Validate Args ...
|
|
if (!key || !this.hasIdentifier(key)) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
// Task Id ...
|
|
let result = key.toString() as string;
|
|
|
|
//
|
|
// Validating Info ...
|
|
let index = result.indexOf(this.idStartKey);
|
|
|
|
//
|
|
result = result.substr(index, result.length);
|
|
result = result.replace(this.idStartKey, '');
|
|
|
|
//
|
|
index = result.indexOf(this.idEndKey);
|
|
result = result.substring(0, index);
|
|
|
|
//
|
|
if (cleanAppName) {
|
|
result = result.replace(this.config.appInstanceName, '');
|
|
}
|
|
|
|
//
|
|
// Return Result ...
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* prepare a Task With ID and return ...
|
|
*
|
|
* @param key the Task Name ...
|
|
* @param id th ID ...
|
|
*/
|
|
setIdentifier(key: string | any, id: string | any, containsAppName = false) {
|
|
return `${key.toString()}${this.idStartKey}${
|
|
containsAppName ? this.config.appInstanceName : ''
|
|
}${id.toString()}${this.idEndKey}`;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-localization.service.ts
|
|
|
|
import {
|
|
XParam,
|
|
getVal,
|
|
XLocale,
|
|
isNumber,
|
|
formatDate,
|
|
XException,
|
|
Exceptions,
|
|
fromUtcDate,
|
|
XBaseService,
|
|
XResourceIDs,
|
|
GetDateProps,
|
|
XExceptionIDs,
|
|
throwException,
|
|
isValidException,
|
|
XTranslationItem,
|
|
isNullOrUndefined,
|
|
getErrorException,
|
|
XLanguageDirection,
|
|
XResourceIdentifier,
|
|
XLanguageDescriptor,
|
|
getErrorDateFormatString,
|
|
getDateOfBirthDateFormatString,
|
|
} from 'x-framework-core';
|
|
import { Injectable, Inject } from '@angular/core';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XLocalizationService extends XBaseService {
|
|
//
|
|
private LANGUAGEDESCRIPTOR: XLanguageDescriptor;
|
|
private AVAILABLELANGUAGES: XLanguageDescriptor[];
|
|
|
|
//
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG) config: XFrameworkServicesConfig
|
|
) {
|
|
super(config);
|
|
|
|
//
|
|
// Inject Loacle and set Application Locale and Direction based on it ...
|
|
this.AVAILABLELANGUAGES = config.availableLanguages;
|
|
this.LANGUAGEDESCRIPTOR = config.availableLanguages.find(
|
|
(al) => al.locale === config.defaultLanguage
|
|
);
|
|
window[XParam.Language] = this.LANGUAGEDESCRIPTOR.locale;
|
|
}
|
|
|
|
//
|
|
//#region Properties ...
|
|
/**
|
|
* Current System Locale ...
|
|
*/
|
|
get locale() {
|
|
return this.languageDescriptor.locale;
|
|
}
|
|
|
|
/**
|
|
* Current Locale UI Direction ...
|
|
*/
|
|
get direction(): XLanguageDirection {
|
|
return this.languageDescriptor.direction;
|
|
}
|
|
|
|
/**
|
|
* current available language
|
|
*/
|
|
get language() {
|
|
return this.languageDescriptor.language;
|
|
}
|
|
|
|
/**
|
|
* get Current Locale Name ...
|
|
*/
|
|
get name() {
|
|
return this.languageDescriptor.name;
|
|
}
|
|
|
|
/**
|
|
* get Current Locale Language Descriptor Object ...
|
|
*/
|
|
get languageDescriptor() {
|
|
return this.LANGUAGEDESCRIPTOR;
|
|
}
|
|
|
|
/**
|
|
* get Available Languages ...
|
|
*/
|
|
get availableLanguages() {
|
|
return this.AVAILABLELANGUAGES;
|
|
}
|
|
//#endregion
|
|
|
|
/**
|
|
* change current language ...
|
|
*
|
|
* @param locale name of available language
|
|
*/
|
|
changeLocale(locale: XLocale) {
|
|
//
|
|
const languageDescriptor = this.languageDescriptorOfLocale(locale);
|
|
if (!languageDescriptor) {
|
|
throwException(XExceptionIDs.InvalidConfiguration);
|
|
}
|
|
|
|
//
|
|
window[XParam.Language] = locale;
|
|
this.LANGUAGEDESCRIPTOR = languageDescriptor;
|
|
}
|
|
|
|
/**
|
|
* Find specific Language Descriptor ...
|
|
*/
|
|
languageDescriptorOfLocale(locale: XLocale) {
|
|
//
|
|
return this.availableLanguages.find((al) => al.locale === locale);
|
|
}
|
|
|
|
/**
|
|
* check an id exists in resources or not
|
|
*/
|
|
isExistsId(id: XResourceIdentifier) {
|
|
//
|
|
const key = getVal(XResourceIDs, id) || id;
|
|
|
|
//
|
|
return (
|
|
this.languageDescriptor.resources.findIndex((tr) => tr.id === key) > -1
|
|
);
|
|
}
|
|
|
|
/**
|
|
* check an id exists in resources of specific locale or not
|
|
*/
|
|
isExistsIdOfLocale(locale: XLocale, id: XResourceIdentifier) {
|
|
//
|
|
const key = getVal(XResourceIDs, id) || id;
|
|
|
|
//
|
|
return (
|
|
this.languageDescriptorOfLocale(locale).resources.findIndex(
|
|
(tr) => tr.id === key
|
|
) > -1
|
|
);
|
|
}
|
|
|
|
/**
|
|
* get translation item of current language
|
|
*/
|
|
getTranslationItem(id: XResourceIdentifier): XTranslationItem {
|
|
//
|
|
const key = getVal(XResourceIDs, id) || id;
|
|
|
|
//
|
|
return this.languageDescriptor.resources.find((tr) => tr.id === key);
|
|
}
|
|
|
|
/**
|
|
* get translation item of specific language
|
|
*/
|
|
getTranslationItemOfLocale(locale: XLocale, id: XResourceIdentifier) {
|
|
//
|
|
const key = getVal(XResourceIDs, id) || id;
|
|
|
|
//
|
|
const selectedLocale = this.languageDescriptorOfLocale(locale);
|
|
|
|
//
|
|
if (!selectedLocale || !this.isExistsIdOfLocale(locale, key)) {
|
|
throwException(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return selectedLocale.resources.find((tr) => tr.id === key);
|
|
}
|
|
|
|
/**
|
|
* get Value of specific id in Current Locale
|
|
*/
|
|
getValue(id: XResourceIdentifier) {
|
|
//
|
|
if (!this.isExistsId(id)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.getTranslationItem(id).value;
|
|
}
|
|
|
|
/**
|
|
* get Value of specific id in specific Locale
|
|
*/
|
|
getValueOfLocale(locale: XLocale, id: XResourceIdentifier) {
|
|
//
|
|
if (!this.isExistsIdOfLocale(locale, id)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.getTranslationItemOfLocale(locale, id).value;
|
|
}
|
|
|
|
/**
|
|
* get coresponding translated value of errors
|
|
*/
|
|
getErrorMessage(err: any, locale?: XLocale) {
|
|
//
|
|
if (!locale) {
|
|
locale = this.locale;
|
|
}
|
|
|
|
//
|
|
let exception: XException;
|
|
|
|
//
|
|
if (isValidException(err)) {
|
|
exception = err as XException;
|
|
} else {
|
|
exception = getErrorException(err);
|
|
}
|
|
|
|
//
|
|
if (exception.id && isNumber(exception.id)) {
|
|
//
|
|
const exceptionID = `ex_${exception.id}`;
|
|
return this.getValueOfLocale(locale, exceptionID);
|
|
}
|
|
|
|
//
|
|
return this.getValueOfLocale(locale, 'general_error');
|
|
}
|
|
|
|
/**
|
|
* get and format date
|
|
*/
|
|
getDate(props?: GetDateProps): string {
|
|
//
|
|
if (!props) {
|
|
props = {};
|
|
}
|
|
|
|
//
|
|
if (!props.locale) {
|
|
props.locale = this.locale;
|
|
}
|
|
//
|
|
if (!props.date) {
|
|
props.date = new Date();
|
|
}
|
|
//
|
|
if (!props.dateFormat) {
|
|
props.dateFormat = getDateOfBirthDateFormatString(props.locale);
|
|
}
|
|
//
|
|
if (!props.toUtc) {
|
|
props.toUtc = false;
|
|
}
|
|
//
|
|
return formatDate(props.date, props.locale, props.dateFormat, props.toUtc);
|
|
}
|
|
|
|
/**
|
|
* combine some resources and represent single joined string ...
|
|
*
|
|
* @param locale translated dest locale ...
|
|
* @param joinString the string which used to join translated parts ...
|
|
* @param resources an array of translation resources ...
|
|
*/
|
|
combine(
|
|
locale?: XLocale,
|
|
joinString: string = ' ',
|
|
...resources: XResourceIdentifier[]
|
|
) {
|
|
//
|
|
if (isNullOrUndefined(locale)) {
|
|
locale = this.locale;
|
|
}
|
|
|
|
//
|
|
const result = resources
|
|
.map((r) => this.getValueOfLocale(locale, r))
|
|
.join(joinString);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-manager.service.ts
|
|
|
|
import { Location } from '@angular/common';
|
|
import { Platform } from '@angular/cdk/platform';
|
|
import { HttpClient } from '@angular/common/http';
|
|
import { Inject, Injectable } from '@angular/core';
|
|
import { XDialogService } from './x-dialog.service';
|
|
import { XStorageService } from './x-storage.service';
|
|
import { XHistoryService } from './x-history.service';
|
|
import { XSecurityService } from './x-security.service';
|
|
import { XSettingsService } from './x-settings.service';
|
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
import { XIdentifierService } from './x-identifier.service';
|
|
import { XGeolocationService } from './x-geolocation.service';
|
|
import { XTaskManagerService } from './x-task-manager.service';
|
|
import { MenuController, NavController } from '@ionic/angular';
|
|
import { XNotificationService } from './x-notification.service';
|
|
import { XLocalizationService } from './x-localization.service';
|
|
import { XThemeManagerService } from './x-theme-manager.service';
|
|
import { XSecureStorageService } from './x-secure-storage.service';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
import { XManagerFinalService } from './x-manager-service-partial/x-manager-final.service';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XManagerService extends XManagerFinalService {
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG)
|
|
public config: XFrameworkServicesConfig,
|
|
public router: Router,
|
|
public platform: Platform,
|
|
public location: Location,
|
|
public httpClient: HttpClient,
|
|
public dialogService: XDialogService,
|
|
public menuController: MenuController,
|
|
public activatedRoute: ActivatedRoute,
|
|
public historyService: XHistoryService,
|
|
public storageService: XStorageService,
|
|
public securityService: XSecurityService,
|
|
public settingsService: XSettingsService,
|
|
public navigationController: NavController,
|
|
public identifierService: XIdentifierService,
|
|
public geoLocationService: XGeolocationService,
|
|
public taskManagerService: XTaskManagerService,
|
|
public themeManagerService: XThemeManagerService,
|
|
public notificationService: XNotificationService,
|
|
public localizationService: XLocalizationService,
|
|
public secureStorageService: XSecureStorageService
|
|
) {
|
|
super(
|
|
config,
|
|
router,
|
|
platform,
|
|
location,
|
|
httpClient,
|
|
dialogService,
|
|
menuController,
|
|
activatedRoute,
|
|
historyService,
|
|
storageService,
|
|
securityService,
|
|
settingsService,
|
|
navigationController,
|
|
geoLocationService,
|
|
taskManagerService,
|
|
themeManagerService,
|
|
notificationService,
|
|
localizationService,
|
|
secureStorageService
|
|
);
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-notification.service.ts
|
|
|
|
import {
|
|
XColor,
|
|
isNumber,
|
|
XActionType,
|
|
XValidators,
|
|
XResourceIDs,
|
|
XBaseService,
|
|
XNotificationParams,
|
|
XTypedNotificationParams,
|
|
XErrorNotificationParams,
|
|
} from 'x-framework-core';
|
|
import { Howl } from 'howler';
|
|
import { ToastOptions } from '@ionic/core';
|
|
import { ToastController } from '@ionic/angular';
|
|
import { Injectable, Inject } from '@angular/core';
|
|
import { XLocalizationService } from './x-localization.service';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XNotificationService extends XBaseService {
|
|
//
|
|
private NOTIFICATION_IDS: string[] = [];
|
|
|
|
//
|
|
private userNotifiCationSound: Howl;
|
|
private captureNotifiCationSound: Howl;
|
|
private systemNotifiCationSound: Howl;
|
|
|
|
//
|
|
public notificationDelay: number;
|
|
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG) config: XFrameworkServicesConfig,
|
|
private localizationService: XLocalizationService,
|
|
private toastController: ToastController
|
|
) {
|
|
//
|
|
super(config);
|
|
|
|
//
|
|
const userActionConfig = config.notificationAudioSources.find(
|
|
(as) => as.type === XActionType.User
|
|
);
|
|
const systemActionConfig = config.notificationAudioSources.find(
|
|
(as) => as.type === XActionType.System
|
|
);
|
|
const captureActionConfig = config.notificationAudioSources.find(
|
|
(as) => as.type === XActionType.Capture
|
|
);
|
|
|
|
//
|
|
this.notificationDelay = config.defaultNotificationDelay;
|
|
|
|
//
|
|
this.userNotifiCationSound = new Howl({
|
|
src: [userActionConfig.resourcePath],
|
|
});
|
|
this.captureNotifiCationSound = new Howl({
|
|
src: [captureActionConfig.resourcePath],
|
|
});
|
|
this.systemNotifiCationSound = new Howl({
|
|
src: [systemActionConfig.resourcePath],
|
|
});
|
|
}
|
|
|
|
/**
|
|
* play sound based on type
|
|
*/
|
|
playSound(type: XActionType = XActionType.System) {
|
|
//
|
|
switch (type) {
|
|
//
|
|
case XActionType.Capture:
|
|
this.playCaptureNotification();
|
|
break;
|
|
|
|
//
|
|
case XActionType.User:
|
|
this.playUserNotification();
|
|
break;
|
|
|
|
//
|
|
default:
|
|
case XActionType.System:
|
|
this.playSystemNotification();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* play system sound
|
|
*/
|
|
playSystemNotification() {
|
|
//
|
|
if (this.systemNotifiCationSound.playing()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.systemNotifiCationSound.play();
|
|
}
|
|
|
|
/**
|
|
* play user sound
|
|
*/
|
|
playUserNotification() {
|
|
//
|
|
if (this.userNotifiCationSound.playing()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.userNotifiCationSound.play();
|
|
}
|
|
|
|
/**
|
|
* play Capture sound
|
|
*/
|
|
playCaptureNotification() {
|
|
//
|
|
if (this.captureNotifiCationSound.playing()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.captureNotifiCationSound.play();
|
|
}
|
|
|
|
//
|
|
//#region Toas Related ...
|
|
/**
|
|
* create a notification object ...
|
|
*
|
|
* @param opt notification options
|
|
*/
|
|
createNotification(props?: XNotificationParams) {
|
|
const toastOpt = this.prepareToastOptions(props);
|
|
return this.toastController.create(toastOpt);
|
|
}
|
|
|
|
/**
|
|
* create and present notification ...
|
|
*
|
|
* @param opt notification options
|
|
*/
|
|
async presentNotification(props?: XNotificationParams) {
|
|
//
|
|
const mProps = props ? props : this.getDefaultNotificationOptions();
|
|
|
|
//
|
|
const notification = await this.createNotification(mProps);
|
|
this.NOTIFICATION_IDS.push(notification.id);
|
|
|
|
//
|
|
notification.onDidDismiss().then(() => {
|
|
if (mProps.onDidDismiss) {
|
|
mProps.onDidDismiss();
|
|
this.NOTIFICATION_IDS = this.NOTIFICATION_IDS.filter(
|
|
(id) => id === notification.id
|
|
);
|
|
}
|
|
});
|
|
|
|
//
|
|
notification.onWillDismiss().then(() => {
|
|
if (mProps.onWillDismiss) {
|
|
mProps.onWillDismiss();
|
|
}
|
|
});
|
|
|
|
//
|
|
notification.present();
|
|
|
|
//
|
|
if (props && props.playSound) {
|
|
this.playSound(props.type);
|
|
}
|
|
}
|
|
|
|
async presentXNotification(props: XTypedNotificationParams) {
|
|
//
|
|
// Validate Args ...
|
|
XValidators.validateNotNull(props);
|
|
|
|
//
|
|
const isResourceID = isNumber(props.message);
|
|
const mMessage = isResourceID
|
|
? this.localizationService.getValue(props.message as XResourceIDs)
|
|
: (props.message as string);
|
|
const defOpts = this.getDefaultNotificationOptions();
|
|
const mProps = {
|
|
...defOpts,
|
|
...props,
|
|
opt: {
|
|
...defOpts.opt,
|
|
...props.opt,
|
|
message: mMessage,
|
|
},
|
|
};
|
|
|
|
//
|
|
await this.presentNotification(mProps);
|
|
}
|
|
|
|
/**
|
|
* present Info notification
|
|
*
|
|
* @param props Notification Properties
|
|
*/
|
|
async presentInfoNotification(
|
|
props: XTypedNotificationParams
|
|
): Promise<void> {
|
|
await this.presentXNotification({
|
|
...props,
|
|
opt: {
|
|
...props.opt,
|
|
color: XColor.Tertiary,
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* present Success Notification
|
|
*
|
|
* @param props Notification Properties
|
|
*/
|
|
async presentSuccessNotification(
|
|
props: XTypedNotificationParams
|
|
): Promise<void> {
|
|
await this.presentXNotification({
|
|
...props,
|
|
opt: {
|
|
...props.opt,
|
|
color: XColor.Success,
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* present Default Success Notification
|
|
*/
|
|
async presentDefaultSuccessNotification(
|
|
dissmissHandler?: () => void
|
|
): Promise<void> {
|
|
//
|
|
const mProps: XTypedNotificationParams = {
|
|
message: XResourceIDs.success_msg,
|
|
dissmissable: true,
|
|
onWillDismiss: dissmissHandler,
|
|
};
|
|
|
|
await this.presentSuccessNotification(mProps);
|
|
}
|
|
|
|
/**
|
|
* present warning notifications
|
|
*
|
|
* @param props Notification Properties
|
|
*/
|
|
async presentWarningNotification(
|
|
props: XTypedNotificationParams
|
|
): Promise<void> {
|
|
await this.presentXNotification({
|
|
...props,
|
|
opt: {
|
|
...props.opt,
|
|
color: XColor.Warning,
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* present error notification
|
|
*
|
|
* @param props Notification Properties
|
|
*/
|
|
async presentDangerNotification(
|
|
props: XTypedNotificationParams
|
|
): Promise<void> {
|
|
await this.presentXNotification({
|
|
...props,
|
|
opt: {
|
|
...props.opt,
|
|
color: XColor.Danger,
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* present an Exception or Error Message ...
|
|
*
|
|
* @param props Notification Properties
|
|
*/
|
|
async presentErrorNotification(
|
|
props: XErrorNotificationParams
|
|
): Promise<void> {
|
|
//
|
|
const mMessage = this.localizationService.getErrorMessage(props.exception);
|
|
await this.presentXNotification({
|
|
...props,
|
|
message: mMessage,
|
|
dissmissable: props.dissmissable,
|
|
opt: {
|
|
...props.opt,
|
|
color: XColor.Danger,
|
|
},
|
|
});
|
|
}
|
|
|
|
async closeAllNotifications() {
|
|
this.NOTIFICATION_IDS.forEach(async (id) => {
|
|
try {
|
|
await this.toastController.dismiss(null, null, id);
|
|
} catch {}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* combines default notification options by
|
|
* given notification options ...
|
|
*
|
|
* @param opt notification options
|
|
*/
|
|
private prepareToastOptions(props?: XNotificationParams): ToastOptions {
|
|
//
|
|
if (!props) {
|
|
props = this.getDefaultNotificationOptions();
|
|
}
|
|
|
|
//
|
|
// Handle Dissmissable
|
|
const mDuration = props.dissmissable ? props.opt.duration : 0;
|
|
|
|
//
|
|
const result = {
|
|
...props.opt,
|
|
duration: mDuration,
|
|
};
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* generate default notification options ...
|
|
*/
|
|
private getDefaultNotificationOptions(): XNotificationParams {
|
|
return {
|
|
playSound: false,
|
|
type: XActionType.System,
|
|
dissmissable: true,
|
|
opt: {
|
|
color: XColor.Tertiary,
|
|
position: 'bottom',
|
|
duration: this.notificationDelay,
|
|
// ,
|
|
// showCloseButton: true,
|
|
// closeButtonText: this.localizationService.getValue(XResourceIDs.dismiss)
|
|
},
|
|
};
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-secure-storage.service.ts
|
|
|
|
import {
|
|
fromJson,
|
|
XStorageItem,
|
|
XExceptionIDs,
|
|
throwException,
|
|
isNullOrUndefined
|
|
} from 'x-framework-core';
|
|
import { Injectable, Inject } from '@angular/core';
|
|
import { XStorageService } from './x-storage.service';
|
|
import { XSecurityService } from './x-security.service';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XSecureStorageService extends XStorageService {
|
|
//
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG) config: XFrameworkServicesConfig,
|
|
private securitySerive: XSecurityService
|
|
) {
|
|
super(config);
|
|
}
|
|
|
|
/**
|
|
* writing a new item in Storage ...
|
|
*
|
|
* @param key the item key
|
|
* @param data the data object which needs to save
|
|
* @param forceRewrite overwrite item if exists, the default is false,
|
|
* means if key exists throws an error ...
|
|
*/
|
|
write(key: string, data: any, forceRewrite: boolean = false) {
|
|
//
|
|
if (!forceRewrite && this.isExists(key)) {
|
|
throwException(XExceptionIDs.Duplicate);
|
|
}
|
|
|
|
//
|
|
const theKey = this.getPreparedKey(key);
|
|
const encryptedValue = this.securitySerive.encryptWithKey(
|
|
JSON.stringify(data)
|
|
);
|
|
|
|
//
|
|
localStorage.setItem(theKey, encryptedValue);
|
|
}
|
|
|
|
/**
|
|
* read an item from Storage ...
|
|
* @param key the item key
|
|
* @param forceExists determine the given key must be exists or not, true is default,
|
|
* means if key not exists throws an error ...
|
|
*/
|
|
read(key: string, forceExists: boolean = true): any | null {
|
|
//
|
|
if (forceExists && !this.isExists(key)) {
|
|
throwException(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
const theKey = this.getPreparedKey(key);
|
|
const item = localStorage.getItem(theKey);
|
|
if (!isNullOrUndefined(item)) {
|
|
try {
|
|
const decryptedValue = this.securitySerive.decryptWithKey(item);
|
|
return JSON.parse(decryptedValue);
|
|
} catch {}
|
|
}
|
|
|
|
//
|
|
return null;
|
|
}
|
|
readOfType<T>(key: string, forceExists: boolean = true): T | null {
|
|
//
|
|
if (!this.isExists(key)) {
|
|
//
|
|
if (forceExists) {
|
|
throwException(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const valStr = this.read(key, forceExists);
|
|
return fromJson<T>(valStr);
|
|
}
|
|
|
|
/**
|
|
* get a List of Stored items as an Array of StorageItem ...
|
|
* @param force true is defualt, means only return list of items
|
|
* from Storage which Stored by Service ...
|
|
*/
|
|
list(force: boolean = true, decrypt: boolean = false): XStorageItem[] | null {
|
|
//
|
|
if (localStorage.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const items: XStorageItem[] = [];
|
|
for (let i = 0; i < localStorage.length; i++) {
|
|
//
|
|
const mKey = localStorage.key(i);
|
|
|
|
//
|
|
const mValue = localStorage.getItem(mKey);
|
|
const mValueRes = decrypt
|
|
? this.securitySerive.decryptWithKey(mValue)
|
|
: mValue;
|
|
|
|
//
|
|
if (force) {
|
|
const theRawKey = this.getRawKey(mKey);
|
|
if (!isNullOrUndefined(theRawKey)) {
|
|
//
|
|
items.push({
|
|
key: theRawKey,
|
|
value: mValueRes
|
|
});
|
|
}
|
|
} else {
|
|
//
|
|
items.push({
|
|
key: mKey,
|
|
value: mValueRes
|
|
});
|
|
}
|
|
}
|
|
|
|
//
|
|
return items;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-security.service.ts
|
|
|
|
import * as CryptoJS from 'crypto-js';
|
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { toMd5, XBaseService, isNullOrEmptyString } from 'x-framework-core';
|
|
import { Injectable, Inject, Sanitizer, SecurityContext } from '@angular/core';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XSecurityService extends XBaseService {
|
|
//
|
|
private readonly SECRET_KEY: string;
|
|
private readonly CIPHER_KEY: string;
|
|
private readonly CIPHER_IV: string;
|
|
private readonly CIPHER_OPTION: CryptoJS.lib.CipherOption;
|
|
|
|
//
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG) config: XFrameworkServicesConfig,
|
|
private sanitizer: Sanitizer,
|
|
private domSanitizer: DomSanitizer
|
|
) {
|
|
super(config);
|
|
|
|
//
|
|
this.SECRET_KEY = toMd5(config.secretKey);
|
|
|
|
//
|
|
const forIv = this.SECRET_KEY.substring(0, 16);
|
|
this.CIPHER_IV = CryptoJS.enc.Utf8.parse(forIv).toString();
|
|
|
|
//
|
|
const forKey = this.SECRET_KEY.substring(0, 32);
|
|
this.CIPHER_KEY = CryptoJS.enc.Utf8.parse(forKey).toString();
|
|
|
|
//
|
|
this.CIPHER_OPTION = {
|
|
iv: CryptoJS.enc.Utf8.parse(this.CIPHER_IV),
|
|
mode: CryptoJS.mode.CBC,
|
|
padding: CryptoJS.pad.Pkcs7,
|
|
};
|
|
}
|
|
|
|
encryptWithKey(
|
|
value: string,
|
|
key?: string,
|
|
options?: CryptoJS.lib.CipherOption
|
|
) {
|
|
//
|
|
if (isNullOrEmptyString(value)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
if (!key) {
|
|
key = this.CIPHER_KEY;
|
|
}
|
|
|
|
//
|
|
if (!options) {
|
|
options = this.CIPHER_OPTION;
|
|
}
|
|
|
|
//
|
|
return CryptoJS.AES.encrypt(value, key, options).toString();
|
|
}
|
|
|
|
encryptWithSecret(
|
|
value: string,
|
|
secret?: string,
|
|
options?: CryptoJS.lib.CipherOption
|
|
) {
|
|
//
|
|
if (isNullOrEmptyString(value)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
if (!secret) {
|
|
secret = this.SECRET_KEY;
|
|
}
|
|
|
|
//
|
|
if (!options) {
|
|
options = this.CIPHER_OPTION;
|
|
}
|
|
|
|
//
|
|
return CryptoJS.AES.encrypt(value, secret, options);
|
|
}
|
|
|
|
decryptWithKey(
|
|
cipherValue: string,
|
|
key?: string,
|
|
options?: CryptoJS.lib.CipherOption
|
|
) {
|
|
//
|
|
if (isNullOrEmptyString(cipherValue)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
if (!key) {
|
|
key = this.CIPHER_KEY;
|
|
}
|
|
|
|
//
|
|
if (!options) {
|
|
options = this.CIPHER_OPTION;
|
|
}
|
|
|
|
//
|
|
const result = CryptoJS.AES.decrypt(cipherValue, key, options).toString(
|
|
CryptoJS.enc.Utf8
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
decryptWithSecret(
|
|
cipherValue: string,
|
|
secret?: string,
|
|
options?: CryptoJS.lib.CipherOption
|
|
) {
|
|
//
|
|
if (isNullOrEmptyString(cipherValue)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
if (!secret) {
|
|
secret = this.SECRET_KEY;
|
|
}
|
|
|
|
//
|
|
if (!options) {
|
|
options = this.CIPHER_OPTION;
|
|
}
|
|
|
|
//
|
|
return CryptoJS.AES.decrypt(cipherValue, secret, options).toString();
|
|
}
|
|
|
|
toMd5(value: string) {
|
|
return toMd5(value);
|
|
}
|
|
|
|
toSafeString(value: string, context: SecurityContext = SecurityContext.NONE) {
|
|
return this.sanitizer.sanitize(context, value);
|
|
}
|
|
|
|
toSafeHTML(value: string) {
|
|
return this.domSanitizer.bypassSecurityTrustHtml(value);
|
|
}
|
|
|
|
toSafeResourceURL(value: string) {
|
|
return this.domSanitizer.bypassSecurityTrustResourceUrl(value);
|
|
}
|
|
|
|
toSafeURL(value: string) {
|
|
return this.domSanitizer.bypassSecurityTrustUrl(value);
|
|
}
|
|
|
|
toSafeScript(value: string) {
|
|
return this.domSanitizer.bypassSecurityTrustScript(value);
|
|
}
|
|
|
|
toSafeStyle(value: string) {
|
|
return this.domSanitizer.bypassSecurityTrustStyle(value);
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-settings.service.ts
|
|
|
|
import {
|
|
isArray,
|
|
XLocale,
|
|
XDeviceInfo,
|
|
XValidators,
|
|
XOrientation,
|
|
XBaseService,
|
|
XDeviceTypes,
|
|
XOneOrManyType,
|
|
XCssProperties,
|
|
XLanguageDirection,
|
|
XSettingsStorageKey,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import {
|
|
Breakpoints,
|
|
BreakpointState,
|
|
BreakpointObserver,
|
|
} from '@angular/cdk/layout';
|
|
import { Observable } from 'rxjs';
|
|
import { Md5 } from 'md5-typescript';
|
|
import { map } from 'rxjs/operators';
|
|
import { Platform } from '@ionic/angular';
|
|
import { Injectable, Inject } from '@angular/core';
|
|
import { XStorageService } from './x-storage.service';
|
|
import { DeviceDetectorService } from 'ngx-device-detector';
|
|
import { XLocalizationService } from './x-localization.service';
|
|
import { Meta, Title, MetaDefinition } from '@angular/platform-browser';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XSettingsService extends XBaseService {
|
|
//
|
|
private PREFIX = '--';
|
|
private DEVICE_INFO: XDeviceInfo;
|
|
private SIDE_MENU_OPENED: boolean;
|
|
|
|
//
|
|
//#region Breakpoint Observers ...
|
|
isMobile$: Observable<boolean>;
|
|
isXSmall$: Observable<boolean>;
|
|
isSmall$: Observable<boolean>;
|
|
isMedium$: Observable<boolean>;
|
|
isLarge$: Observable<boolean>;
|
|
isXLarge$: Observable<boolean>;
|
|
isTablet$: Observable<boolean>;
|
|
isWeb$: Observable<boolean>;
|
|
isPortrait$: Observable<boolean>;
|
|
isLandscape$: Observable<boolean>;
|
|
orientation$: Observable<XOrientation>;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Properties ...
|
|
//
|
|
get uiDirection(): XLanguageDirection {
|
|
return this.localizationService.direction;
|
|
}
|
|
//#endregion
|
|
|
|
constructor(
|
|
public platform: Platform,
|
|
private meta: Meta,
|
|
private titleService: Title,
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG) config: XFrameworkServicesConfig,
|
|
private storageService: XStorageService,
|
|
private localizationService: XLocalizationService,
|
|
private deviceService: DeviceDetectorService,
|
|
private breakPointObserver: BreakpointObserver
|
|
) {
|
|
//
|
|
super(config);
|
|
|
|
//
|
|
// Handle Ui Directions based on Current Locale ...
|
|
this.applyCurrentLocale();
|
|
|
|
//
|
|
// Generate Device Info ...
|
|
this.prepareDeviceInfo();
|
|
|
|
//
|
|
// define objservable ...
|
|
this.defineUiBreakPointObservers();
|
|
|
|
//
|
|
// Handle Metas for Theme ...
|
|
this.handleThemeMetaTags();
|
|
|
|
//
|
|
// Prepare Toolbar Height ...
|
|
}
|
|
|
|
/**
|
|
* restart application ...
|
|
*/
|
|
restart() {
|
|
//
|
|
if (!window || !window.location) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const href = window.location.href;
|
|
setTimeout(() => {
|
|
window.location.href = href;
|
|
window.location.reload();
|
|
}, 100)
|
|
}
|
|
|
|
/**
|
|
* change system locale ...
|
|
*
|
|
* @param locale available locale
|
|
*/
|
|
async changeLocale(locale: XLocale, refresh: boolean = false) {
|
|
//
|
|
XValidators.validateNotNull(locale);
|
|
if (locale === this.localizationService.locale) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.storageService.write(XSettingsStorageKey.Locale, locale, true);
|
|
this.localizationService.changeLocale(locale);
|
|
this.applyCurrentLocale();
|
|
|
|
//
|
|
if (refresh) {
|
|
this.restart();
|
|
}
|
|
}
|
|
|
|
//
|
|
//#region Met Seo Service ...
|
|
addTag(tag: MetaDefinition, forceCreation?: boolean) {
|
|
this.meta.addTag(tag, forceCreation);
|
|
}
|
|
|
|
addTags(tags: MetaDefinition[], forceCreation?: boolean) {
|
|
this.meta.addTags(tags, forceCreation);
|
|
}
|
|
|
|
getTag(attrSelector: string) {
|
|
this.meta.getTag(attrSelector);
|
|
}
|
|
|
|
getTags(attrSelector: string) {
|
|
this.meta.getTags(attrSelector);
|
|
}
|
|
|
|
updateTag(tag: MetaDefinition, attrSelector?: string) {
|
|
this.meta.updateTag(tag, attrSelector);
|
|
}
|
|
|
|
removeTag(attrSelector: string) {
|
|
this.meta.removeTag(attrSelector);
|
|
}
|
|
|
|
removeTagElement(meta: HTMLMetaElement) {
|
|
this.meta.removeTagElement(meta);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Title Service ...
|
|
/**
|
|
* set Page ( Current Document ) Title
|
|
* in Browser ...
|
|
*/
|
|
setTitle(title?: string) {
|
|
//
|
|
const appNameKey = this.config.appNameResource;
|
|
const appName = this.localizationService.getValue(appNameKey);
|
|
|
|
//
|
|
const pageTitle = !isNullOrEmptyString(title)
|
|
? `${appName} > ${title}`
|
|
: appName;
|
|
|
|
//
|
|
this.titleService.setTitle(pageTitle);
|
|
}
|
|
|
|
/**
|
|
* get the Current Document Title ...
|
|
*/
|
|
getTitle() {
|
|
return this.titleService.getTitle();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Device Service ...
|
|
/**
|
|
* get Current Device Model Info
|
|
*/
|
|
get device() {
|
|
return this.DEVICE_INFO;
|
|
}
|
|
|
|
/**
|
|
* get Current Device token
|
|
*/
|
|
get deviceToken() {
|
|
return this.DEVICE_INFO.token;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Css Property Handler ...
|
|
/**
|
|
* reading the CSS Property ...
|
|
*
|
|
* @param key the key of property
|
|
*/
|
|
readCssProperty(key: XCssProperties): string {
|
|
//
|
|
const bodyStyles = window.getComputedStyle(document.body);
|
|
return bodyStyles.getPropertyValue(this.prepareCssKey(key));
|
|
}
|
|
|
|
getCssVar(name: XCssProperties, element?: HTMLElement) {
|
|
//
|
|
const docElement = element
|
|
? getComputedStyle(element)
|
|
: getComputedStyle(document.documentElement);
|
|
return !name || !docElement || isNullOrEmptyString(name)
|
|
? ''
|
|
: docElement.getPropertyValue(this.prepareCssKey(name));
|
|
}
|
|
|
|
setCssVar(
|
|
name: XCssProperties,
|
|
value: string,
|
|
elements?: XOneOrManyType<HTMLElement>
|
|
) {
|
|
//
|
|
if (isNullOrEmptyString(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (!elements || !isArray(elements)) {
|
|
//
|
|
const docElement = elements
|
|
? (elements as HTMLElement).style
|
|
: document.documentElement.style;
|
|
|
|
//
|
|
docElement.setProperty(this.prepareCssKey(name), value);
|
|
} else {
|
|
(elements as HTMLElement[]).forEach((e) => {
|
|
e.style.setProperty(this.prepareCssKey(name), value);
|
|
});
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Theme Manager ...
|
|
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private
|
|
private applyCurrentLocale() {
|
|
//
|
|
let storedLocale = this.localizationService.locale;
|
|
const isExistsLocale = this.storageService.isExists(
|
|
XSettingsStorageKey.Locale
|
|
);
|
|
if (isExistsLocale) {
|
|
storedLocale = this.storageService.readOfType<XLocale>(
|
|
XSettingsStorageKey.Locale
|
|
);
|
|
this.localizationService.changeLocale(storedLocale);
|
|
}
|
|
|
|
//
|
|
this.storageService.write(XSettingsStorageKey.Locale, storedLocale, true);
|
|
|
|
//
|
|
//#region Handle Ui Directions based on Current Locale ...
|
|
document.documentElement.lang = this.localizationService.language;
|
|
document.documentElement.dir = this.localizationService.direction;
|
|
|
|
//
|
|
this.setTitle();
|
|
|
|
//
|
|
// Document CSS ...
|
|
document.body.style.setProperty(
|
|
this.prepareCssKey('ui-direction'),
|
|
this.localizationService.direction
|
|
);
|
|
|
|
//
|
|
const isRtl = this.localizationService.direction === 'rtl';
|
|
document.body.style.setProperty(
|
|
this.prepareCssKey('is-rtl'),
|
|
isRtl.toString()
|
|
);
|
|
//#endregion
|
|
}
|
|
|
|
private prepareDeviceInfo() {
|
|
//
|
|
//#region Generate Device Info ...
|
|
//
|
|
// Reading Device Specifications ...
|
|
const deviceOs = this.deviceService.os;
|
|
const deviceBrowser = this.deviceService.browser;
|
|
const deviceOsVersion = this.deviceService.os_version;
|
|
const deviceUserAgent = this.deviceService.userAgent;
|
|
|
|
//
|
|
// Generating Device Type ...
|
|
let mDeviceType: XDeviceTypes;
|
|
if (this.deviceService.isDesktop()) {
|
|
mDeviceType = XDeviceTypes.Desktop;
|
|
} else if (this.deviceService.isTablet()) {
|
|
mDeviceType = XDeviceTypes.Tablet;
|
|
} else if (this.deviceService.isMobile()) {
|
|
mDeviceType = XDeviceTypes.Mobile;
|
|
} else {
|
|
mDeviceType = XDeviceTypes.Unknown;
|
|
}
|
|
|
|
//
|
|
// Generating Device Identifier and it's token ...
|
|
const deviceIdentifier = `[${deviceOs}]-[${deviceOsVersion}]-[${mDeviceType}]-[${deviceBrowser}]-[${deviceUserAgent}]`;
|
|
const deviceToken = Md5.init(deviceIdentifier);
|
|
|
|
//
|
|
this.DEVICE_INFO = {
|
|
os: deviceOs,
|
|
browser: deviceBrowser,
|
|
osVersion: deviceOsVersion,
|
|
userAgent: deviceUserAgent,
|
|
deviceType: mDeviceType,
|
|
identifier: deviceIdentifier,
|
|
token: deviceToken,
|
|
};
|
|
//#endregion
|
|
}
|
|
|
|
private defineUiBreakPointObservers() {
|
|
//
|
|
//#region define objservable ...
|
|
this.isPortrait$ = this.breakPointObserver
|
|
.observe([
|
|
Breakpoints.WebPortrait,
|
|
Breakpoints.TabletPortrait,
|
|
Breakpoints.HandsetPortrait,
|
|
])
|
|
.pipe(map((breakPointState: BreakpointState) => breakPointState.matches));
|
|
|
|
//
|
|
this.isLandscape$ = this.breakPointObserver
|
|
.observe([
|
|
Breakpoints.WebLandscape,
|
|
Breakpoints.TabletLandscape,
|
|
Breakpoints.HandsetLandscape,
|
|
])
|
|
.pipe(map((breakPointState: BreakpointState) => breakPointState.matches));
|
|
|
|
//
|
|
this.orientation$ = this.breakPointObserver
|
|
.observe([
|
|
Breakpoints.WebPortrait,
|
|
Breakpoints.TabletPortrait,
|
|
Breakpoints.HandsetPortrait,
|
|
Breakpoints.WebLandscape,
|
|
Breakpoints.TabletLandscape,
|
|
Breakpoints.HandsetLandscape,
|
|
])
|
|
.pipe(
|
|
map(() => {
|
|
if (
|
|
this.breakPointObserver.isMatched([
|
|
Breakpoints.WebPortrait,
|
|
Breakpoints.TabletPortrait,
|
|
Breakpoints.HandsetPortrait,
|
|
])
|
|
) {
|
|
return 'portrait';
|
|
} else {
|
|
return 'landscape';
|
|
}
|
|
})
|
|
);
|
|
|
|
//
|
|
this.isXSmall$ = this.breakPointObserver
|
|
.observe(Breakpoints.XSmall)
|
|
.pipe(map((breakPointState: BreakpointState) => breakPointState.matches));
|
|
|
|
//
|
|
this.isSmall$ = this.breakPointObserver
|
|
.observe(Breakpoints.Small)
|
|
.pipe(map((breakPointState: BreakpointState) => breakPointState.matches));
|
|
|
|
//
|
|
this.isMedium$ = this.breakPointObserver
|
|
.observe(Breakpoints.Medium)
|
|
.pipe(map((breakPointState: BreakpointState) => breakPointState.matches));
|
|
|
|
//
|
|
this.isLarge$ = this.breakPointObserver
|
|
.observe(Breakpoints.Large)
|
|
.pipe(map((breakPointState: BreakpointState) => breakPointState.matches));
|
|
|
|
//
|
|
this.isXLarge$ = this.breakPointObserver
|
|
.observe(Breakpoints.XLarge)
|
|
.pipe(map((breakPointState: BreakpointState) => breakPointState.matches));
|
|
|
|
//
|
|
this.isTablet$ = this.breakPointObserver
|
|
.observe(Breakpoints.Tablet)
|
|
.pipe(map((breakPointState: BreakpointState) => breakPointState.matches));
|
|
|
|
//
|
|
this.isWeb$ = this.breakPointObserver
|
|
.observe(Breakpoints.Web)
|
|
.pipe(map((breakPointState: BreakpointState) => breakPointState.matches));
|
|
|
|
//
|
|
this.isMobile$ = this.breakPointObserver
|
|
.observe('(max-width: 768px)')
|
|
.pipe(map((breakPointState: BreakpointState) => breakPointState.matches));
|
|
//#endregion
|
|
}
|
|
|
|
private handleThemeMetaTags() {
|
|
//
|
|
//#region Handle Metas for Theme ...
|
|
const darkPrimaryColor = this.readCssProperty('x-app-bar-color');
|
|
this.addTag(
|
|
{
|
|
name: 'theme-color',
|
|
content: darkPrimaryColor,
|
|
},
|
|
true
|
|
);
|
|
this.addTag(
|
|
{
|
|
name: 'msapplication-navbutton-color',
|
|
content: darkPrimaryColor,
|
|
},
|
|
true
|
|
);
|
|
this.addTag(
|
|
{
|
|
name: 'apple-mobile-web-app-capable',
|
|
content: 'yes',
|
|
},
|
|
true
|
|
);
|
|
this.addTag(
|
|
{
|
|
name: 'apple-mobile-web-app-status-bar-style',
|
|
content: darkPrimaryColor,
|
|
},
|
|
true
|
|
);
|
|
//#endregion
|
|
}
|
|
|
|
private prepareCssKey(key: XCssProperties) {
|
|
return `${this.PREFIX}${key}`;
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-storage.service.ts
|
|
|
|
import {
|
|
fromJson,
|
|
XStorageItem,
|
|
XBaseService,
|
|
XExceptionIDs,
|
|
throwException,
|
|
isNullOrUndefined
|
|
} from 'x-framework-core';
|
|
import { Injectable, Inject } from '@angular/core';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class XStorageService extends XBaseService {
|
|
//
|
|
private keyPrefix: string;
|
|
|
|
//
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG) config: XFrameworkServicesConfig
|
|
) {
|
|
super(config);
|
|
|
|
//
|
|
if (isNullOrUndefined(typeof Storage)) {
|
|
throwException(XExceptionIDs.StorageNotSupported);
|
|
}
|
|
|
|
//
|
|
this.keyPrefix = `${config.appInstanceName}`;
|
|
}
|
|
|
|
/**
|
|
* determine a key exists in storage or not ...
|
|
* @param key the item key
|
|
*/
|
|
isExists(key: string) {
|
|
//
|
|
const theKey = this.getPreparedKey(key);
|
|
const result = localStorage.getItem(theKey) !== null;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* writing a new item in Storage ...
|
|
*
|
|
* @param key the item key
|
|
* @param data the data object which needs to save
|
|
* @param forceRewrite overwrite item if exists, the default is false,
|
|
* means if key exists throws an error ...
|
|
*/
|
|
write(key: string, data: any, forceRewrite: boolean = false) {
|
|
//
|
|
if (!forceRewrite && this.isExists(key)) {
|
|
throwException(XExceptionIDs.Duplicate);
|
|
}
|
|
|
|
//
|
|
const theKey = this.getPreparedKey(key);
|
|
localStorage.setItem(theKey, JSON.stringify(data));
|
|
}
|
|
|
|
/**
|
|
* read an item from Storage ...
|
|
* @param key the item key
|
|
* @param forceExists determine the given key must be exists or not, true is default,
|
|
* means if key not exists throws an error ...
|
|
*/
|
|
read(key: string, forceExists: boolean = true): any | null {
|
|
//
|
|
if (forceExists && !this.isExists(key)) {
|
|
throwException(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
const theKey = this.getPreparedKey(key);
|
|
const item = localStorage.getItem(theKey);
|
|
if (!isNullOrUndefined(item)) {
|
|
try {
|
|
return JSON.parse(item);
|
|
} catch {}
|
|
}
|
|
|
|
//
|
|
return null;
|
|
}
|
|
readOfType<T>(key: string, forceExists: boolean = true): T | null {
|
|
//
|
|
if (!this.isExists(key)) {
|
|
//
|
|
if (forceExists) {
|
|
throwException(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const valStr = this.read(key, forceExists);
|
|
return fromJson<T>(valStr);
|
|
}
|
|
|
|
/**
|
|
* remove an stored item from Storage ...
|
|
* @param key the item key
|
|
* @param forceExists determine the given key must be exists or not, true is default,
|
|
* means if key not exists throws an error ...
|
|
*/
|
|
remove(key: string, forceExists: boolean = true) {
|
|
//
|
|
if (forceExists && !this.isExists(key)) {
|
|
throwException(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
const theKey = this.getPreparedKey(key);
|
|
localStorage.removeItem(theKey);
|
|
}
|
|
|
|
/**
|
|
* get a List of Stored items as an Array of StorageItem ...
|
|
* @param force true is defualt, means only return list of items
|
|
* from Storage which Stored by Service ...
|
|
*/
|
|
list(force: boolean = true): XStorageItem[] | null {
|
|
//
|
|
if (localStorage.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const items: XStorageItem[] = [];
|
|
for (let i = 0; i < localStorage.length; i++) {
|
|
//
|
|
const mKey = localStorage.key(i);
|
|
|
|
//
|
|
if (force) {
|
|
const theRawKey = this.getRawKey(mKey);
|
|
if (!isNullOrUndefined(theRawKey)) {
|
|
//
|
|
items.push({
|
|
key: theRawKey,
|
|
value: localStorage.getItem(mKey)
|
|
});
|
|
}
|
|
} else {
|
|
//
|
|
items.push({
|
|
key: mKey,
|
|
value: localStorage.getItem(mKey)
|
|
});
|
|
}
|
|
}
|
|
|
|
//
|
|
return items;
|
|
}
|
|
|
|
/**
|
|
* get the number of items which stored in Storage ...
|
|
* @param force true is defualt, means only return number of items
|
|
* from Storage which Stored by Service ...
|
|
*/
|
|
length(force: boolean = true) {
|
|
//
|
|
if (force) {
|
|
return this.list().length;
|
|
}
|
|
|
|
//
|
|
return localStorage.length;
|
|
}
|
|
|
|
/**
|
|
* clear all items from Storage ...
|
|
* @param force true is defualt, means only clear items
|
|
* from Storage which Stored by Service ...
|
|
*/
|
|
clear(force: boolean = true) {
|
|
localStorage.clear();
|
|
}
|
|
|
|
protected getPreparedKey(key: string) {
|
|
return `${this.keyPrefix}_${key}`;
|
|
}
|
|
|
|
protected getRawKey(key: string): string | null {
|
|
//
|
|
const baseKeySubstr = `${this.keyPrefix}_`;
|
|
if (key.indexOf(baseKeySubstr) === -1) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return key.replace(baseKeySubstr, '');
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-task-manager.service.ts
|
|
|
|
import {
|
|
XTask,
|
|
XException,
|
|
XBaseService,
|
|
XTaskPriority,
|
|
isValidException,
|
|
getErrorException,
|
|
} from 'x-framework-core';
|
|
import { Injectable, Inject } from '@angular/core';
|
|
import { concatMap, catchError, tap } from 'rxjs/operators';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { Subscription, Subject, BehaviorSubject, of, throwError } from 'rxjs';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XTaskManagerService extends XBaseService {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
subscription: Subscription;
|
|
|
|
//
|
|
// Notify loading ...
|
|
public allTasksFinished = new Subject();
|
|
public loading = new BehaviorSubject<boolean>(false);
|
|
|
|
//
|
|
// notify Specific Task Start or Finished ...
|
|
public taskStart = new Subject<XTask<any>>();
|
|
public taskError = new Subject<XTask<any>>();
|
|
public taskFinished = new Subject<XTask<any>>();
|
|
|
|
//
|
|
private isPaused = false;
|
|
private isStarted = false;
|
|
private tasks = new Map<string, XTask<any>>();
|
|
private taskQueue = new Subject<XTask<any>>();
|
|
|
|
/**
|
|
* retrieve a Collection of Tasks which Pending to run ...
|
|
*/
|
|
get taskList() {
|
|
return this.getSortedTasksLists();
|
|
}
|
|
|
|
/**
|
|
* retrieve Running State of Tasks ...
|
|
*/
|
|
get paused() {
|
|
return this.isPaused;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG) config: XFrameworkServicesConfig
|
|
) {
|
|
super(config);
|
|
|
|
//
|
|
// Register Task Queue Runner ...
|
|
this.taskQueue.asObservable().subscribe((t) => {
|
|
this.handleTaskRun(t);
|
|
});
|
|
|
|
//
|
|
this.allTasksFinished.asObservable().subscribe(() => {
|
|
this.loading.next(false);
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
/**
|
|
* determines a Tasks is in Pending List or not ...
|
|
*/
|
|
has(taskName: string) {
|
|
return this.tasks.has(taskName);
|
|
}
|
|
|
|
/**
|
|
* delete a task from Pending List ...
|
|
*/
|
|
delete(taskName: string) {
|
|
return this.tasks.delete(taskName);
|
|
}
|
|
|
|
/**
|
|
* add a Task to Pending List ...
|
|
*/
|
|
add<T>(task: XTask<T>) {
|
|
//
|
|
// Prevent Duplicate ...
|
|
if (this.has(task.name)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// add Task to Pending List ...
|
|
this.tasks.set(task.name, task);
|
|
|
|
//
|
|
// Start Running if it's not Started Before ...
|
|
if (!this.isStarted) {
|
|
this.requestNext();
|
|
}
|
|
|
|
//
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Change Specific Tasks Priority ...
|
|
*/
|
|
changePriority(taskName: string, priority: XTaskPriority) {
|
|
//
|
|
if (!this.has(taskName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.tasks.get(taskName).priority = priority;
|
|
}
|
|
|
|
/**
|
|
* Count Pending List Tasks ...
|
|
*/
|
|
count() {
|
|
return this.tasks.size;
|
|
}
|
|
|
|
/**
|
|
* Remove All Pending List Task ...
|
|
*/
|
|
clear() {
|
|
this.isStarted = false;
|
|
this.tasks.clear();
|
|
}
|
|
|
|
/**
|
|
* Pause Running of Tasks ...
|
|
*/
|
|
pause() {
|
|
this.isPaused = true;
|
|
}
|
|
|
|
/**
|
|
* Continue Running Pending Tasks ...
|
|
*/
|
|
continue() {
|
|
//
|
|
if (!this.isPaused) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.isPaused = false;
|
|
this.requestNext();
|
|
}
|
|
|
|
/**
|
|
* Toggle Pause/Continue Tasks Running ...
|
|
*/
|
|
toggle() {
|
|
//
|
|
if (this.isPaused) {
|
|
this.continue();
|
|
} else {
|
|
this.pause();
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private requestNext() {
|
|
//
|
|
if (this.isPaused) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const task = this.popTask();
|
|
|
|
//
|
|
if (task) {
|
|
//
|
|
this.isStarted = true;
|
|
this.taskQueue.next(task);
|
|
} else {
|
|
//
|
|
this.isStarted = false;
|
|
if (this.tasks.size === 0) {
|
|
//
|
|
this.loading.next(false);
|
|
this.allTasksFinished.next();
|
|
}
|
|
}
|
|
}
|
|
|
|
private popTask() {
|
|
//
|
|
const result = this.getSortedTasksLists().pop() || null;
|
|
|
|
//
|
|
if (result) {
|
|
this.tasks.delete(result.name);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private getSortedTasksLists() {
|
|
//
|
|
return Array.from(this.tasks.values())
|
|
.sort((a, b) => a.priority - b.priority)
|
|
.reverse();
|
|
}
|
|
|
|
private applyWrapperToTask(task: XTask<any>) {
|
|
//
|
|
return of(task).pipe(
|
|
concatMap((res) => {
|
|
//
|
|
if (res.affectLoading) {
|
|
this.loading.next(true);
|
|
}
|
|
|
|
//
|
|
this.taskStart.next(res);
|
|
|
|
//
|
|
return res.task.pipe(
|
|
catchError((err) => {
|
|
//
|
|
this.isStarted = false;
|
|
this.loading.next(false);
|
|
|
|
//
|
|
res.error = getErrorException(err);
|
|
|
|
//
|
|
if (isValidException(err.error)) {
|
|
res.error = err.error as XException;
|
|
}
|
|
|
|
//
|
|
this.taskError.next(res);
|
|
|
|
//
|
|
this.handleUnSubscribe();
|
|
return throwError(res.error);
|
|
}),
|
|
tap((tRes) => {
|
|
//
|
|
this.isStarted = false;
|
|
this.loading.next(false);
|
|
|
|
//
|
|
res.result = tRes;
|
|
this.taskFinished.next(res);
|
|
|
|
//
|
|
this.handleUnSubscribe();
|
|
this.requestNext();
|
|
})
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
private handleTaskRun(task: XTask<any>) {
|
|
//
|
|
const mXTObs = this.applyWrapperToTask(task);
|
|
|
|
//
|
|
this.subscription = mXTObs.subscribe(
|
|
(_) => {},
|
|
(_) => {}
|
|
);
|
|
}
|
|
|
|
private handleUnSubscribe() {
|
|
//
|
|
if (this.subscription) {
|
|
//
|
|
this.subscription.unsubscribe();
|
|
this.subscription = null;
|
|
}
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-theme-manager.service.ts
|
|
|
|
import {
|
|
keys,
|
|
hasChild,
|
|
XThemeType,
|
|
XThemePack,
|
|
XThemeColors,
|
|
downloadFile,
|
|
XBaseService,
|
|
XExceptionIDs,
|
|
XThemeCssVars,
|
|
toNormalString,
|
|
isNullOrUndefined,
|
|
isNullOrEmptyString,
|
|
XExceptionIdentifier,
|
|
XThemeTypeIdentifier,
|
|
XThemeCssVarsIdentifier,
|
|
} from 'x-framework-core';
|
|
import { XStorageService } from './x-storage.service';
|
|
import { XSettingsService } from './x-settings.service';
|
|
import { XNotificationService } from './x-notification.service';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from './tokens/x-injectable-tokens';
|
|
import { Injectable, Inject, EventEmitter, ElementRef } from '@angular/core';
|
|
import { XFrameworkServicesConfig } from './config/x-framework-services.config';
|
|
|
|
const XThemeManagerStorageKeys = {
|
|
CurrentTheme: 'current_theme',
|
|
CurrentThemeType: 'current_theme_type',
|
|
Themes: 'themes',
|
|
};
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class XThemeManagerService extends XBaseService {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
private PREFIX = '--';
|
|
readonly ColorCssVars = Object.assign({}, XThemeCssVars);
|
|
|
|
//
|
|
notifyChanges = new EventEmitter<void>();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG)
|
|
public config: XFrameworkServicesConfig,
|
|
private storageService: XStorageService,
|
|
private settingsService: XSettingsService,
|
|
private notificationService: XNotificationService
|
|
) {
|
|
//
|
|
super(config);
|
|
|
|
//
|
|
this.initializeService();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Actions ...
|
|
async applyCurrentTheme(element?: ElementRef) {
|
|
//
|
|
const currentTheme = await this.getCurrentTheme();
|
|
const isDefaultThemeExists = !isNullOrUndefined(currentTheme);
|
|
if (isDefaultThemeExists) {
|
|
//
|
|
const type = await this.getCurrentThemeType();
|
|
await this.setTheme(currentTheme, type, false, false, element);
|
|
|
|
//
|
|
this.notifyChanges.emit();
|
|
}
|
|
}
|
|
|
|
async getCurrentThemeName() {
|
|
//
|
|
const mKey = XThemeManagerStorageKeys.CurrentTheme;
|
|
|
|
//
|
|
const isExists = this.storageService.isExists(mKey);
|
|
if (!isExists) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
const result = this.storageService.readOfType<string>(mKey);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
async setCurrentThemeName(themeName: string, notifyChanges: boolean = true) {
|
|
//
|
|
const isExists = await this.isThemeExists(themeName);
|
|
if (!isExists) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const mKey = XThemeManagerStorageKeys.CurrentTheme;
|
|
|
|
//
|
|
this.storageService.write(mKey, themeName, true);
|
|
|
|
//
|
|
if (notifyChanges) {
|
|
//
|
|
this.notifyChanges.emit();
|
|
await this.issueSuccessNotification();
|
|
}
|
|
|
|
//
|
|
return true;
|
|
}
|
|
|
|
async getCurrentThemeType() {
|
|
//
|
|
const mKey = XThemeManagerStorageKeys.CurrentThemeType;
|
|
|
|
//
|
|
const isExists = this.storageService.isExists(mKey);
|
|
if (!isExists) {
|
|
return XThemeType.Light;
|
|
}
|
|
|
|
//
|
|
const result = this.storageService.readOfType<XThemeTypeIdentifier>(mKey);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
async setCurrentThemeType(
|
|
themeType: XThemeTypeIdentifier,
|
|
notifyChanges: boolean = true
|
|
) {
|
|
//
|
|
if (isNullOrEmptyString(themeType)) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.InvalidArgs);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const mKey = XThemeManagerStorageKeys.CurrentThemeType;
|
|
|
|
//
|
|
this.storageService.write(mKey, themeType, true);
|
|
|
|
//
|
|
if (notifyChanges) {
|
|
//
|
|
this.notifyChanges.emit();
|
|
await this.issueSuccessNotification();
|
|
}
|
|
|
|
//
|
|
return true;
|
|
}
|
|
|
|
async setTheme(
|
|
theme: XThemePack,
|
|
whichType: XThemeTypeIdentifier = XThemeType.Light,
|
|
notifyChanges: boolean = true,
|
|
restart: boolean = true,
|
|
element?: ElementRef
|
|
) {
|
|
//
|
|
if (isNullOrUndefined(theme)) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.InvalidArgs);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const isExists = await this.isThemeExists(theme.name);
|
|
if (!isExists) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
let result = false;
|
|
switch (whichType) {
|
|
//
|
|
case XThemeType.Light:
|
|
result = await this.setThemeColors(theme.light.colors, element);
|
|
break;
|
|
|
|
//
|
|
case XThemeType.Dark:
|
|
result = await this.setThemeColors(theme.dark.colors, element);
|
|
break;
|
|
}
|
|
|
|
//
|
|
if (result) {
|
|
//
|
|
await this.setCurrentThemeType(whichType, false);
|
|
await this.setCurrentThemeName(theme.name, false);
|
|
}
|
|
|
|
//
|
|
if (result && notifyChanges) {
|
|
//
|
|
this.notifyChanges.emit();
|
|
await this.issueSuccessNotification();
|
|
}
|
|
|
|
//
|
|
if (result && restart) {
|
|
this.settingsService.restart();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
async cloneTheme(
|
|
themeName: string,
|
|
clonedThemeName: string,
|
|
notifyChanges: boolean = true
|
|
) {
|
|
//
|
|
const isExists = await this.isThemeExists(themeName);
|
|
if (!isExists) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const isClonedThemeNameReserved = await this.isThemeExists(clonedThemeName);
|
|
if (isClonedThemeNameReserved) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.Duplicate);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const theme = await this.getTheme(themeName);
|
|
if (!theme) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
theme.name = clonedThemeName;
|
|
const result = await this.saveTheme(theme, false);
|
|
|
|
//
|
|
if (result && notifyChanges) {
|
|
this.notifyChanges.emit();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
async exportTheme(themeName: string) {
|
|
//
|
|
if (isNullOrEmptyString(themeName)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const theme = await this.getTheme(themeName);
|
|
if (isNullOrUndefined(theme)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const theJSON = JSON.stringify(theme);
|
|
|
|
//
|
|
downloadFile(theJSON, 'text/json', `x-framework-${theme.name}-theme.json`);
|
|
}
|
|
|
|
async removeTheme(themeName: string, notifyChanges: boolean = true) {
|
|
//
|
|
const isExists = await this.isThemeExists(themeName);
|
|
if (!isExists) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const currentThemeName = await this.getCurrentThemeName();
|
|
if (!currentThemeName) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const themes = await this.getThemes();
|
|
if (!hasChild(themes) || themes.length === 1) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const filteredThemes = themes.filter(
|
|
(th) => toNormalString(th.name) !== toNormalString(themeName)
|
|
);
|
|
|
|
//
|
|
let result = false;
|
|
try {
|
|
//
|
|
result = true;
|
|
this.writeThemes(filteredThemes);
|
|
} catch {
|
|
result = false;
|
|
}
|
|
|
|
//
|
|
const isCurrentRemoved =
|
|
toNormalString(currentThemeName) === toNormalString(themeName);
|
|
if (isCurrentRemoved) {
|
|
//
|
|
const newCurrentTheme = filteredThemes[0];
|
|
const themeType = await this.getCurrentThemeType();
|
|
result = await this.setTheme(newCurrentTheme, themeType, false, false);
|
|
}
|
|
|
|
//
|
|
if (result && notifyChanges) {
|
|
//
|
|
this.notifyChanges.emit();
|
|
await this.issueSuccessNotification();
|
|
}
|
|
|
|
//
|
|
if (result && isCurrentRemoved) {
|
|
this.settingsService.restart();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
async saveTheme(theme: XThemePack, notifyChanges: boolean = true) {
|
|
//
|
|
if (isNullOrUndefined(theme)) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.InvalidArgs);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const isExists = await this.isThemeExists(theme.name);
|
|
if (isExists) {
|
|
//
|
|
if (notifyChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.Duplicate);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const themeType = await this.getCurrentThemeType();
|
|
|
|
//
|
|
const themes = await this.getThemes();
|
|
if (!hasChild(themes)) {
|
|
//
|
|
const newThemes = [theme];
|
|
|
|
//
|
|
this.writeThemes(newThemes);
|
|
|
|
//
|
|
const result = await this.setTheme(theme, themeType, true);
|
|
return result;
|
|
} else {
|
|
//
|
|
const themeIndex = themes.findIndex((th) => th.name === theme.name);
|
|
if (themeIndex === -1) {
|
|
themes.push(theme);
|
|
} else {
|
|
themes[themeIndex] = theme;
|
|
}
|
|
|
|
//
|
|
this.writeThemes(themes);
|
|
|
|
//
|
|
if (notifyChanges) {
|
|
//
|
|
this.notifyChanges.emit();
|
|
await this.issueSuccessNotification();
|
|
}
|
|
|
|
//
|
|
return true;
|
|
}
|
|
}
|
|
|
|
async updateTheme(
|
|
themeName: string,
|
|
updatedTheme: XThemePack,
|
|
notifiChanges: boolean = true,
|
|
restartIfCurrent: boolean = true
|
|
) {
|
|
//
|
|
if (isNullOrEmptyString(themeName) || isNullOrUndefined(updatedTheme)) {
|
|
//
|
|
if (notifiChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.InvalidArgs);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const isExists = await this.isThemeExists(themeName);
|
|
if (!isExists) {
|
|
//
|
|
if (notifiChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const currentThemeName = await this.getCurrentThemeName();
|
|
const isCurrent =
|
|
toNormalString(themeName) === toNormalString(currentThemeName);
|
|
|
|
//
|
|
let result = false;
|
|
const themes = this.readThemes();
|
|
const themeIndex = themes.findIndex(
|
|
(th) => toNormalString(th.name) === toNormalString(themeName)
|
|
);
|
|
if (themeIndex < 0) {
|
|
//
|
|
if (notifiChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.NotFound);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
themes[themeIndex] = updatedTheme;
|
|
try {
|
|
result = true;
|
|
this.writeThemes(themes);
|
|
} catch {
|
|
//
|
|
if (notifiChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.ActionFailed);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
|
|
//
|
|
if (result && isCurrent) {
|
|
//
|
|
const mode = await this.getCurrentThemeType();
|
|
const isSetted = await this.setTheme(updatedTheme, mode, false, false);
|
|
if (!isSetted) {
|
|
//
|
|
if (notifiChanges) {
|
|
await this.issueFailedNotification(XExceptionIDs.ActionFailed);
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (result && notifiChanges) {
|
|
await this.issueSuccessNotification();
|
|
}
|
|
|
|
//
|
|
if (isCurrent && restartIfCurrent) {
|
|
this.settingsService.restart();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
async getCurrentTheme() {
|
|
//
|
|
const currentThemeName = await this.getCurrentThemeName();
|
|
const isExists = await this.isThemeExists(currentThemeName);
|
|
if (!isExists) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const result = await this.getTheme(currentThemeName);
|
|
return result;
|
|
}
|
|
|
|
async getThemeNames() {
|
|
//
|
|
const themes = await this.getThemes();
|
|
if (!hasChild(themes)) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
return themes.map((th) => th.name);
|
|
}
|
|
|
|
async getThemes() {
|
|
//
|
|
const result = this.readThemes();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
async getTheme(themeName: string) {
|
|
//
|
|
const isExists = await this.isThemeExists(themeName);
|
|
if (!isExists) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
const themes = await this.getThemes();
|
|
return themes.find(
|
|
(th) => toNormalString(th.name) === toNormalString(themeName)
|
|
);
|
|
}
|
|
|
|
async isThemeExists(themeName: string) {
|
|
//
|
|
if (isNullOrEmptyString(themeName)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const themes = await this.getThemeNames();
|
|
const result =
|
|
themes.findIndex(
|
|
(th) => toNormalString(th) === toNormalString(themeName)
|
|
) > -1;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
async setLightMode() {
|
|
//
|
|
const currentTheme = await this.getCurrentTheme();
|
|
if (isNullOrUndefined(currentTheme)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return await this.setTheme(currentTheme, XThemeType.Light, false, true);
|
|
}
|
|
|
|
async setDarkMode() {
|
|
//
|
|
const currentTheme = await this.getCurrentTheme();
|
|
if (isNullOrUndefined(currentTheme)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return await this.setTheme(currentTheme, XThemeType.Dark, false, true);
|
|
}
|
|
|
|
async toggleMode() {
|
|
//
|
|
const currentTheme = await this.getCurrentTheme();
|
|
const currentThemeMode = await this.getCurrentThemeType();
|
|
if (isNullOrUndefined(currentTheme)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const mode: XThemeType =
|
|
currentThemeMode === XThemeType.Light
|
|
? XThemeType.Dark
|
|
: XThemeType.Light;
|
|
|
|
//
|
|
return await this.setTheme(currentTheme, mode, false, true);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private async initializeService() {
|
|
//
|
|
const currentTheme = await this.getCurrentTheme();
|
|
const isDefaultThemeExists = !isNullOrUndefined(currentTheme);
|
|
if (!isDefaultThemeExists) {
|
|
//
|
|
const defaultTheme: XThemePack = {
|
|
name: 'default',
|
|
light: {
|
|
type: XThemeType.Light,
|
|
colors: {
|
|
//
|
|
//#region Primary ...
|
|
//
|
|
XColorPrimary: this.getCssVar(XThemeCssVars.XColorPrimary),
|
|
XColorPrimaryContrast: this.getCssVar(
|
|
XThemeCssVars.XColorPrimaryContrast
|
|
),
|
|
|
|
//
|
|
XColorPrimaryShade: this.getCssVar(
|
|
XThemeCssVars.XColorPrimaryShade
|
|
),
|
|
XColorPrimaryShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorPrimaryShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorPrimaryTint: this.getCssVar(XThemeCssVars.XColorPrimaryTint),
|
|
XColorPrimaryTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorPrimaryTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Secondary ...
|
|
//
|
|
XColorSecondary: this.getCssVar(XThemeCssVars.XColorSecondary),
|
|
XColorSecondaryContrast: this.getCssVar(
|
|
XThemeCssVars.XColorSecondaryContrast
|
|
),
|
|
|
|
//
|
|
XColorSecondaryShade: this.getCssVar(
|
|
XThemeCssVars.XColorSecondaryShade
|
|
),
|
|
XColorSecondaryShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorSecondaryShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorSecondaryTint: this.getCssVar(
|
|
XThemeCssVars.XColorSecondaryTint
|
|
),
|
|
XColorSecondaryTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorSecondaryTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Tertiary ...
|
|
//
|
|
XColorTertiary: this.getCssVar(XThemeCssVars.XColorTertiary),
|
|
XColorTertiaryContrast: this.getCssVar(
|
|
XThemeCssVars.XColorTertiaryContrast
|
|
),
|
|
|
|
//
|
|
XColorTertiaryShade: this.getCssVar(
|
|
XThemeCssVars.XColorTertiaryShade
|
|
),
|
|
XColorTertiaryShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorTertiaryShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorTertiaryTint: this.getCssVar(
|
|
XThemeCssVars.XColorTertiaryTint
|
|
),
|
|
XColorTertiaryTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorTertiaryTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Success ...
|
|
//
|
|
XColorSuccess: this.getCssVar(XThemeCssVars.XColorSuccess),
|
|
XColorSuccessContrast: this.getCssVar(
|
|
XThemeCssVars.XColorSuccessContrast
|
|
),
|
|
|
|
//
|
|
XColorSuccessShade: this.getCssVar(
|
|
XThemeCssVars.XColorSuccessShade
|
|
),
|
|
XColorSuccessShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorSuccessShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorSuccessTint: this.getCssVar(XThemeCssVars.XColorSuccessTint),
|
|
XColorSuccessTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorSuccessTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Warning ...
|
|
//
|
|
XColorWarning: this.getCssVar(XThemeCssVars.XColorWarning),
|
|
XColorWarningContrast: this.getCssVar(
|
|
XThemeCssVars.XColorWarningContrast
|
|
),
|
|
|
|
//
|
|
XColorWarningShade: this.getCssVar(
|
|
XThemeCssVars.XColorWarningShade
|
|
),
|
|
XColorWarningShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorWarningShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorWarningTint: this.getCssVar(XThemeCssVars.XColorWarningTint),
|
|
XColorWarningTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorWarningTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Danger ...
|
|
//
|
|
XColorDanger: this.getCssVar(XThemeCssVars.XColorDanger),
|
|
XColorDangerContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDangerContrast
|
|
),
|
|
|
|
//
|
|
XColorDangerShade: this.getCssVar(XThemeCssVars.XColorDangerShade),
|
|
XColorDangerShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDangerShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorDangerTint: this.getCssVar(XThemeCssVars.XColorDangerTint),
|
|
XColorDangerTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDangerTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Dark ...
|
|
//
|
|
XColorDark: this.getCssVar(XThemeCssVars.XColorDark),
|
|
XColorDarkContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkContrast
|
|
),
|
|
|
|
//
|
|
XColorDarkShade: this.getCssVar(XThemeCssVars.XColorDarkShade),
|
|
XColorDarkShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorDarkTint: this.getCssVar(XThemeCssVars.XColorDarkTint),
|
|
XColorDarkTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Medium ...
|
|
//
|
|
XColorMedium: this.getCssVar(XThemeCssVars.XColorMedium),
|
|
XColorMediumContrast: this.getCssVar(
|
|
XThemeCssVars.XColorMediumContrast
|
|
),
|
|
|
|
//
|
|
XColorMediumShade: this.getCssVar(XThemeCssVars.XColorMediumShade),
|
|
XColorMediumShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorMediumShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorMediumTint: this.getCssVar(XThemeCssVars.XColorMediumTint),
|
|
XColorMediumTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorMediumTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Light ...
|
|
//
|
|
XColorLight: this.getCssVar(XThemeCssVars.XColorLight),
|
|
XColorLightContrast: this.getCssVar(
|
|
XThemeCssVars.XColorLightContrast
|
|
),
|
|
|
|
//
|
|
XColorLightShade: this.getCssVar(XThemeCssVars.XColorLightShade),
|
|
XColorLightShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorLightShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorLightTint: this.getCssVar(XThemeCssVars.XColorLightTint),
|
|
XColorLightTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorLightTintContrast
|
|
),
|
|
//#endregion
|
|
},
|
|
},
|
|
dark: {
|
|
type: XThemeType.Dark,
|
|
colors: {
|
|
//
|
|
//#region Primary ...
|
|
//
|
|
XColorPrimary: this.getCssVar(XThemeCssVars.XColorDark),
|
|
XColorPrimaryContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkContrast
|
|
),
|
|
|
|
//
|
|
XColorPrimaryShade: this.getCssVar(XThemeCssVars.XColorDarkShade),
|
|
XColorPrimaryShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorPrimaryTint: this.getCssVar(XThemeCssVars.XColorDarkTint),
|
|
XColorPrimaryTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Secondary ...
|
|
//
|
|
XColorSecondary: this.getCssVar(XThemeCssVars.XColorDarkTint),
|
|
XColorSecondaryContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkTintContrast
|
|
),
|
|
|
|
//
|
|
XColorSecondaryShade: this.getCssVar(XThemeCssVars.XColorDarkTint),
|
|
XColorSecondaryShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkTintContrast
|
|
),
|
|
|
|
//
|
|
XColorSecondaryTint: this.getCssVar(XThemeCssVars.XColorDarkTint),
|
|
XColorSecondaryTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Tertiary ...
|
|
//
|
|
XColorTertiary: this.getCssVar(XThemeCssVars.XColorTertiary),
|
|
XColorTertiaryContrast: this.getCssVar(
|
|
XThemeCssVars.XColorTertiaryContrast
|
|
),
|
|
|
|
//
|
|
XColorTertiaryShade: this.getCssVar(
|
|
XThemeCssVars.XColorTertiaryShade
|
|
),
|
|
XColorTertiaryShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorTertiaryShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorTertiaryTint: this.getCssVar(
|
|
XThemeCssVars.XColorTertiaryTint
|
|
),
|
|
XColorTertiaryTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorTertiaryTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Success ...
|
|
//
|
|
XColorSuccess: this.getCssVar(XThemeCssVars.XColorSuccess),
|
|
XColorSuccessContrast: this.getCssVar(
|
|
XThemeCssVars.XColorSuccessContrast
|
|
),
|
|
|
|
//
|
|
XColorSuccessShade: this.getCssVar(
|
|
XThemeCssVars.XColorSuccessShade
|
|
),
|
|
XColorSuccessShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorSuccessShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorSuccessTint: this.getCssVar(XThemeCssVars.XColorSuccessTint),
|
|
XColorSuccessTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorSuccessTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Warning ...
|
|
//
|
|
XColorWarning: this.getCssVar(XThemeCssVars.XColorWarning),
|
|
XColorWarningContrast: this.getCssVar(
|
|
XThemeCssVars.XColorWarningContrast
|
|
),
|
|
|
|
//
|
|
XColorWarningShade: this.getCssVar(
|
|
XThemeCssVars.XColorWarningShade
|
|
),
|
|
XColorWarningShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorWarningShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorWarningTint: this.getCssVar(XThemeCssVars.XColorWarningTint),
|
|
XColorWarningTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorWarningTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Danger ...
|
|
//
|
|
XColorDanger: this.getCssVar(XThemeCssVars.XColorDanger),
|
|
XColorDangerContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDangerContrast
|
|
),
|
|
|
|
//
|
|
XColorDangerShade: this.getCssVar(XThemeCssVars.XColorDangerShade),
|
|
XColorDangerShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDangerShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorDangerTint: this.getCssVar(XThemeCssVars.XColorDangerTint),
|
|
XColorDangerTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDangerTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Dark ...
|
|
//
|
|
XColorDark: this.getCssVar(XThemeCssVars.XColorDark),
|
|
XColorDarkContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkContrast
|
|
),
|
|
|
|
//
|
|
XColorDarkShade: this.getCssVar(XThemeCssVars.XColorDarkShade),
|
|
XColorDarkShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorDarkTint: this.getCssVar(XThemeCssVars.XColorDarkTint),
|
|
XColorDarkTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorDarkTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Medium ...
|
|
//
|
|
XColorMedium: this.getCssVar(XThemeCssVars.XColorMedium),
|
|
XColorMediumContrast: this.getCssVar(
|
|
XThemeCssVars.XColorMediumContrast
|
|
),
|
|
|
|
//
|
|
XColorMediumShade: this.getCssVar(XThemeCssVars.XColorMediumShade),
|
|
XColorMediumShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorMediumShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorMediumTint: this.getCssVar(XThemeCssVars.XColorMediumTint),
|
|
XColorMediumTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorMediumTintContrast
|
|
),
|
|
//#endregion
|
|
|
|
//
|
|
//#region Light ...
|
|
//
|
|
XColorLight: this.getCssVar(XThemeCssVars.XColorLight),
|
|
XColorLightContrast: this.getCssVar(
|
|
XThemeCssVars.XColorLightContrast
|
|
),
|
|
|
|
//
|
|
XColorLightShade: this.getCssVar(XThemeCssVars.XColorLightShade),
|
|
XColorLightShadeContrast: this.getCssVar(
|
|
XThemeCssVars.XColorLightShadeContrast
|
|
),
|
|
|
|
//
|
|
XColorLightTint: this.getCssVar(XThemeCssVars.XColorLightTint),
|
|
XColorLightTintContrast: this.getCssVar(
|
|
XThemeCssVars.XColorLightTintContrast
|
|
),
|
|
//#endregion
|
|
},
|
|
},
|
|
};
|
|
|
|
//
|
|
await this.saveTheme(defaultTheme, false);
|
|
} else {
|
|
//
|
|
const type = await this.getCurrentThemeType();
|
|
await this.setTheme(currentTheme, type, false, false);
|
|
}
|
|
|
|
//
|
|
this.notifyChanges.emit();
|
|
}
|
|
|
|
private async issueFailedNotification(exception?: XExceptionIdentifier) {
|
|
//
|
|
if (isNullOrUndefined(exception)) {
|
|
exception = XExceptionIDs.ActionFailed;
|
|
}
|
|
|
|
//
|
|
await this.notificationService.presentErrorNotification({
|
|
exception,
|
|
dissmissable: false,
|
|
});
|
|
}
|
|
|
|
private async issueSuccessNotification() {
|
|
//
|
|
await this.notificationService.presentDefaultSuccessNotification();
|
|
}
|
|
|
|
//
|
|
//#region Read and Write Storage ...
|
|
private writeThemes(themes: XThemePack[]) {
|
|
//
|
|
const mKey = XThemeManagerStorageKeys.Themes;
|
|
|
|
//
|
|
this.storageService.write(mKey, themes, true);
|
|
}
|
|
|
|
private readThemes() {
|
|
//
|
|
const mKey = XThemeManagerStorageKeys.Themes;
|
|
|
|
//
|
|
const isExists = this.storageService.isExists(mKey);
|
|
if (!isExists) {
|
|
return [];
|
|
}
|
|
|
|
//
|
|
return this.storageService.readOfType<XThemePack[]>(mKey, false);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region CssVar Manipulators ...
|
|
/**
|
|
* prepare a css var name
|
|
*
|
|
* @param key css variable name
|
|
*/
|
|
private prepareCssKey(key: XThemeCssVarsIdentifier) {
|
|
return `${this.PREFIX}${key}`;
|
|
}
|
|
|
|
/**
|
|
* remove css key prefix ...
|
|
*
|
|
* @param key a prepared css var ...
|
|
*/
|
|
private removeCssKeyPrefix(key: XThemeCssVarsIdentifier) {
|
|
return key.replace(this.PREFIX, '');
|
|
}
|
|
|
|
/**
|
|
* read specific css var value of an element
|
|
* @param name css variable name
|
|
* @param element destination element
|
|
*/
|
|
private getCssVar(name: XThemeCssVarsIdentifier) {
|
|
//
|
|
return getComputedStyle(document.body).getPropertyValue(
|
|
this.prepareCssKey(name)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* set css var into element ...
|
|
*
|
|
* @param name css var name
|
|
* @param value css var value
|
|
* @param elements destination element of array of elements
|
|
*/
|
|
private setCssVar(
|
|
name: XThemeCssVarsIdentifier,
|
|
value: string,
|
|
element?: ElementRef
|
|
) {
|
|
//
|
|
if (isNullOrEmptyString(name)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Setting Variable on Element if exists ...
|
|
if (element && element.nativeElement) {
|
|
(element.nativeElement as HTMLElement).style.setProperty(
|
|
this.prepareCssKey(name),
|
|
value
|
|
);
|
|
}
|
|
|
|
//
|
|
// Setting Variable on root ...
|
|
document.documentElement.style.setProperty(this.prepareCssKey(name), value);
|
|
}
|
|
|
|
private async setThemeColors(theme: XThemeColors, element?: ElementRef) {
|
|
//
|
|
if (isNullOrUndefined(theme)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
const colorKeys = keys(theme);
|
|
colorKeys.forEach((cKey) => {
|
|
//
|
|
const cssKey = this.ColorCssVars[cKey] as string;
|
|
const ionCssKey = cssKey.replace('x-', 'ion-');
|
|
const cssValue = toNormalString(theme[cKey]);
|
|
|
|
//
|
|
this.setCssVar(cssKey, cssValue, element);
|
|
this.setCssVar(ionCssKey, cssValue, element);
|
|
});
|
|
|
|
//
|
|
return true;
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\config\x-framework-services.config.ts
|
|
|
|
import { XFrameworkCoreConfig } from 'x-framework-core';
|
|
|
|
// tslint:disable-next-line:no-empty-interface
|
|
export interface XFrameworkServicesConfig extends XFrameworkCoreConfig {
|
|
geoLocationConfig?: PositionOptions
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\directives\x-currency-formatter.directive.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
Renderer2,
|
|
Directive,
|
|
ElementRef,
|
|
forwardRef,
|
|
HostListener
|
|
} from '@angular/core';
|
|
import {
|
|
XLocale,
|
|
removeAll,
|
|
applyLocale,
|
|
isNullOrEmptyString
|
|
} from 'x-framework-core';
|
|
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from '../config/x-framework-services.config';
|
|
|
|
export const X_CURRENCY_FORMATTER: any = {
|
|
useExisting: forwardRef(() => XCurrencyFormatterDirective),
|
|
provide: NG_VALUE_ACCESSOR,
|
|
multi: true
|
|
};
|
|
|
|
@Directive({
|
|
// tslint:disable-next-line:directive-selector
|
|
selector: '[xCurrencyFormatter]',
|
|
providers: [X_CURRENCY_FORMATTER]
|
|
})
|
|
export class XCurrencyFormatterDirective implements ControlValueAccessor {
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
locale: XLocale;
|
|
|
|
@Input()
|
|
applyLocaleToCurrency: boolean;
|
|
|
|
@Input()
|
|
currencySeperator: string;
|
|
|
|
@Input()
|
|
enabledCurrencyFormatter: boolean;
|
|
|
|
onChange = (_: any) => {};
|
|
|
|
onTouched = () => {};
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
private renderer: Renderer2,
|
|
private elementRef: ElementRef,
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG)
|
|
private config: XFrameworkServicesConfig
|
|
) {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Host Bindings ...
|
|
@HostListener('change', ['$event.target.value'])
|
|
change(value: string) {
|
|
//
|
|
const res = this.getUnformattedValue(value);
|
|
this.onChange(res);
|
|
}
|
|
|
|
@HostListener('input', ['$event.target.value'])
|
|
input(value: string) {
|
|
//
|
|
const res = this.getUnformattedValue(value);
|
|
this.onChange(res);
|
|
}
|
|
|
|
@HostListener('blur')
|
|
onBlur() {
|
|
this.onTouched();
|
|
}
|
|
|
|
@HostListener('keydown', ['$event'])
|
|
onKeyDown(event: any) {
|
|
if (this.enabledCurrencyFormatter) {
|
|
this.setOnlyNumberType(event);
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Implemenntation of Interface ...
|
|
writeValue(value: string): void {
|
|
this.setValue(value);
|
|
}
|
|
|
|
registerOnChange(fn: (_: string | any | null) => void): void {
|
|
this.onChange = value => {
|
|
//
|
|
fn(this.enabledCurrencyFormatter ? +value : value);
|
|
this.setValue(value);
|
|
};
|
|
}
|
|
|
|
registerOnTouched(fn: () => void): void {
|
|
this.onTouched = fn;
|
|
}
|
|
|
|
setDisabledState(isDisabled: boolean): void {
|
|
this.renderer.setProperty(
|
|
this.elementRef.nativeElement,
|
|
'disabled',
|
|
isDisabled
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private isElementValid() {
|
|
return this.elementRef && this.elementRef.nativeElement;
|
|
}
|
|
|
|
private getFormattedValue(value: string) {
|
|
//
|
|
if (!this.enabledCurrencyFormatter || !value) {
|
|
return value || '';
|
|
}
|
|
|
|
//
|
|
if (this.applyLocaleToCurrency) {
|
|
value = applyLocale(value, this.locale || this.config.defaultLanguage);
|
|
}
|
|
|
|
//
|
|
const result = value
|
|
.toString()
|
|
.replace(/\B(?=(\d{3})+(?!\d))/g, this.currencySeperator);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private getUnformattedValue(value: string) {
|
|
//
|
|
const result = removeAll(value, this.currencySeperator, true);
|
|
return result;
|
|
}
|
|
|
|
private getNormalizedValue(value: string) {
|
|
//
|
|
if (!this.isElementValid()) {
|
|
return value;
|
|
}
|
|
|
|
//
|
|
value = isNullOrEmptyString(value) ? '' : this.getUnformattedValue(value);
|
|
|
|
//
|
|
if (this.enabledCurrencyFormatter) {
|
|
value = this.getFormattedValue(value);
|
|
} else {
|
|
value = this.getUnformattedValue(value);
|
|
}
|
|
|
|
//
|
|
return value;
|
|
}
|
|
|
|
private setValue(value: string) {
|
|
//
|
|
const normalizedValue = this.getNormalizedValue(value);
|
|
this.renderer.setProperty(
|
|
this.elementRef.nativeElement,
|
|
'value',
|
|
normalizedValue
|
|
);
|
|
}
|
|
|
|
private setOnlyNumberType(e: any) {
|
|
//
|
|
const keyCode = e.code as string;
|
|
const isValidKey =
|
|
keyCode.includes('Digit') || keyCode.includes('Backspace');
|
|
|
|
//
|
|
if (!isValidKey) {
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\directives\x-date-presenter.directive.ts
|
|
|
|
import {
|
|
XLocale,
|
|
formatDate,
|
|
getDateOfBirthDateFormatString,
|
|
} from 'x-framework-core';
|
|
import { XLocalizationService } from '../x-localization.service';
|
|
import {
|
|
Directive,
|
|
ElementRef,
|
|
OnInit,
|
|
Input,
|
|
OnChanges,
|
|
SimpleChanges,
|
|
} from '@angular/core';
|
|
|
|
@Directive({
|
|
// tslint:disable-next-line:directive-selector
|
|
selector: '[xDatePresenter]',
|
|
})
|
|
export class XDatePresenterDirective implements OnInit, OnChanges {
|
|
//
|
|
@Input()
|
|
date?: Date | string;
|
|
|
|
@Input()
|
|
locale?: XLocale;
|
|
|
|
@Input()
|
|
format?: string;
|
|
|
|
@Input()
|
|
isUtc?: boolean;
|
|
|
|
@Input()
|
|
toUtc?: boolean;
|
|
|
|
constructor(
|
|
private element: ElementRef,
|
|
private localizationService: XLocalizationService
|
|
) {}
|
|
|
|
ngOnInit() {
|
|
this.presentDate();
|
|
}
|
|
|
|
ngOnChanges(changes: SimpleChanges): void {
|
|
this.presentDate();
|
|
}
|
|
|
|
private presentDate() {
|
|
//
|
|
if (!this.locale) {
|
|
this.locale = this.localizationService.locale;
|
|
}
|
|
|
|
//
|
|
if (!this.date) {
|
|
this.date = new Date();
|
|
}
|
|
|
|
//
|
|
if (!this.format) {
|
|
this.format = getDateOfBirthDateFormatString(this.locale);
|
|
}
|
|
|
|
//
|
|
if (!this.toUtc) {
|
|
this.toUtc = false;
|
|
}
|
|
|
|
//
|
|
let dateStr: string;
|
|
try {
|
|
dateStr = formatDate(
|
|
this.date,
|
|
this.locale,
|
|
this.format,
|
|
this.isUtc,
|
|
this.toUtc
|
|
);
|
|
} catch {
|
|
dateStr = '---';
|
|
}
|
|
|
|
//
|
|
this.element.nativeElement.innerHTML = dateStr;
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\directives\x-from-input-formatter.directive.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
Directive,
|
|
Renderer2,
|
|
ElementRef,
|
|
forwardRef,
|
|
HostListener,
|
|
} from '@angular/core';
|
|
import {
|
|
XLocale,
|
|
hasChild,
|
|
removeAll,
|
|
getDigits,
|
|
toXString,
|
|
applyLocale,
|
|
getNonDigits,
|
|
removeSpaces,
|
|
isNullOrUndefined,
|
|
extractUniqueChars,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from '../config/x-framework-services.config';
|
|
|
|
export const X_FORM_INPUT_FORMATTER: any = {
|
|
useExisting: forwardRef(() => XFromInputFormatterDirective),
|
|
provide: NG_VALUE_ACCESSOR,
|
|
multi: true,
|
|
};
|
|
|
|
export enum XFormInputFormatter {
|
|
ApplyLocale = 'apply_locale',
|
|
FormatCurrency = 'format_currency',
|
|
StringFormatter = 'string_formatter',
|
|
StringInputFormatter = 'string_input_formatter',
|
|
FormatCurrencyAndApplyLocale = 'format_currency_apply_locale',
|
|
StringFormatterAndApplyLocale = 'string_formatter_apply_locale',
|
|
StringInputFormatterAndApplyLocale = 'string_input_formatter_apply_locale',
|
|
}
|
|
|
|
export type XFormInputFormatterIdentifier = XFormInputFormatter | string;
|
|
|
|
export enum XStringInputFormatType {
|
|
None = 'none',
|
|
LowerCase = 'lowercase',
|
|
UpperCase = 'uppercase',
|
|
NonSpace = 'non_space',
|
|
NonDigits = 'none_digits',
|
|
OnlyDigits = 'only_digits',
|
|
UniqueChars = 'unique_chars',
|
|
}
|
|
|
|
export type XStringInputFormatTypeIdentifier = XStringInputFormatType | string;
|
|
|
|
@Directive({
|
|
// tslint:disable-next-line:directive-selector
|
|
selector: '[xFromInputFormatter]',
|
|
providers: [X_FORM_INPUT_FORMATTER],
|
|
})
|
|
export class XFromInputFormatterDirective implements ControlValueAccessor {
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
locale: XLocale;
|
|
|
|
@Input()
|
|
inputFormatterType: XFormInputFormatterIdentifier;
|
|
|
|
@Input()
|
|
stringInputFormatterType: XStringInputFormatTypeIdentifier;
|
|
|
|
@Input()
|
|
seperator: string;
|
|
|
|
@Input()
|
|
currencyLable: string;
|
|
|
|
@Input()
|
|
stringFormatter: number[];
|
|
|
|
@Input()
|
|
enabledInputFormatter: boolean;
|
|
|
|
//
|
|
onChange = (_: any) => {};
|
|
|
|
onTouched = () => {};
|
|
|
|
onFocused = () => {};
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
private renderer: Renderer2,
|
|
private elementRef: ElementRef,
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG)
|
|
private config: XFrameworkServicesConfig
|
|
) {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Type Detectors ...
|
|
isCurrencyType() {
|
|
return (
|
|
this.inputFormatterType === XFormInputFormatter.FormatCurrency ||
|
|
this.inputFormatterType ===
|
|
XFormInputFormatter.FormatCurrencyAndApplyLocale
|
|
);
|
|
}
|
|
|
|
isStringFormatterType() {
|
|
return (
|
|
this.inputFormatterType === XFormInputFormatter.StringFormatter ||
|
|
this.inputFormatterType ===
|
|
XFormInputFormatter.StringFormatterAndApplyLocale ||
|
|
this.inputFormatterType === XFormInputFormatter.StringInputFormatter ||
|
|
this.inputFormatterType ===
|
|
XFormInputFormatter.StringInputFormatterAndApplyLocale
|
|
);
|
|
}
|
|
|
|
isLocaleType() {
|
|
return (
|
|
this.inputFormatterType === XFormInputFormatter.ApplyLocale ||
|
|
this.inputFormatterType ===
|
|
XFormInputFormatter.FormatCurrencyAndApplyLocale ||
|
|
this.inputFormatterType ===
|
|
XFormInputFormatter.StringFormatterAndApplyLocale ||
|
|
this.inputFormatterType ===
|
|
XFormInputFormatter.StringInputFormatterAndApplyLocale
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Host Bindings ...
|
|
@HostListener('change', ['$event.target.value'])
|
|
change(value: string) {
|
|
//
|
|
const res = this.getUnformattedValue(value);
|
|
this.onChange(res);
|
|
}
|
|
|
|
@HostListener('input', ['$event.target.value'])
|
|
input(value: string) {
|
|
//
|
|
const res = this.getUnformattedValue(value);
|
|
this.onChange(res);
|
|
}
|
|
|
|
@HostListener('focus')
|
|
onFocus() {
|
|
this.onFocused();
|
|
if (this.isCurrencyType()) {
|
|
this.clearCurrencyLabel();
|
|
}
|
|
}
|
|
|
|
@HostListener('blur')
|
|
onBlur() {
|
|
this.onTouched();
|
|
if (this.isCurrencyType()) {
|
|
this.applyCurrencyLabel();
|
|
}
|
|
}
|
|
|
|
@HostListener('keydown', ['$event'])
|
|
onKeyDown(event: any) {
|
|
// if (this.isCurrencyType()) {
|
|
// this.setOnlyNumberType(event);
|
|
// }
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Implemenntation of Interface ...
|
|
writeValue(value: string): void {
|
|
this.setValue(value);
|
|
}
|
|
|
|
registerOnChange(fn: (_: string | any | null) => void): void {
|
|
this.onChange = (value) => {
|
|
//
|
|
fn(this.isCurrencyType() ? +value : value);
|
|
|
|
//
|
|
this.setValue(value);
|
|
};
|
|
}
|
|
|
|
registerOnTouched(fn: () => void): void {
|
|
this.onTouched = fn;
|
|
}
|
|
|
|
setDisabledState(isDisabled: boolean): void {
|
|
//
|
|
if (isDisabled && this.isCurrencyType()) {
|
|
this.applyCurrencyLabel();
|
|
}
|
|
|
|
//
|
|
this.renderer.setProperty(
|
|
this.elementRef.nativeElement,
|
|
'disabled',
|
|
isDisabled
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private isElementValid() {
|
|
return this.elementRef && this.elementRef.nativeElement;
|
|
}
|
|
|
|
private getFormattedValue(value: string) {
|
|
//
|
|
// Normallize Value ...
|
|
if (isNullOrEmptyString(value) || !this.enabledInputFormatter) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
// Prepared Formatted Value ...
|
|
let result = this.isCurrencyType()
|
|
? this.getCurrencyFormattedValue(value)
|
|
: this.isStringFormatterType()
|
|
? this.getStringFormattedValue(value)
|
|
: value || '';
|
|
|
|
//
|
|
// Apply Locale if Localeable Input Type ...
|
|
if (this.isLocaleType()) {
|
|
result = this.getLocaleFormattedValue(result);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private getUnformattedValue(value: string) {
|
|
//
|
|
let result = value.toString() || '';
|
|
|
|
//
|
|
const seperator = isNullOrEmptyString(this.seperator) ? '' : this.seperator;
|
|
|
|
//
|
|
// Remove All occurence of seperator ...
|
|
if (this.enabledInputFormatter) {
|
|
result = removeAll(value, seperator, true);
|
|
}
|
|
|
|
//
|
|
// Currency Lable ...
|
|
if (this.isCurrencyType() && !isNullOrEmptyString(this.currencyLable)) {
|
|
result = result.replace(this.currencyLable, '').trim();
|
|
}
|
|
|
|
//
|
|
// Change Locale to Default ...
|
|
if (this.isLocaleType()) {
|
|
result = !isNullOrEmptyString(result) ? applyLocale(result, 'en-US') : '';
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private getNormalizedValue(value: string) {
|
|
//
|
|
if (!this.isElementValid()) {
|
|
return value;
|
|
}
|
|
|
|
//
|
|
// Normallize Value and prevent from null ...
|
|
let result = value ? value.toString() || '' : '';
|
|
result = isNullOrEmptyString(value) ? '' : this.getUnformattedValue(value);
|
|
if (!this.enabledInputFormatter) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Apply Locale ...
|
|
if (this.inputFormatterType === XFormInputFormatter.ApplyLocale) {
|
|
//
|
|
result = applyLocale(value, this.locale || this.config.defaultLanguage);
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Formatter ...
|
|
if (this.isCurrencyType() || this.isStringFormatterType()) {
|
|
return this.getFormattedValue(result);
|
|
}
|
|
|
|
//
|
|
return value;
|
|
}
|
|
|
|
private setValue(value: string, normalizeValue = true) {
|
|
//
|
|
const normalizedValue = normalizeValue
|
|
? this.getNormalizedValue(value)
|
|
: value || '';
|
|
this.renderer.setProperty(
|
|
this.elementRef.nativeElement,
|
|
'value',
|
|
normalizedValue
|
|
);
|
|
}
|
|
|
|
private getValue() {
|
|
return this.elementRef.nativeElement.value
|
|
? (this.elementRef.nativeElement.value as string)
|
|
: '';
|
|
}
|
|
|
|
private setOnlyNumberType(e: any) {
|
|
//
|
|
const keyCode = e.code as string;
|
|
const numPadKeys = [...new Array(10).keys()].map((c, i) => `Numpad${i}`);
|
|
const isValidKey =
|
|
keyCode.includes('Tab') ||
|
|
keyCode.includes('Digit') ||
|
|
keyCode.includes('Backspace') ||
|
|
numPadKeys.includes(keyCode);
|
|
|
|
//
|
|
if (!isValidKey) {
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
|
|
//
|
|
//#region Formatter Actions ...
|
|
private getLocaleFormattedValue(value: any) {
|
|
//
|
|
const mValue = value ? (value.toString() as string) : '';
|
|
return applyLocale(mValue, this.locale || this.config.defaultLanguage);
|
|
}
|
|
|
|
private getStringFormattedValue(value: any) {
|
|
//
|
|
const mValue = !isNullOrUndefined(value) ? toXString(value) : '';
|
|
|
|
//
|
|
let mResultValue = '';
|
|
|
|
//
|
|
if (
|
|
this.inputFormatterType === XFormInputFormatter.StringFormatter ||
|
|
this.inputFormatterType ===
|
|
XFormInputFormatter.StringFormatterAndApplyLocale
|
|
) {
|
|
//
|
|
if (!hasChild(this.stringFormatter)) {
|
|
return mValue;
|
|
}
|
|
|
|
//
|
|
let mSource = mValue;
|
|
this.stringFormatter.forEach((l, i) => {
|
|
if (mSource.length >= l) {
|
|
//
|
|
const selected = mSource.substring(0, l);
|
|
|
|
//
|
|
mResultValue +=
|
|
i === this.stringFormatter.length
|
|
? selected
|
|
: `${selected}${this.seperator}`;
|
|
|
|
//
|
|
mSource = mSource.substr(l, mValue.length);
|
|
}
|
|
});
|
|
|
|
//
|
|
if (mSource.length > 0) {
|
|
mResultValue += `${mSource}`;
|
|
}
|
|
} else if (
|
|
this.inputFormatterType === XFormInputFormatter.StringInputFormatter ||
|
|
this.inputFormatterType ===
|
|
XFormInputFormatter.StringInputFormatterAndApplyLocale
|
|
) {
|
|
//
|
|
switch (this.stringInputFormatterType) {
|
|
//
|
|
case XStringInputFormatType.LowerCase:
|
|
mResultValue = mValue.toLowerCase();
|
|
break;
|
|
|
|
//
|
|
case XStringInputFormatType.UpperCase:
|
|
mResultValue = mValue.toUpperCase();
|
|
break;
|
|
|
|
//
|
|
case XStringInputFormatType.NonDigits:
|
|
//
|
|
mResultValue = getNonDigits(mValue);
|
|
break;
|
|
|
|
//
|
|
case XStringInputFormatType.UniqueChars:
|
|
//
|
|
mResultValue = extractUniqueChars(mValue);
|
|
break;
|
|
|
|
//
|
|
case XStringInputFormatType.NonSpace:
|
|
mResultValue = removeSpaces(mValue.trim());
|
|
break;
|
|
|
|
//
|
|
case XStringInputFormatType.OnlyDigits:
|
|
mResultValue = getDigits(mValue);
|
|
break;
|
|
|
|
//
|
|
default:
|
|
mResultValue = mValue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return mResultValue;
|
|
}
|
|
|
|
private getCurrencyFormattedValue(value: any) {
|
|
//
|
|
const mValue = value ? getDigits(value.toString() as string) : '';
|
|
const seperator = isNullOrEmptyString(this.seperator) ? '' : this.seperator;
|
|
const formattedValue = mValue.replace(/\B(?=(\d{3})+(?!\d))/g, seperator);
|
|
|
|
//
|
|
const result = !isNullOrEmptyString(formattedValue) ? formattedValue : '';
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
private applyCurrencyLabel() {
|
|
//
|
|
if (!this.isCurrencyType()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
let value = this.getValue();
|
|
|
|
//
|
|
if (
|
|
!isNullOrEmptyString(value) &&
|
|
!isNullOrEmptyString(this.currencyLable)
|
|
) {
|
|
value = `${value} ${this.currencyLable}`;
|
|
}
|
|
|
|
//
|
|
this.setValue(value, false);
|
|
}
|
|
|
|
private clearCurrencyLabel() {
|
|
//
|
|
if (!this.isCurrencyType()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
let value = this.getValue();
|
|
|
|
//
|
|
if (
|
|
!isNullOrEmptyString(value) &&
|
|
!isNullOrEmptyString(this.currencyLable)
|
|
) {
|
|
value = value.replace(this.currencyLable, '');
|
|
}
|
|
|
|
//
|
|
this.setValue(value);
|
|
}
|
|
//#endregion
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\directives\x-locale-input-formatter.directive.ts
|
|
|
|
import {
|
|
Input,
|
|
Inject,
|
|
Directive,
|
|
Renderer2,
|
|
ElementRef,
|
|
forwardRef,
|
|
HostListener,
|
|
} from '@angular/core';
|
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XLocale, applyLocale, isNullOrEmptyString } from 'x-framework-core';
|
|
import { XFrameworkServicesConfig } from '../config/x-framework-services.config';
|
|
|
|
export const X_LOCALE_FORMATTER: any = {
|
|
useExisting: forwardRef(() => XLocaleInputFormatterDirective),
|
|
provide: NG_VALUE_ACCESSOR,
|
|
multi: true,
|
|
};
|
|
|
|
@Directive({
|
|
// tslint:disable-next-line:directive-selector
|
|
selector: '[xLocaleInputFormatter]',
|
|
providers: [X_LOCALE_FORMATTER],
|
|
})
|
|
export class XLocaleInputFormatterDirective implements ControlValueAccessor {
|
|
//
|
|
//#region Props ...
|
|
@Input()
|
|
locale: XLocale;
|
|
|
|
@Input()
|
|
enabledLocaleFormatter: boolean;
|
|
|
|
onChange = (_: any) => {};
|
|
|
|
onTouched = () => {};
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
private renderer: Renderer2,
|
|
private elementRef: ElementRef,
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG)
|
|
private config: XFrameworkServicesConfig
|
|
) {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Host Bindings ...
|
|
@HostListener('change', ['$event.target.value'])
|
|
change(value: string) {
|
|
this.onChange(value);
|
|
}
|
|
|
|
@HostListener('input', ['$event.target.value'])
|
|
input(value: string) {
|
|
this.onChange(value);
|
|
}
|
|
|
|
@HostListener('blur')
|
|
onBlur() {
|
|
this.onTouched();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Implemenntation of Interface ...
|
|
writeValue(value: string): void {
|
|
this.setValue(value);
|
|
}
|
|
|
|
registerOnChange(fn: (_: string | any | null) => void): void {
|
|
this.onChange = (value) => {
|
|
//
|
|
fn(value);
|
|
this.setValue(value);
|
|
};
|
|
}
|
|
|
|
registerOnTouched(fn: () => void): void {
|
|
this.onTouched = fn;
|
|
}
|
|
|
|
setDisabledState(isDisabled: boolean): void {
|
|
this.renderer.setProperty(
|
|
this.elementRef.nativeElement,
|
|
'disabled',
|
|
isDisabled
|
|
);
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private isElementValid() {
|
|
return this.elementRef && this.elementRef.nativeElement;
|
|
}
|
|
|
|
private getFormattedValue(value: string) {
|
|
//
|
|
if (!this.enabledLocaleFormatter || !value) {
|
|
return value || '';
|
|
}
|
|
|
|
//
|
|
value = applyLocale(value, this.locale || this.config.defaultLanguage);
|
|
|
|
//
|
|
return value;
|
|
}
|
|
|
|
private getNormalizedValue(value: string) {
|
|
//
|
|
if (!this.isElementValid()) {
|
|
return value;
|
|
}
|
|
|
|
//
|
|
value = isNullOrEmptyString(value) ? '' : this.getFormattedValue(value);
|
|
|
|
//
|
|
return value;
|
|
}
|
|
|
|
private setValue(value: string) {
|
|
//
|
|
const normalizedValue = this.getNormalizedValue(value);
|
|
this.renderer.setProperty(
|
|
this.elementRef.nativeElement,
|
|
'value',
|
|
normalizedValue
|
|
);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\directives\x-swipable.directive.ts
|
|
|
|
import {
|
|
Input,
|
|
OnInit,
|
|
Output,
|
|
OnChanges,
|
|
Directive,
|
|
OnDestroy,
|
|
ElementRef,
|
|
EventEmitter,
|
|
SimpleChanges,
|
|
AfterViewInit,
|
|
} from '@angular/core';
|
|
import { Subject, Observable } from 'rxjs';
|
|
import { keys, nameof } from 'x-framework-core';
|
|
import { GestureController } from '@ionic/angular';
|
|
import { Gesture, GestureDetail } from '@ionic/core';
|
|
import { takeUntil, debounceTime } from 'rxjs/operators';
|
|
import { XSettingsService } from '../x-settings.service';
|
|
|
|
export enum XSwipeDirection {
|
|
UP = 'up',
|
|
DOWN = 'down',
|
|
LEFT = 'left',
|
|
START = 'start',
|
|
RIGHT = 'right',
|
|
END = 'end',
|
|
}
|
|
|
|
export type XSwipeDirectionIdentifier = XSwipeDirection | string;
|
|
|
|
export enum XSwipeSupportedDirections {
|
|
VERTICALL,
|
|
HORIZONTAL_LEFT_RIGHT,
|
|
HORIZONTAL_START_END,
|
|
ALL,
|
|
}
|
|
|
|
export interface XSwipeEvent {
|
|
deltaX: number;
|
|
deltaY: number;
|
|
direction: XSwipeDirectionIdentifier;
|
|
}
|
|
|
|
@Directive({
|
|
// tslint:disable-next-line:directive-selector
|
|
selector: '[xSwipable]',
|
|
})
|
|
export class XSwipableDirective
|
|
implements OnInit, AfterViewInit, OnDestroy, OnChanges {
|
|
//
|
|
//#region Props ...
|
|
private gesture: Gesture;
|
|
private unsubscriber = new Subject();
|
|
private issueSwipeEvents$ = new Subject<GestureDetail>();
|
|
private uiDirection = this.settingsService.uiDirection;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Inputs ...
|
|
@Input()
|
|
threshold = 60;
|
|
|
|
@Input()
|
|
swipeDisabled = false;
|
|
|
|
@Input()
|
|
debounceTime = 300;
|
|
|
|
@Input()
|
|
supportedDirections: XSwipeSupportedDirections =
|
|
XSwipeSupportedDirections.HORIZONTAL_START_END;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Event Emitters ...
|
|
@Output()
|
|
swipe = new EventEmitter<XSwipeEvent>();
|
|
|
|
@Output()
|
|
swipeUp = new EventEmitter();
|
|
|
|
@Output()
|
|
swipeDown = new EventEmitter();
|
|
|
|
@Output()
|
|
swipeLeft = new EventEmitter();
|
|
|
|
@Output()
|
|
swipeStart = new EventEmitter();
|
|
|
|
@Output()
|
|
swipeRight = new EventEmitter();
|
|
|
|
@Output()
|
|
swipeEnd = new EventEmitter();
|
|
//#endregion
|
|
|
|
//
|
|
//#region Constructor ...
|
|
constructor(
|
|
private elementRef: ElementRef,
|
|
private gestureCtrl: GestureController,
|
|
private settingsService: XSettingsService
|
|
) {}
|
|
//#endregion
|
|
|
|
//
|
|
//#region LifeCycles ...
|
|
ngOnInit() {
|
|
this.prepareGesture();
|
|
}
|
|
|
|
ngAfterViewInit() {
|
|
this.registerIssueSwipeHandler();
|
|
}
|
|
|
|
ngOnDestroy() {
|
|
this.destroyGesture();
|
|
this.issueSwipeEvents$.complete();
|
|
this.releaseUnsubscriber();
|
|
}
|
|
|
|
ngOnChanges(changes: SimpleChanges) {
|
|
//
|
|
const changeKesy = keys(changes);
|
|
|
|
//
|
|
const isThresholdChanged = changeKesy.includes(
|
|
nameof<XSwipableDirective>('threshold')
|
|
);
|
|
if (isThresholdChanged) {
|
|
this.prepareGesture();
|
|
}
|
|
|
|
//
|
|
const isDebounceTimeChanged = changeKesy.includes(
|
|
nameof<XSwipableDirective>('debounceTime')
|
|
);
|
|
if (isDebounceTimeChanged) {
|
|
this.registerIssueSwipeHandler();
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
private prepareGesture() {
|
|
//
|
|
this.destroyGesture();
|
|
|
|
//
|
|
this.gesture = this.gestureCtrl.create({
|
|
el: this.elementRef.nativeElement,
|
|
threshold: this.threshold,
|
|
gestureName: 'x-gesture',
|
|
onMove: (detail) => {
|
|
this.onMoveHandler(detail);
|
|
},
|
|
});
|
|
|
|
//
|
|
this.gesture.enable();
|
|
}
|
|
|
|
private destroyGesture() {
|
|
//
|
|
if (this.gesture) {
|
|
//
|
|
this.gesture.destroy();
|
|
this.gesture = null;
|
|
}
|
|
}
|
|
|
|
private releaseUnsubscriber() {
|
|
//
|
|
if (!this.unsubscriber.closed) {
|
|
this.unsubscriber.next();
|
|
this.unsubscriber.complete();
|
|
}
|
|
}
|
|
|
|
private applyTakeUntilWrapper<T>(task: Observable<T>): Observable<T> {
|
|
return task.pipe(takeUntil(this.unsubscriber));
|
|
}
|
|
|
|
private registerIssueSwipeHandler() {
|
|
//
|
|
this.applyTakeUntilWrapper(
|
|
this.issueSwipeEvents$
|
|
.asObservable()
|
|
.pipe(debounceTime(this.debounceTime))
|
|
).subscribe((gDetail) => {
|
|
//
|
|
if (this.swipeDisabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const mSwipeEvent: Partial<XSwipeEvent> = {
|
|
deltaX: gDetail.deltaX,
|
|
deltaY: gDetail.deltaY,
|
|
};
|
|
|
|
//
|
|
// Handle Vertical ...
|
|
if (
|
|
this.supportedDirections === XSwipeSupportedDirections.ALL ||
|
|
this.supportedDirections === XSwipeSupportedDirections.VERTICALL
|
|
) {
|
|
//
|
|
let swipeDir: XSwipeDirection;
|
|
|
|
//
|
|
if (gDetail.deltaY >= 0) {
|
|
//
|
|
swipeDir = XSwipeDirection.DOWN;
|
|
|
|
//
|
|
this.swipeDown.emit();
|
|
} else {
|
|
//
|
|
swipeDir = XSwipeDirection.UP;
|
|
|
|
//
|
|
this.swipeUp.emit();
|
|
}
|
|
|
|
//
|
|
// Handle Global Event ...
|
|
mSwipeEvent.direction = swipeDir;
|
|
this.swipe.emit(mSwipeEvent as XSwipeEvent);
|
|
}
|
|
|
|
//
|
|
// Handle Horizontal Left Right ...
|
|
if (
|
|
this.supportedDirections === XSwipeSupportedDirections.ALL ||
|
|
this.supportedDirections ===
|
|
XSwipeSupportedDirections.HORIZONTAL_LEFT_RIGHT
|
|
) {
|
|
//
|
|
let swipeDir: XSwipeDirection;
|
|
|
|
//
|
|
if (gDetail.deltaX >= 0) {
|
|
//
|
|
swipeDir = XSwipeDirection.RIGHT;
|
|
|
|
//
|
|
this.swipeRight.emit();
|
|
} else {
|
|
//
|
|
swipeDir = XSwipeDirection.LEFT;
|
|
|
|
//
|
|
this.swipeLeft.emit();
|
|
}
|
|
|
|
//
|
|
// Handle Global Event ...
|
|
mSwipeEvent.direction = swipeDir;
|
|
this.swipe.emit(mSwipeEvent as XSwipeEvent);
|
|
}
|
|
|
|
//
|
|
// Handle Horizontal Start End ...
|
|
if (
|
|
this.supportedDirections === XSwipeSupportedDirections.ALL ||
|
|
this.supportedDirections ===
|
|
XSwipeSupportedDirections.HORIZONTAL_START_END
|
|
) {
|
|
//
|
|
let swipeDir: XSwipeDirection;
|
|
|
|
//
|
|
if (gDetail.deltaX >= 0) {
|
|
//
|
|
if (this.uiDirection === 'ltr') {
|
|
//
|
|
swipeDir = XSwipeDirection.END;
|
|
|
|
//
|
|
this.swipeEnd.emit();
|
|
} else {
|
|
//
|
|
swipeDir = XSwipeDirection.START;
|
|
|
|
//
|
|
this.swipeStart.emit();
|
|
}
|
|
} else {
|
|
//
|
|
if (this.uiDirection === 'ltr') {
|
|
//
|
|
swipeDir = XSwipeDirection.START;
|
|
|
|
//
|
|
this.swipeStart.emit();
|
|
} else {
|
|
//
|
|
swipeDir = XSwipeDirection.END;
|
|
|
|
//
|
|
this.swipeEnd.emit();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Global Event ...
|
|
mSwipeEvent.direction = swipeDir;
|
|
this.swipe.emit(mSwipeEvent as XSwipeEvent);
|
|
}
|
|
});
|
|
}
|
|
|
|
private onMoveHandler(ev: GestureDetail) {
|
|
//
|
|
if (this.swipeDisabled) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.issueSwipeEvents$.next(ev);
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\modules\x-directives.module.ts
|
|
|
|
import { NgModule } from '@angular/core';
|
|
import { IonicModule } from '@ionic/angular';
|
|
import { CommonModule } from '@angular/common';
|
|
import { XTranslatePipe } from '../pipes/x-translate.pipe';
|
|
import { XSwipableDirective } from '../directives/x-swipable.directive';
|
|
import { XDatePresenterDirective } from '../directives/x-date-presenter.directive';
|
|
import { XCurrencyFormatterDirective } from '../directives/x-currency-formatter.directive';
|
|
import { XFromInputFormatterDirective } from '../directives/x-from-input-formatter.directive';
|
|
import { XLocaleInputFormatterDirective } from '../directives/x-locale-input-formatter.directive';
|
|
|
|
@NgModule({
|
|
declarations: [
|
|
//
|
|
// Pipes ...
|
|
XTranslatePipe,
|
|
|
|
//
|
|
// Directives
|
|
XSwipableDirective,
|
|
XDatePresenterDirective,
|
|
XCurrencyFormatterDirective,
|
|
XFromInputFormatterDirective,
|
|
XLocaleInputFormatterDirective
|
|
],
|
|
imports: [CommonModule, IonicModule],
|
|
exports: [
|
|
//
|
|
CommonModule,
|
|
IonicModule,
|
|
|
|
//
|
|
// Pipes ...
|
|
XTranslatePipe,
|
|
|
|
//
|
|
// Directives
|
|
XSwipableDirective,
|
|
XDatePresenterDirective,
|
|
XCurrencyFormatterDirective,
|
|
XFromInputFormatterDirective,
|
|
XLocaleInputFormatterDirective
|
|
]
|
|
})
|
|
export class XDirectivesModule {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\pipes\x-translate.pipe.ts
|
|
|
|
import {
|
|
XLocale,
|
|
toNumber,
|
|
isString,
|
|
XResourceIDs,
|
|
XTranslationItem
|
|
} from 'x-framework-core';
|
|
import { Pipe, PipeTransform } from '@angular/core';
|
|
import { XLocalizationService } from '../x-localization.service';
|
|
|
|
@Pipe({
|
|
name: 'xTranslate'
|
|
})
|
|
export class XTranslatePipe implements PipeTransform {
|
|
//
|
|
constructor(private localizationService: XLocalizationService) {}
|
|
|
|
/**
|
|
* translate a resource to specific language in a pipe
|
|
*
|
|
* @param key the resource identifier
|
|
* @param locale the selected or default locale
|
|
*/
|
|
transform(
|
|
key: XResourceIDs | XTranslationItem | string,
|
|
locale?: XLocale
|
|
): string {
|
|
//
|
|
if (!locale) {
|
|
locale = this.localizationService.locale;
|
|
}
|
|
|
|
//
|
|
const isStringKey = isString(key);
|
|
if (!isStringKey) {
|
|
key = toNumber(key) as XResourceIDs;
|
|
}
|
|
|
|
//
|
|
const isExist = isStringKey
|
|
? this.localizationService.isExistsIdOfLocale(locale, key as string)
|
|
: this.localizationService.isExistsIdOfLocale(
|
|
locale,
|
|
key as XResourceIDs
|
|
);
|
|
if (!isExist) {
|
|
return '';
|
|
}
|
|
|
|
//
|
|
return isStringKey
|
|
? this.localizationService.getValueOfLocale(locale, key as string)
|
|
: this.localizationService.getValueOfLocale(locale, key as XResourceIDs);
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\tokens\x-injectable-tokens.ts
|
|
|
|
import { InjectionToken } from '@angular/core';
|
|
import { XFrameworkServicesConfig } from '../config/x-framework-services.config';
|
|
|
|
export const X_FRAMEWORK_SERVICES_CONFIG = new InjectionToken<
|
|
XFrameworkServicesConfig
|
|
>('x_config');
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-manager-service-partial\x-manager-base.service.ts
|
|
|
|
import { Location } from '@angular/common';
|
|
import { XBaseService } from 'x-framework-core';
|
|
import { Platform } from '@angular/cdk/platform';
|
|
import { HttpClient } from '@angular/common/http';
|
|
import { Inject, Injectable } from '@angular/core';
|
|
import { XDialogService } from '../x-dialog.service';
|
|
import { XHistoryService } from '../x-history.service';
|
|
import { XStorageService } from '../x-storage.service';
|
|
import { XSecurityService } from '../x-security.service';
|
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
import { XSettingsService } from '../x-settings.service';
|
|
import { MenuController, NavController } from '@ionic/angular';
|
|
import { XGeolocationService } from '../x-geolocation.service';
|
|
import { XTaskManagerService } from '../x-task-manager.service';
|
|
import { XNotificationService } from '../x-notification.service';
|
|
import { XLocalizationService } from '../x-localization.service';
|
|
import { XThemeManagerService } from '../x-theme-manager.service';
|
|
import { XSecureStorageService } from '../x-secure-storage.service';
|
|
import { X_FRAMEWORK_SERVICES_CONFIG } from '../tokens/x-injectable-tokens';
|
|
import { XFrameworkServicesConfig } from '../config/x-framework-services.config';
|
|
|
|
@Injectable()
|
|
export abstract class XManagerBaseService extends XBaseService {
|
|
constructor(
|
|
@Inject(X_FRAMEWORK_SERVICES_CONFIG)
|
|
public config: XFrameworkServicesConfig,
|
|
public router: Router,
|
|
public platform: Platform,
|
|
public location: Location,
|
|
public httpClient: HttpClient,
|
|
public dialogService: XDialogService,
|
|
public menuController: MenuController,
|
|
public activatedRoute: ActivatedRoute,
|
|
public historyService: XHistoryService,
|
|
public storageService: XStorageService,
|
|
public securityService: XSecurityService,
|
|
public settingsService: XSettingsService,
|
|
public navigationController: NavController,
|
|
public geoLocationService: XGeolocationService,
|
|
public taskManagerService: XTaskManagerService,
|
|
public themeManagerService: XThemeManagerService,
|
|
public notificationService: XNotificationService,
|
|
public localizationService: XLocalizationService,
|
|
public secureStorageService: XSecureStorageService
|
|
) {
|
|
super(config);
|
|
}
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-manager-service-partial\x-manager-final.service.ts
|
|
|
|
import { XManagerRouteService } from './x-manager-route.service';
|
|
|
|
export abstract class XManagerFinalService extends XManagerRouteService {}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-manager-service-partial\x-manager-route.service.ts
|
|
|
|
import {
|
|
keys,
|
|
XPage,
|
|
toArray,
|
|
fromJson,
|
|
hasChild,
|
|
XRouterTarget,
|
|
XOneOrManyType,
|
|
XParamIdentifier,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import { XManagerUIStateService } from './x-manager-ui-state.service';
|
|
import { Params, UrlTree, ParamMap, NavigationExtras } from '@angular/router';
|
|
|
|
export abstract class XManagerRouteService extends XManagerUIStateService {
|
|
//
|
|
//#region Props ...
|
|
//
|
|
public routeDataChanged$ = this.router.routerState.root.data;
|
|
public routeParmChanged$ = this.router.routerState.root.params;
|
|
public routeQueryParmChanged$ = this.router.routerState.root.queryParams;
|
|
//#endregion
|
|
|
|
//
|
|
//#region Route Related Actions ...
|
|
/**
|
|
* some times we had to force change location ...
|
|
*
|
|
* @param route the specified route
|
|
*/
|
|
changeLocation(route?: string) {
|
|
window.location.href = this.getFullUrl(route);
|
|
}
|
|
|
|
/**
|
|
* retrieve base url (Origin) address
|
|
*/
|
|
getBaseUrl() {
|
|
return window.location.origin;
|
|
}
|
|
|
|
/**
|
|
* retrieve current route
|
|
*/
|
|
getRoute() {
|
|
return this.router && this.router.url ? this.router.url : '/';
|
|
}
|
|
|
|
/**
|
|
* merge several parts of a url ...
|
|
*
|
|
* @param route an instance of url tree array ...
|
|
*/
|
|
mergeRoutes(route: XOneOrManyType<string>) {
|
|
//
|
|
if (!hasChild(route)) {
|
|
return '/';
|
|
}
|
|
|
|
//
|
|
try {
|
|
return toArray(route).join('/').replace('//', '/');
|
|
} catch {}
|
|
|
|
//
|
|
return '/';
|
|
}
|
|
|
|
/**
|
|
* retrieve page route ...
|
|
*
|
|
* @param page an instance of XPage ...
|
|
*/
|
|
getPageRoute(page: XPage) {
|
|
//
|
|
if (!page || !hasChild(page.route)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.mergeRoutes(page.route);
|
|
}
|
|
|
|
/**
|
|
* generate and retrieve the fully qualified URL address of
|
|
* specified route
|
|
*
|
|
* @param route the selected app route
|
|
*/
|
|
getFullUrl(route?: string) {
|
|
//
|
|
const mBase = this.getBaseUrl().endsWith('/')
|
|
? this.getBaseUrl()
|
|
: `${this.getBaseUrl()}/`;
|
|
const mRoute = !route
|
|
? ''
|
|
: !route.startsWith('/')
|
|
? route
|
|
: route.substring(1);
|
|
|
|
//
|
|
return `${mBase}${mRoute}`;
|
|
}
|
|
|
|
/**
|
|
* navigate to specific location ...
|
|
*
|
|
* @param commands url or url tree parts which required to navigate
|
|
* @param extras the navigation params or options
|
|
*/
|
|
navigate(commands: any[], extras?: NavigationExtras) {
|
|
return this.router.navigate(commands, extras);
|
|
}
|
|
|
|
/**
|
|
* navigate to specific location ...
|
|
*
|
|
* @param commands url or url tree parts which required to navigate
|
|
* @param extras the navigation params or options
|
|
* @param replaceUrl determines the url replaced or not
|
|
*/
|
|
navigateReplace(
|
|
commands: any[],
|
|
extras?: NavigationExtras,
|
|
replaceUrl: boolean = true
|
|
) {
|
|
return this.router.navigate(commands, { ...extras, replaceUrl });
|
|
}
|
|
|
|
/**
|
|
* navigate to specific location by it's url ...
|
|
*
|
|
* @param url specific url address for navigating
|
|
* @param extras the navigation params or options
|
|
*/
|
|
navigateByUrl(url: string | UrlTree, extras?: NavigationExtras) {
|
|
return this.router.navigate([url], extras);
|
|
}
|
|
|
|
/**
|
|
* navigate to specific location by it's url ...
|
|
*
|
|
* @param url specific url address for navigating
|
|
* @param extras the navigation params or options
|
|
* @param replaceUrl determines the url replaced or not
|
|
*/
|
|
navigateByUrlReplace(
|
|
url: string | UrlTree,
|
|
extras?: NavigationExtras,
|
|
replaceUrl: boolean = true
|
|
) {
|
|
return this.router.navigate([url], { ...extras, replaceUrl });
|
|
}
|
|
|
|
/**
|
|
* navigate to Specific Page ...
|
|
*
|
|
* @param page an instance of XPage
|
|
* @param extras the navigation params or options
|
|
*/
|
|
navigateByPage(page: XPage, extras?: NavigationExtras) {
|
|
//
|
|
const route = this.getPageRoute(page);
|
|
if (isNullOrEmptyString(route)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return this.navigateByUrl(route, extras);
|
|
}
|
|
|
|
/**
|
|
* navigate to Specific Page ...
|
|
*
|
|
* @param page an instance of XPage
|
|
* @param extras the navigation params or options
|
|
* @param replaceUrl determines the url replaced or not
|
|
*/
|
|
navigateByPageReplace(
|
|
page: XPage,
|
|
extras?: NavigationExtras,
|
|
replaceUrl: boolean = true
|
|
) {
|
|
//
|
|
const route = this.getPageRoute(page);
|
|
if (isNullOrEmptyString(route)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
return this.navigateByUrl(route, { ...extras, replaceUrl });
|
|
}
|
|
|
|
/**
|
|
* Applies an array of commands to the current URL tree and creates a new URL tree.
|
|
*
|
|
* When given an activated route, applies the given commands starting from the route.
|
|
* Otherwise, applies the given command starting from the root.
|
|
*
|
|
* @param commands An array of commands to apply.
|
|
* @param navigationExtras Options that control the navigation strategy.
|
|
* @returns The new URL tree.
|
|
*/
|
|
createUrlTree(commands: any[], navigationExtras?: NavigationExtras): UrlTree {
|
|
return this.router.createUrlTree(commands, navigationExtras);
|
|
}
|
|
|
|
/** Serializes a `UrlTree` into a string */
|
|
serializeUrl(url: UrlTree): string {
|
|
return this.router.serializeUrl(url);
|
|
}
|
|
|
|
/** Parses a string into a `UrlTree` */
|
|
parseUrl(url: string): UrlTree {
|
|
return this.router.parseUrl(url);
|
|
}
|
|
|
|
/** Returns whether the url is activated */
|
|
isActive(url: string | UrlTree, exact: boolean): boolean {
|
|
return this.router.isActive(url, exact);
|
|
}
|
|
|
|
/**
|
|
* open specifc url ...
|
|
*
|
|
* @param url URL address
|
|
* @param target link taget
|
|
*/
|
|
openUrl(url: string, target: XRouterTarget = XRouterTarget.BLANK) {
|
|
//
|
|
if (isNullOrEmptyString(url)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
const link = document.createElement('a');
|
|
link.target = target;
|
|
link.href = url;
|
|
|
|
//
|
|
link.click();
|
|
link.remove();
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Handling Query Param actions ...
|
|
/**
|
|
* change page Query Params ...
|
|
* @param params Query Parameters
|
|
*/
|
|
changeQueryParams(params: Params) {
|
|
//
|
|
return this.router.navigate([], {
|
|
relativeTo: this.activatedRoute,
|
|
queryParams: params,
|
|
queryParamsHandling: 'merge',
|
|
});
|
|
}
|
|
|
|
clearQueryParams() {
|
|
//
|
|
return this.router.navigate([], {
|
|
relativeTo: this.activatedRoute,
|
|
queryParams: {},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get CurrentPages Query Params ...
|
|
*/
|
|
getQueryParams(): Params {
|
|
return this.router.routerState.snapshot.root.queryParams;
|
|
}
|
|
|
|
getQueryParamMap(): ParamMap {
|
|
return this.router.routerState.snapshot.root.queryParamMap;
|
|
}
|
|
|
|
isContainQueryParam(param: XParamIdentifier) {
|
|
return this.getQueryParamMap().has(param);
|
|
}
|
|
|
|
getQueryParamVal(param: XParamIdentifier) {
|
|
//
|
|
if (!this.isContainQueryParam(param)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.getQueryParamMap().get(param);
|
|
}
|
|
|
|
getQueryParamValOfType<T>(param: XParamIdentifier) {
|
|
//
|
|
if (!this.isContainQueryParam(param)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return fromJson<T>(this.getQueryParamMap().get(param));
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Handling Param actions ...
|
|
/**
|
|
* Get CurrentPages Query Params ...
|
|
*/
|
|
getParams(): Params {
|
|
return this.router.routerState.snapshot.root.params;
|
|
}
|
|
|
|
getParamMap(): Params {
|
|
return this.router.routerState.snapshot.root.paramMap;
|
|
}
|
|
|
|
isContainParam(param: XParamIdentifier) {
|
|
return this.getParamMap().has(param);
|
|
}
|
|
|
|
changeParam(params: Params) {
|
|
//
|
|
return this.router.navigate(['', params], {
|
|
relativeTo: this.activatedRoute,
|
|
replaceUrl: true,
|
|
});
|
|
}
|
|
|
|
getParamVal(param: XParamIdentifier) {
|
|
//
|
|
if (!this.isContainParam(param)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.getParamMap().get(param);
|
|
}
|
|
|
|
getParamValOfType<T>(param: XParamIdentifier) {
|
|
//
|
|
if (!this.isContainParam(param)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return fromJson<T>(this.getParamMap().get(param));
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region State Handling ...
|
|
/**
|
|
* change page state ...
|
|
* @param params State Parameters
|
|
*/
|
|
changeState(params: Params) {
|
|
//
|
|
return this.router.navigate([], {
|
|
relativeTo: this.activatedRoute,
|
|
replaceUrl: true,
|
|
state: params,
|
|
});
|
|
}
|
|
|
|
getStates(): Params {
|
|
return this.router.getCurrentNavigation().extras.state || {};
|
|
}
|
|
|
|
isContainState(param: XParamIdentifier) {
|
|
//
|
|
const paramKeys = keys(this.getStates());
|
|
const result = paramKeys.includes(param);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
getStateVal(param: XParamIdentifier) {
|
|
//
|
|
if (!this.isContainState(param)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return this.getStates()[param] || null;
|
|
}
|
|
|
|
getStateValOfType<T>(param: XParamIdentifier) {
|
|
//
|
|
if (!this.isContainState(param)) {
|
|
return null;
|
|
}
|
|
|
|
//
|
|
return fromJson<T>(this.getStateVal(param)) || null;
|
|
}
|
|
//#endregion
|
|
}
|
|
|
|
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkServicesHolder\projects\x-framework-services\src\lib\x-manager-service-partial\x-manager-ui-state.service.ts
|
|
|
|
import {
|
|
XLocale,
|
|
XUiEvent,
|
|
notValue,
|
|
XException,
|
|
XLanguageDirection,
|
|
isNullOrEmptyString,
|
|
} from 'x-framework-core';
|
|
import { Subject, of } from 'rxjs';
|
|
import { filter, concatMap } from 'rxjs/operators';
|
|
import { XManagerBaseService } from './x-manager-base.service';
|
|
|
|
export abstract class XManagerUIStateService extends XManagerBaseService {
|
|
//
|
|
//#region props ...
|
|
private IS_LOADING: boolean;
|
|
private UI_DISABLED: boolean;
|
|
private ERROR: XException = null;
|
|
|
|
//
|
|
public uiStateChanged = new Subject<XUiEvent>();
|
|
|
|
//
|
|
public isMobileUi$ = this.settingsService.isMobile$;
|
|
public isNotMobileUi$ = notValue(this.settingsService.isMobile$);
|
|
|
|
//
|
|
public isLoading$ = this.uiStateChanged.asObservable().pipe(
|
|
filter((uiState) =>
|
|
[XUiEvent.StartLoading, XUiEvent.StopLoading].includes(uiState)
|
|
),
|
|
concatMap((state) => {
|
|
return of(state === XUiEvent.StartLoading ? true : false);
|
|
})
|
|
);
|
|
//#endregion
|
|
|
|
//
|
|
//#region Getter(s) ...
|
|
set uiDisabled(v: boolean) {
|
|
//
|
|
if (v === this.UI_DISABLED) {
|
|
return;
|
|
}
|
|
|
|
this.UI_DISABLED = v;
|
|
this.uiStateChanged.next(v ? XUiEvent.Disabled : XUiEvent.Enabled);
|
|
}
|
|
|
|
//
|
|
get uiDisabled() {
|
|
return this.UI_DISABLED;
|
|
}
|
|
|
|
//
|
|
set loading(v: boolean) {
|
|
//
|
|
if (v === this.IS_LOADING) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.IS_LOADING = v;
|
|
this.uiStateChanged.next(v ? XUiEvent.StartLoading : XUiEvent.StopLoading);
|
|
}
|
|
|
|
//
|
|
get isLoading() {
|
|
return this.IS_LOADING;
|
|
}
|
|
|
|
//
|
|
set error(exception: XException | null) {
|
|
//
|
|
if (exception === this.ERROR) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
this.ERROR = exception;
|
|
|
|
//
|
|
if (exception) {
|
|
//
|
|
if (this.loading) {
|
|
this.loading = false;
|
|
}
|
|
|
|
//
|
|
this.uiDisabled = true;
|
|
} else {
|
|
//
|
|
this.uiDisabled = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
get error() {
|
|
return this.ERROR;
|
|
}
|
|
|
|
//
|
|
get hasError() {
|
|
return !!this.ERROR;
|
|
}
|
|
|
|
//
|
|
get uiDirection(): XLanguageDirection {
|
|
return this.settingsService.uiDirection;
|
|
}
|
|
|
|
//
|
|
get currentLanguage() {
|
|
return this.localizationService.language;
|
|
}
|
|
|
|
//
|
|
get currentLocale(): XLocale {
|
|
return this.localizationService.locale;
|
|
}
|
|
|
|
//
|
|
get isRtl() {
|
|
return this.settingsService.uiDirection === 'rtl';
|
|
}
|
|
|
|
//
|
|
get isLtr() {
|
|
return this.settingsService.uiDirection === 'ltr';
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region UI Actions ...
|
|
//
|
|
public dispatchResizeEvent() {
|
|
//
|
|
window.dispatchEvent(new Event('resize'));
|
|
setTimeout(() => window.dispatchEvent(new Event('resize')), 500);
|
|
}
|
|
|
|
/**
|
|
* save a text value to clipboard ...
|
|
*
|
|
* @param value the content which reuired to save to clipboard ...
|
|
*/
|
|
public saveToClipboard(value: string) {
|
|
//
|
|
if (isNullOrEmptyString(value)) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
if (
|
|
document.queryCommandSupported &&
|
|
document.queryCommandSupported('copy')
|
|
) {
|
|
//
|
|
const textarea = document.createElement('textarea');
|
|
textarea.textContent = value;
|
|
// Prevent scrolling to bottom of page in Microsoft Edge.
|
|
textarea.style.position = 'fixed';
|
|
document.body.appendChild(textarea);
|
|
textarea.select();
|
|
|
|
//
|
|
try {
|
|
// Security exception may be thrown by some browsers.
|
|
return document.execCommand('copy');
|
|
} catch (ex) {
|
|
return false;
|
|
} finally {
|
|
document.body.removeChild(textarea);
|
|
}
|
|
}
|
|
|
|
//
|
|
return false;
|
|
}
|
|
//#endregion
|
|
|
|
//
|
|
//#region Private ...
|
|
//#endregion
|
|
}
|