MOBILE-3320 lint: Update linting rules
parent
58e7a78ee7
commit
43946fb61e
50
.eslintrc.js
50
.eslintrc.js
|
@ -15,6 +15,7 @@ module.exports = {
|
||||||
'prettier/@typescript-eslint',
|
'prettier/@typescript-eslint',
|
||||||
'plugin:jest/recommended',
|
'plugin:jest/recommended',
|
||||||
'plugin:@angular-eslint/recommended',
|
'plugin:@angular-eslint/recommended',
|
||||||
|
'plugin:promise/recommended',
|
||||||
],
|
],
|
||||||
parser: '@typescript-eslint/parser',
|
parser: '@typescript-eslint/parser',
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
|
@ -22,11 +23,12 @@ module.exports = {
|
||||||
sourceType: 'module',
|
sourceType: 'module',
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
'eslint-plugin-prefer-arrow',
|
|
||||||
'eslint-plugin-jsdoc',
|
|
||||||
'@typescript-eslint',
|
'@typescript-eslint',
|
||||||
'header',
|
'header',
|
||||||
'jest',
|
'jest',
|
||||||
|
'jsdoc',
|
||||||
|
'prefer-arrow',
|
||||||
|
'promise',
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
'@angular-eslint/component-class-suffix': ['error', { suffixes: ['Component', 'Page'] }],
|
'@angular-eslint/component-class-suffix': ['error', { suffixes: ['Component', 'Page'] }],
|
||||||
|
@ -56,7 +58,29 @@ module.exports = {
|
||||||
accessibility: 'no-public',
|
accessibility: 'no-public',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'@typescript-eslint/indent': 'off',
|
'@typescript-eslint/explicit-module-boundary-types': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowArgumentsExplicitlyTypedAsAny: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/indent': [
|
||||||
|
'error',
|
||||||
|
4,
|
||||||
|
{
|
||||||
|
SwitchCase: 1,
|
||||||
|
ignoredNodes: [
|
||||||
|
'ClassProperty *',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/lines-between-class-members': [
|
||||||
|
'error',
|
||||||
|
'always',
|
||||||
|
{
|
||||||
|
exceptAfterSingleLine: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
'@typescript-eslint/member-delimiter-style': [
|
'@typescript-eslint/member-delimiter-style': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
@ -104,18 +128,6 @@ module.exports = {
|
||||||
'always',
|
'always',
|
||||||
],
|
],
|
||||||
'@typescript-eslint/type-annotation-spacing': 'error',
|
'@typescript-eslint/type-annotation-spacing': 'error',
|
||||||
'@typescript-eslint/typedef': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
arrayDestructuring: false,
|
|
||||||
arrowParameter: false,
|
|
||||||
memberVariableDeclaration: true,
|
|
||||||
objectDestructuring: false,
|
|
||||||
parameter: true,
|
|
||||||
propertyDeclaration: true,
|
|
||||||
variableDeclaration: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'@typescript-eslint/unified-signatures': 'error',
|
'@typescript-eslint/unified-signatures': 'error',
|
||||||
'header/header': [
|
'header/header': [
|
||||||
2,
|
2,
|
||||||
|
@ -137,12 +149,20 @@ module.exports = {
|
||||||
],
|
],
|
||||||
1,
|
1,
|
||||||
],
|
],
|
||||||
|
'promise/catch-or-return': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
allowFinally: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
'arrow-body-style': ['error', 'as-needed'],
|
'arrow-body-style': ['error', 'as-needed'],
|
||||||
'array-bracket-spacing': ['error', 'never'],
|
'array-bracket-spacing': ['error', 'never'],
|
||||||
'comma-dangle': ['error', 'always-multiline'],
|
'comma-dangle': ['error', 'always-multiline'],
|
||||||
'constructor-super': 'error',
|
'constructor-super': 'error',
|
||||||
'curly': 'error',
|
'curly': 'error',
|
||||||
'eol-last': 'error',
|
'eol-last': 'error',
|
||||||
|
'function-call-argument-newline': ['error', 'consistent'],
|
||||||
|
'function-paren-newline': ['error', 'multiline-arguments'],
|
||||||
'id-blacklist': [
|
'id-blacklist': [
|
||||||
'error',
|
'error',
|
||||||
'any',
|
'any',
|
||||||
|
|
|
@ -7826,6 +7826,12 @@
|
||||||
"integrity": "sha512-C8YMhL+r8RMeMdYAw/rQtE6xNdMulj+zGWud/qIGnlmomiPRaLDGLMeskZ3alN6uMBojmooRimtdrXebLN4svQ==",
|
"integrity": "sha512-C8YMhL+r8RMeMdYAw/rQtE6xNdMulj+zGWud/qIGnlmomiPRaLDGLMeskZ3alN6uMBojmooRimtdrXebLN4svQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"eslint-plugin-promise": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"eslint-scope": {
|
"eslint-scope": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
|
||||||
|
|
|
@ -130,6 +130,7 @@
|
||||||
"eslint-plugin-jest": "^24.1.0",
|
"eslint-plugin-jest": "^24.1.0",
|
||||||
"eslint-plugin-jsdoc": "^30.6.3",
|
"eslint-plugin-jsdoc": "^30.6.3",
|
||||||
"eslint-plugin-prefer-arrow": "^1.2.2",
|
"eslint-plugin-prefer-arrow": "^1.2.2",
|
||||||
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
"faker": "^5.1.0",
|
"faker": "^5.1.0",
|
||||||
"jest": "^26.5.0",
|
"jest": "^26.5.0",
|
||||||
"jest-preset-angular": "^8.3.1",
|
"jest-preset-angular": "^8.3.1",
|
||||||
|
|
|
@ -51,25 +51,9 @@ export class CoreIframeUtilsProvider {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.logger = CoreLogger.getInstance('CoreUtilsProvider');
|
this.logger = CoreLogger.getInstance('CoreUtilsProvider');
|
||||||
|
|
||||||
const win = <WKUserScriptWindow> window;
|
if (CoreApp.instance.isIOS() && 'WKUserScript' in window) {
|
||||||
|
// eslint-disable-next-line promise/catch-or-return
|
||||||
if (CoreApp.instance.isIOS() && win.WKUserScript) {
|
Platform.instance.ready().then(() => this.injectiOSScripts(window));
|
||||||
Platform.instance.ready().then(() => {
|
|
||||||
// Inject code to the iframes because we cannot access the online ones.
|
|
||||||
const wwwPath = CoreFile.instance.getWWWAbsolutePath();
|
|
||||||
const linksPath = CoreTextUtils.instance.concatenatePaths(wwwPath, 'assets/js/iframe-treat-links.js');
|
|
||||||
const recaptchaPath = CoreTextUtils.instance.concatenatePaths(wwwPath, 'assets/js/iframe-recaptcha.js');
|
|
||||||
|
|
||||||
win.WKUserScript.addScript({ id: 'CoreIframeUtilsLinksScript', file: linksPath });
|
|
||||||
win.WKUserScript.addScript({
|
|
||||||
id: 'CoreIframeUtilsRecaptchaScript',
|
|
||||||
file: recaptchaPath,
|
|
||||||
injectionTime: WKUserScriptInjectionTime.END,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle post messages received by iframes.
|
|
||||||
window.addEventListener('message', this.handleIframeMessage.bind(this));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,11 +198,15 @@ export class CoreIframeUtilsProvider {
|
||||||
* @param contentDocument The document of the element contents.
|
* @param contentDocument The document of the element contents.
|
||||||
* @param navCtrl NavController to use if a link can be opened in the app.
|
* @param navCtrl NavController to use if a link can be opened in the app.
|
||||||
*/
|
*/
|
||||||
redefineWindowOpen(element: CoreFrameElement, contentWindow: Window, contentDocument: Document,
|
redefineWindowOpen(
|
||||||
navCtrl?: NavController): void {
|
element: CoreFrameElement,
|
||||||
|
contentWindow: Window,
|
||||||
|
contentDocument: Document,
|
||||||
|
navCtrl?: NavController,
|
||||||
|
): void {
|
||||||
if (contentWindow) {
|
if (contentWindow) {
|
||||||
// Intercept window.open.
|
// Intercept window.open.
|
||||||
contentWindow.open = (url: string, name: string): Window => {
|
contentWindow.open = (url: string, name: string) => {
|
||||||
this.windowOpen(url, name, element, navCtrl);
|
this.windowOpen(url, name, element, navCtrl);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -387,8 +375,11 @@ export class CoreIframeUtilsProvider {
|
||||||
* @param event Click event.
|
* @param event Click event.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected async linkClicked(link: {href: string; target?: string}, element?: HTMLFrameElement | HTMLObjectElement,
|
protected async linkClicked(
|
||||||
event?: Event): Promise<void> {
|
link: {href: string; target?: string},
|
||||||
|
element?: HTMLFrameElement | HTMLObjectElement,
|
||||||
|
event?: Event,
|
||||||
|
): Promise<void> {
|
||||||
if (event && event.defaultPrevented) {
|
if (event && event.defaultPrevented) {
|
||||||
// Event already prevented by some other code.
|
// Event already prevented by some other code.
|
||||||
return;
|
return;
|
||||||
|
@ -454,6 +445,27 @@ export class CoreIframeUtilsProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject code to the iframes because we cannot access the online ones.
|
||||||
|
*
|
||||||
|
* @param userScriptWindow Window.
|
||||||
|
*/
|
||||||
|
private injectiOSScripts(userScriptWindow: WKUserScriptWindow) {
|
||||||
|
const wwwPath = CoreFile.instance.getWWWAbsolutePath();
|
||||||
|
const linksPath = CoreTextUtils.instance.concatenatePaths(wwwPath, 'assets/js/iframe-treat-links.js');
|
||||||
|
const recaptchaPath = CoreTextUtils.instance.concatenatePaths(wwwPath, 'assets/js/iframe-recaptcha.js');
|
||||||
|
|
||||||
|
userScriptWindow.WKUserScript.addScript({ id: 'CoreIframeUtilsLinksScript', file: linksPath });
|
||||||
|
userScriptWindow.WKUserScript.addScript({
|
||||||
|
id: 'CoreIframeUtilsRecaptchaScript',
|
||||||
|
file: recaptchaPath,
|
||||||
|
injectionTime: WKUserScriptInjectionTime.END,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle post messages received by iframes.
|
||||||
|
window.addEventListener('message', this.handleIframeMessage.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CoreIframeUtils extends makeSingleton(CoreIframeUtilsProvider) {}
|
export class CoreIframeUtils extends makeSingleton(CoreIframeUtilsProvider) {}
|
||||||
|
|
|
@ -450,8 +450,17 @@ export class CoreTextUtilsProvider {
|
||||||
* @param courseId Course ID the text belongs to. It can be used to improve performance with filters.
|
* @param courseId Course ID the text belongs to. It can be used to improve performance with filters.
|
||||||
* @deprecated since 3.8.3. Please use viewText instead.
|
* @deprecated since 3.8.3. Please use viewText instead.
|
||||||
*/
|
*/
|
||||||
expandText(title: string, text: string, component?: string, componentId?: string | number, files?: CoreWSExternalFile[],
|
expandText(
|
||||||
filter?: boolean, contextLevel?: string, instanceId?: number, courseId?: number): void {
|
title: string,
|
||||||
|
text: string,
|
||||||
|
component?: string,
|
||||||
|
componentId?: string | number,
|
||||||
|
files?: CoreWSExternalFile[],
|
||||||
|
filter?: boolean,
|
||||||
|
contextLevel?: string,
|
||||||
|
instanceId?: number,
|
||||||
|
courseId?: number,
|
||||||
|
): void {
|
||||||
return this.viewText(title, text, {
|
return this.viewText(title, text, {
|
||||||
component,
|
component,
|
||||||
componentId,
|
componentId,
|
||||||
|
|
|
@ -48,12 +48,8 @@ export class CoreUtilsProvider {
|
||||||
constructor(protected zone: NgZone) {
|
constructor(protected zone: NgZone) {
|
||||||
this.logger = CoreLogger.getInstance('CoreUtilsProvider');
|
this.logger = CoreLogger.getInstance('CoreUtilsProvider');
|
||||||
|
|
||||||
Platform.instance.ready().then(() => {
|
// eslint-disable-next-line promise/catch-or-return
|
||||||
if (window.cordova && window.cordova.InAppBrowser) {
|
Platform.instance.ready().then(() => this.overrideWindowOpen());
|
||||||
// Override the default window.open with the InAppBrowser one.
|
|
||||||
window.open = window.cordova.InAppBrowser.open;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,7 +72,7 @@ export class CoreUtilsProvider {
|
||||||
|
|
||||||
if (!this.isWebServiceError(error)) {
|
if (!this.isWebServiceError(error)) {
|
||||||
// Local error. Add an extra warning.
|
// Local error. Add an extra warning.
|
||||||
errorMessage += '<br><br>' + Translate.instance.instant('core.errorsomedatanotdownloaded');
|
errorMessage += '<br><br>' + Translate.instance.instant('core.errorsomedatanotdownloaded');
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorMessage;
|
return errorMessage;
|
||||||
|
@ -88,35 +84,25 @@ export class CoreUtilsProvider {
|
||||||
* @param promises Promises.
|
* @param promises Promises.
|
||||||
* @return Promise resolved if all promises are resolved and rejected if at least 1 promise fails.
|
* @return Promise resolved if all promises are resolved and rejected if at least 1 promise fails.
|
||||||
*/
|
*/
|
||||||
allPromises(promises: Promise<unknown>[]): Promise<void> {
|
async allPromises(promises: Promise<unknown>[]): Promise<void> {
|
||||||
if (!promises || !promises.length) {
|
if (!promises || !promises.length) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject): void => {
|
const getPromiseError = async (promise): Promise<Error | void> => {
|
||||||
const total = promises.length;
|
try {
|
||||||
let count = 0;
|
await promise;
|
||||||
let hasFailed = false;
|
} catch (error) {
|
||||||
let error;
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
promises.forEach((promise) => {
|
const errors = await Promise.all(promises.map(getPromiseError));
|
||||||
promise.catch((err) => {
|
const error = errors.find(error => !!error);
|
||||||
hasFailed = true;
|
|
||||||
error = err;
|
|
||||||
}).finally(() => {
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (count === total) {
|
if (error) {
|
||||||
// All promises have finished, reject/resolve.
|
throw error;
|
||||||
if (hasFailed) {
|
}
|
||||||
reject(error);
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,9 +137,13 @@ export class CoreUtilsProvider {
|
||||||
* @param undefinedIsNull True if undefined is equal to null. Defaults to true.
|
* @param undefinedIsNull True if undefined is equal to null. Defaults to true.
|
||||||
* @return Whether both items are equal.
|
* @return Whether both items are equal.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
|
basicLeftCompare(
|
||||||
basicLeftCompare(itemA: any, itemB: any, maxLevels: number = 0,
|
itemA: any, // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
level: number = 0, undefinedIsNull: boolean = true): boolean {
|
itemB: any, // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
maxLevels: number = 0,
|
||||||
|
level: number = 0,
|
||||||
|
undefinedIsNull: boolean = true,
|
||||||
|
): boolean {
|
||||||
if (typeof itemA == 'function' || typeof itemB == 'function') {
|
if (typeof itemA == 'function' || typeof itemB == 'function') {
|
||||||
return true; // Don't compare functions.
|
return true; // Don't compare functions.
|
||||||
} else if (typeof itemA == 'object' && typeof itemB == 'object') {
|
} else if (typeof itemA == 'object' && typeof itemB == 'object') {
|
||||||
|
@ -467,19 +457,24 @@ export class CoreUtilsProvider {
|
||||||
* @param ...args All the params sent after checkAll will be passed to isEnabledFn.
|
* @param ...args All the params sent after checkAll will be passed to isEnabledFn.
|
||||||
* @return Promise resolved with the list of enabled sites.
|
* @return Promise resolved with the list of enabled sites.
|
||||||
*/
|
*/
|
||||||
filterEnabledSites<P extends []>(siteIds: string[], isEnabledFn: (siteId, ...args: P) => boolean | Promise<boolean>,
|
filterEnabledSites<P extends unknown[]>(
|
||||||
checkAll?: boolean, ...args: P): Promise<string[]> {
|
siteIds: string[],
|
||||||
|
isEnabledFn: (siteId, ...args: P) => boolean | Promise<boolean>,
|
||||||
|
checkAll?: boolean,
|
||||||
|
...args: P
|
||||||
|
): Promise<string[]> {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
const enabledSites = [];
|
const enabledSites = [];
|
||||||
|
|
||||||
for (const i in siteIds) {
|
for (const i in siteIds) {
|
||||||
const siteId = siteIds[i];
|
const siteId = siteIds[i];
|
||||||
|
const pushIfEnabled = enabled => enabled && enabledSites.push(siteId);
|
||||||
if (checkAll || !promises.length) {
|
if (checkAll || !promises.length) {
|
||||||
promises.push(Promise.resolve(isEnabledFn.apply(isEnabledFn, [siteId].concat(args))).then((enabled) => {
|
promises.push(
|
||||||
if (enabled) {
|
Promise
|
||||||
enabledSites.push(siteId);
|
.resolve(isEnabledFn(siteId, ...args))
|
||||||
}
|
.then(pushIfEnabled),
|
||||||
}));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,8 +522,13 @@ export class CoreUtilsProvider {
|
||||||
* @param maxDepth Max Depth to convert to tree. Children found will be in the last level of depth.
|
* @param maxDepth Max Depth to convert to tree. Children found will be in the last level of depth.
|
||||||
* @return Array with the formatted tree, children will be on each node under children field.
|
* @return Array with the formatted tree, children will be on each node under children field.
|
||||||
*/
|
*/
|
||||||
formatTree<T>(list: T[], parentFieldName: string = 'parent', idFieldName: string = 'id', rootParentId: number = 0,
|
formatTree<T>(
|
||||||
maxDepth: number = 5): TreeNode<T>[] {
|
list: T[],
|
||||||
|
parentFieldName: string = 'parent',
|
||||||
|
idFieldName: string = 'id',
|
||||||
|
rootParentId: number = 0,
|
||||||
|
maxDepth: number = 5,
|
||||||
|
): TreeNode<T>[] {
|
||||||
const map = {};
|
const map = {};
|
||||||
const mapDepth = {};
|
const mapDepth = {};
|
||||||
const tree: TreeNode<T>[] = [];
|
const tree: TreeNode<T>[] = [];
|
||||||
|
@ -649,7 +649,7 @@ export class CoreUtilsProvider {
|
||||||
|
|
||||||
if (fallbackLang === defaultLang) {
|
if (fallbackLang === defaultLang) {
|
||||||
// Same language, just reject.
|
// Same language, just reject.
|
||||||
return Promise.reject('Countries not found.');
|
throw new Error('Countries not found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getCountryKeysListForLanguage(fallbackLang);
|
return this.getCountryKeysListForLanguage(fallbackLang);
|
||||||
|
@ -786,7 +786,7 @@ export class CoreUtilsProvider {
|
||||||
* @param value Value to check.
|
* @param value Value to check.
|
||||||
* @return Whether the value is false, 0 or "0".
|
* @return Whether the value is false, 0 or "0".
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
isFalseOrZero(value: any): boolean {
|
isFalseOrZero(value: any): boolean {
|
||||||
return typeof value != 'undefined' && (value === false || value === 'false' || parseInt(value, 10) === 0);
|
return typeof value != 'undefined' && (value === false || value === 'false' || parseInt(value, 10) === 0);
|
||||||
}
|
}
|
||||||
|
@ -797,7 +797,7 @@ export class CoreUtilsProvider {
|
||||||
* @param value Value to check.
|
* @param value Value to check.
|
||||||
* @return Whether the value is true, 1 or "1".
|
* @return Whether the value is true, 1 or "1".
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
isTrueOrOne(value: any): boolean {
|
isTrueOrOne(value: any): boolean {
|
||||||
return typeof value != 'undefined' && (value === true || value === 'true' || parseInt(value, 10) === 1);
|
return typeof value != 'undefined' && (value === true || value === 'true' || parseInt(value, 10) === 1);
|
||||||
}
|
}
|
||||||
|
@ -808,7 +808,7 @@ export class CoreUtilsProvider {
|
||||||
* @param error Error to check.
|
* @param error Error to check.
|
||||||
* @return Whether the error was returned by the WebService.
|
* @return Whether the error was returned by the WebService.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
isWebServiceError(error: any): boolean {
|
isWebServiceError(error: any): boolean {
|
||||||
return error && (typeof error.warningcode != 'undefined' || (typeof error.errorcode != 'undefined' &&
|
return error && (typeof error.warningcode != 'undefined' || (typeof error.errorcode != 'undefined' &&
|
||||||
error.errorcode != 'invalidtoken' && error.errorcode != 'userdeleted' && error.errorcode != 'upgraderunning' &&
|
error.errorcode != 'invalidtoken' && error.errorcode != 'userdeleted' && error.errorcode != 'upgraderunning' &&
|
||||||
|
@ -827,8 +827,12 @@ export class CoreUtilsProvider {
|
||||||
* @param defaultValue Element that will become default option value. Default 0.
|
* @param defaultValue Element that will become default option value. Default 0.
|
||||||
* @return The now assembled array
|
* @return The now assembled array
|
||||||
*/
|
*/
|
||||||
makeMenuFromList<T>(list: string, defaultLabel?: string, separator: string = ',',
|
makeMenuFromList<T>(
|
||||||
defaultValue?: T): { label: string; value: T | number }[] {
|
list: string,
|
||||||
|
defaultLabel?: string,
|
||||||
|
separator: string = ',',
|
||||||
|
defaultValue?: T,
|
||||||
|
): { label: string; value: T | number }[] {
|
||||||
// Split and format the list.
|
// Split and format the list.
|
||||||
const split = list.split(separator).map((label, index) => ({
|
const split = list.split(separator).map((label, index) => ({
|
||||||
label: label.trim(),
|
label: label.trim(),
|
||||||
|
@ -863,7 +867,7 @@ export class CoreUtilsProvider {
|
||||||
* @param value Value to check.
|
* @param value Value to check.
|
||||||
* @return True if not null and not undefined.
|
* @return True if not null and not undefined.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
notNullOrUndefined(value: any): boolean {
|
notNullOrUndefined(value: any): boolean {
|
||||||
return typeof value != 'undefined' && value !== null;
|
return typeof value != 'undefined' && value !== null;
|
||||||
}
|
}
|
||||||
|
@ -1008,36 +1012,32 @@ export class CoreUtilsProvider {
|
||||||
* @param url The URL of the file.
|
* @param url The URL of the file.
|
||||||
* @return Promise resolved when opened.
|
* @return Promise resolved when opened.
|
||||||
*/
|
*/
|
||||||
openOnlineFile(url: string): Promise<void> {
|
async openOnlineFile(url: string): Promise<void> {
|
||||||
if (CoreApp.instance.isAndroid()) {
|
if (CoreApp.instance.isAndroid()) {
|
||||||
// In Android we need the mimetype to open it.
|
// In Android we need the mimetype to open it.
|
||||||
return this.getMimeTypeFromUrl(url).catch(() => {
|
const mimetype = await this.ignoreErrors(this.getMimeTypeFromUrl(url));
|
||||||
// Error getting mimetype, return undefined.
|
|
||||||
}).then((mimetype) => {
|
|
||||||
if (!mimetype) {
|
|
||||||
// Couldn't retrieve mimetype. Return error.
|
|
||||||
return Promise.reject(Translate.instance.instant('core.erroropenfilenoextension'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = {
|
if (!mimetype) {
|
||||||
action: WebIntent.instance.ACTION_VIEW,
|
// Couldn't retrieve mimetype. Return error.
|
||||||
url,
|
throw new Error(Translate.instance.instant('core.erroropenfilenoextension'));
|
||||||
type: mimetype,
|
}
|
||||||
};
|
|
||||||
|
|
||||||
return WebIntent.instance.startActivity(options).catch((error) => {
|
const options = {
|
||||||
this.logger.error('Error opening online file ' + url + ' with mimetype ' + mimetype);
|
action: WebIntent.instance.ACTION_VIEW,
|
||||||
this.logger.error('Error: ', JSON.stringify(error));
|
url,
|
||||||
|
type: mimetype,
|
||||||
|
};
|
||||||
|
|
||||||
return Promise.reject(Translate.instance.instant('core.erroropenfilenoapp'));
|
return WebIntent.instance.startActivity(options).catch((error) => {
|
||||||
});
|
this.logger.error('Error opening online file ' + url + ' with mimetype ' + mimetype);
|
||||||
|
this.logger.error('Error: ', JSON.stringify(error));
|
||||||
|
|
||||||
|
throw new Error(Translate.instance.instant('core.erroropenfilenoapp'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the rest of platforms we need to open them in InAppBrowser.
|
// In the rest of platforms we need to open them in InAppBrowser.
|
||||||
this.openInApp(url);
|
this.openInApp(url);
|
||||||
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1062,8 +1062,13 @@ export class CoreUtilsProvider {
|
||||||
* @param sortByValue True to sort values alphabetically, false otherwise.
|
* @param sortByValue True to sort values alphabetically, false otherwise.
|
||||||
* @return Array of objects with the name & value of each property.
|
* @return Array of objects with the name & value of each property.
|
||||||
*/
|
*/
|
||||||
objectToArrayOfObjects(obj: Record<string, unknown>, keyName: string, valueName: string, sortByKey?: boolean,
|
objectToArrayOfObjects(
|
||||||
sortByValue?: boolean): Record<string, unknown>[] {
|
obj: Record<string, unknown>,
|
||||||
|
keyName: string,
|
||||||
|
valueName: string,
|
||||||
|
sortByKey?: boolean,
|
||||||
|
sortByValue?: boolean,
|
||||||
|
): Record<string, unknown>[] {
|
||||||
// Get the entries from an object or primitive value.
|
// Get the entries from an object or primitive value.
|
||||||
const getEntries = (elKey: string, value: unknown): Record<string, unknown>[] | unknown => {
|
const getEntries = (elKey: string, value: unknown): Record<string, unknown>[] | unknown => {
|
||||||
if (typeof value == 'undefined' || value == null) {
|
if (typeof value == 'undefined' || value == null) {
|
||||||
|
@ -1123,8 +1128,12 @@ export class CoreUtilsProvider {
|
||||||
* @param keyPrefix Key prefix if neededs to delete it.
|
* @param keyPrefix Key prefix if neededs to delete it.
|
||||||
* @return Object.
|
* @return Object.
|
||||||
*/
|
*/
|
||||||
objectToKeyValueMap(objects: Record<string, unknown>[], keyName: string, valueName: string,
|
objectToKeyValueMap(
|
||||||
keyPrefix?: string): {[name: string]: unknown} {
|
objects: Record<string, unknown>[],
|
||||||
|
keyName: string,
|
||||||
|
valueName: string,
|
||||||
|
keyPrefix?: string,
|
||||||
|
): {[name: string]: unknown} {
|
||||||
if (!objects) {
|
if (!objects) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1343,13 +1352,25 @@ export class CoreUtilsProvider {
|
||||||
*/
|
*/
|
||||||
timeoutPromise<T>(promise: Promise<T>, time: number): Promise<T> {
|
timeoutPromise<T>(promise: Promise<T>, time: number): Promise<T> {
|
||||||
return new Promise((resolve, reject): void => {
|
return new Promise((resolve, reject): void => {
|
||||||
const timeout = setTimeout(() => {
|
let timedOut = false;
|
||||||
reject({ timeout: true });
|
const resolveBeforeTimeout = () => {
|
||||||
}, time);
|
if (timedOut) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
const timeout = setTimeout(
|
||||||
|
() => {
|
||||||
|
reject({ timeout: true });
|
||||||
|
timedOut = true;
|
||||||
|
},
|
||||||
|
time,
|
||||||
|
);
|
||||||
|
|
||||||
promise.then(resolve).catch(reject).finally(() => {
|
promise
|
||||||
clearTimeout(timeout);
|
.then(resolveBeforeTimeout)
|
||||||
});
|
.catch(reject)
|
||||||
|
.finally(() => clearTimeout(timeout));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1362,7 +1383,7 @@ export class CoreUtilsProvider {
|
||||||
* @param strict If true, then check the input and return false if it is not a valid number.
|
* @param strict If true, then check the input and return false if it is not a valid number.
|
||||||
* @return False if bad format, empty string if empty value or the parsed float if not.
|
* @return False if bad format, empty string if empty value or the parsed float if not.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
unformatFloat(localeFloat: any, strict?: boolean): false | '' | number {
|
unformatFloat(localeFloat: any, strict?: boolean): false | '' | number {
|
||||||
// Bad format on input type number.
|
// Bad format on input type number.
|
||||||
if (typeof localeFloat == 'undefined') {
|
if (typeof localeFloat == 'undefined') {
|
||||||
|
@ -1568,6 +1589,17 @@ export class CoreUtilsProvider {
|
||||||
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override native window.open with InAppBrowser if available.
|
||||||
|
*/
|
||||||
|
private overrideWindowOpen() {
|
||||||
|
if (!window.cordova?.InAppBrowser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.open = window.cordova.InAppBrowser.open;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CoreUtils extends makeSingleton(CoreUtilsProvider) {}
|
export class CoreUtils extends makeSingleton(CoreUtilsProvider) {}
|
||||||
|
|
Loading…
Reference in New Issue