MOBILE-3320 tsconfig: Use strict checks
parent
b366486aaa
commit
b83d1df97b
|
@ -148,6 +148,7 @@ var appConfig = {
|
|||
'warn',
|
||||
{
|
||||
allowFinally: true,
|
||||
terminationMethod: ['catch', 'finally'],
|
||||
},
|
||||
],
|
||||
'arrow-body-style': ['error', 'as-needed'],
|
||||
|
|
|
@ -40,7 +40,7 @@ export class CoreSingletonsFactory {
|
|||
/**
|
||||
* Angular injector used to resolve singleton instances.
|
||||
*/
|
||||
private injector: Injector;
|
||||
private injector?: Injector;
|
||||
|
||||
/**
|
||||
* Set the injector that will be used to resolve instances in the singletons created with this factory.
|
||||
|
@ -68,6 +68,10 @@ export class CoreSingletonsFactory {
|
|||
static get instance(): Service {
|
||||
// Initialize instances lazily.
|
||||
if (!this.serviceInstance) {
|
||||
if (!factory.injector) {
|
||||
throw new Error('Can\'t resolve a singleton instance without an injector');
|
||||
}
|
||||
|
||||
this.serviceInstance = factory.injector.get(injectionToken);
|
||||
}
|
||||
|
||||
|
|
|
@ -133,8 +133,8 @@ export interface SQLiteDBForeignKeySchema {
|
|||
*/
|
||||
export class SQLiteDB {
|
||||
|
||||
db: SQLiteObject;
|
||||
promise: Promise<void>;
|
||||
db?: SQLiteObject;
|
||||
promise!: Promise<void>;
|
||||
|
||||
/**
|
||||
* Create and open the database.
|
||||
|
@ -164,7 +164,7 @@ export class SQLiteDB {
|
|||
foreignKeys?: SQLiteDBForeignKeySchema[],
|
||||
tableCheck?: string,
|
||||
): string {
|
||||
const columnsSql = [];
|
||||
const columnsSql: string[] = [];
|
||||
let sql = `CREATE TABLE IF NOT EXISTS ${name} (`;
|
||||
|
||||
// First define all the columns.
|
||||
|
@ -225,8 +225,8 @@ export class SQLiteDB {
|
|||
for (const index in foreignKeys) {
|
||||
const foreignKey = foreignKeys[index];
|
||||
|
||||
if (!foreignKey.columns || !!foreignKey.columns.length) {
|
||||
return;
|
||||
if (!foreignKey?.columns.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sql += `, FOREIGN KEY (${foreignKey.columns.join(', ')}) REFERENCES ${foreignKey.table} `;
|
||||
|
@ -251,7 +251,7 @@ export class SQLiteDB {
|
|||
async close(): Promise<void> {
|
||||
await this.ready();
|
||||
|
||||
await this.db.close();
|
||||
await this.db!.close();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -348,10 +348,7 @@ export class SQLiteDB {
|
|||
* @return Promise resolved when success.
|
||||
*/
|
||||
async createTablesFromSchema(tables: SQLiteDBTableSchema[]): Promise<void> {
|
||||
const promises = [];
|
||||
tables.forEach((table) => {
|
||||
promises.push(this.createTableFromSchema(table));
|
||||
});
|
||||
const promises = tables.map(table => this.createTableFromSchema(table));
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
@ -432,7 +429,7 @@ export class SQLiteDB {
|
|||
async execute(sql: string, params?: SQLiteDBRecordValue[]): Promise<any> {
|
||||
await this.ready();
|
||||
|
||||
return this.db.executeSql(sql, params);
|
||||
return this.db!.executeSql(sql, params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -447,7 +444,7 @@ export class SQLiteDB {
|
|||
async executeBatch(sqlStatements: (string | string[] | any)[]): Promise<void> {
|
||||
await this.ready();
|
||||
|
||||
await this.db.sqlBatch(sqlStatements);
|
||||
await this.db!.sqlBatch(sqlStatements);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -532,7 +529,7 @@ export class SQLiteDB {
|
|||
* @return Promise resolved with the field's value.
|
||||
*/
|
||||
async getFieldSql(sql: string, params?: SQLiteDBRecordValue[]): Promise<SQLiteDBRecordValue> {
|
||||
const record = await this.getRecordSql(sql, params);
|
||||
const record = await this.getRecordSql<Record<string, SQLiteDBRecordValue>>(sql, params);
|
||||
if (!record) {
|
||||
throw new CoreError('No record found.');
|
||||
}
|
||||
|
@ -552,7 +549,7 @@ export class SQLiteDB {
|
|||
getInOrEqual(
|
||||
items: SQLiteDBRecordValue | SQLiteDBRecordValue[],
|
||||
equal: boolean = true,
|
||||
onEmptyItems?: SQLiteDBRecordValue,
|
||||
onEmptyItems?: SQLiteDBRecordValue | null,
|
||||
): SQLiteDBQueryParams {
|
||||
let sql = '';
|
||||
let params: SQLiteDBRecordValue[];
|
||||
|
@ -564,7 +561,7 @@ export class SQLiteDB {
|
|||
|
||||
// Handle onEmptyItems on empty array of items.
|
||||
if (Array.isArray(items) && !items.length) {
|
||||
if (onEmptyItems === null) { // Special case, NULL value.
|
||||
if (onEmptyItems === null || typeof onEmptyItems === 'undefined') { // Special case, NULL value.
|
||||
sql = equal ? ' IS NULL' : ' IS NOT NULL';
|
||||
|
||||
return { sql, params: [] };
|
||||
|
@ -758,7 +755,7 @@ export class SQLiteDB {
|
|||
|
||||
const result = await this.execute(sql, params);
|
||||
// Retrieve the records.
|
||||
const records = [];
|
||||
const records: T[] = [];
|
||||
for (let i = 0; i < result.rows.length; i++) {
|
||||
records.push(result.rows.item(i));
|
||||
}
|
||||
|
@ -868,7 +865,7 @@ export class SQLiteDB {
|
|||
* @param limitNum How many results to return.
|
||||
* @return Normalised limit params in array: [limitFrom, limitNum].
|
||||
*/
|
||||
normaliseLimitFromNum(limitFrom: number, limitNum: number): number[] {
|
||||
normaliseLimitFromNum(limitFrom?: number, limitNum?: number): number[] {
|
||||
// We explicilty treat these cases as 0.
|
||||
if (!limitFrom || limitFrom === -1) {
|
||||
limitFrom = 0;
|
||||
|
@ -893,7 +890,7 @@ export class SQLiteDB {
|
|||
async open(): Promise<void> {
|
||||
await this.ready();
|
||||
|
||||
await this.db.open();
|
||||
await this.db!.open();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -994,11 +991,7 @@ export class SQLiteDB {
|
|||
return 0;
|
||||
}
|
||||
|
||||
const sets = [];
|
||||
for (const key in data) {
|
||||
sets.push(`${key} = ?`);
|
||||
}
|
||||
|
||||
const sets = Object.keys(data).map(key => `${key} = ?`);
|
||||
let sql = `UPDATE ${table} SET ${sets.join(', ')}`;
|
||||
if (where) {
|
||||
sql += ` WHERE ${where}`;
|
||||
|
@ -1029,8 +1022,8 @@ export class SQLiteDB {
|
|||
};
|
||||
}
|
||||
|
||||
const where = [];
|
||||
const params = [];
|
||||
const where: string[] = [];
|
||||
const params: SQLiteDBRecordValue[] = [];
|
||||
|
||||
for (const key in conditions) {
|
||||
const value = conditions[key];
|
||||
|
@ -1064,7 +1057,7 @@ export class SQLiteDB {
|
|||
};
|
||||
}
|
||||
|
||||
const params = [];
|
||||
const params: SQLiteDBRecordValue[] = [];
|
||||
let sql = '';
|
||||
|
||||
values.forEach((value) => {
|
||||
|
|
|
@ -20,7 +20,6 @@ import { SQLiteDB } from '@classes/sqlitedb';
|
|||
* Class to mock the interaction with the SQLite database.
|
||||
*/
|
||||
export class SQLiteDBMock extends SQLiteDB {
|
||||
promise: Promise<void>;
|
||||
|
||||
/**
|
||||
* Create and open the database.
|
||||
|
@ -46,9 +45,11 @@ export class SQLiteDBMock extends SQLiteDB {
|
|||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
emptyDatabase(): Promise<any> {
|
||||
async emptyDatabase(): Promise<any> {
|
||||
await this.ready();
|
||||
|
||||
return new Promise((resolve, reject): void => {
|
||||
this.db.transaction((tx) => {
|
||||
this.db!.transaction((tx) => {
|
||||
// Query all tables from sqlite_master that we have created and can modify.
|
||||
const args = [];
|
||||
const query = `SELECT * FROM sqlite_master
|
||||
|
@ -63,7 +64,7 @@ export class SQLiteDBMock extends SQLiteDB {
|
|||
}
|
||||
|
||||
// Drop all the tables.
|
||||
const promises = [];
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
for (let i = 0; i < result.rows.length; i++) {
|
||||
promises.push(new Promise((resolve, reject): void => {
|
||||
|
@ -73,7 +74,7 @@ export class SQLiteDBMock extends SQLiteDB {
|
|||
}));
|
||||
}
|
||||
|
||||
Promise.all(promises).then(resolve, reject);
|
||||
Promise.all(promises).then(resolve).catch(reject);
|
||||
}, reject);
|
||||
});
|
||||
});
|
||||
|
@ -88,14 +89,18 @@ export class SQLiteDBMock extends SQLiteDB {
|
|||
* @param params Query parameters.
|
||||
* @return Promise resolved with the result.
|
||||
*/
|
||||
execute(sql: string, params?: any[]): Promise<any> {
|
||||
async execute(sql: string, params?: any[]): Promise<any> {
|
||||
await this.ready();
|
||||
|
||||
return new Promise((resolve, reject): void => {
|
||||
// With WebSQL, all queries must be run in a transaction.
|
||||
this.db.transaction((tx) => {
|
||||
this.db!.transaction((tx) => {
|
||||
tx.executeSql(sql, params, (tx, results) => {
|
||||
resolve(results);
|
||||
}, (tx, error) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(sql, params, error);
|
||||
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
@ -110,11 +115,13 @@ export class SQLiteDBMock extends SQLiteDB {
|
|||
* @param sqlStatements SQL statements to execute.
|
||||
* @return Promise resolved with the result.
|
||||
*/
|
||||
executeBatch(sqlStatements: any[]): Promise<any> {
|
||||
async executeBatch(sqlStatements: any[]): Promise<any> {
|
||||
await this.ready();
|
||||
|
||||
return new Promise((resolve, reject): void => {
|
||||
// Create a transaction to execute the queries.
|
||||
this.db.transaction((tx) => {
|
||||
const promises = [];
|
||||
this.db!.transaction((tx) => {
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
// Execute all the queries. Each statement can be a string or an array.
|
||||
sqlStatements.forEach((statement) => {
|
||||
|
@ -133,7 +140,9 @@ export class SQLiteDBMock extends SQLiteDB {
|
|||
tx.executeSql(query, params, (tx, results) => {
|
||||
resolve(results);
|
||||
}, (tx, error) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(query, params, error);
|
||||
|
||||
reject(error);
|
||||
});
|
||||
}));
|
||||
|
|
|
@ -45,13 +45,13 @@ export class CoreAppProvider {
|
|||
|
||||
protected db: SQLiteDB;
|
||||
protected logger: CoreLogger;
|
||||
protected ssoAuthenticationDeferred: PromiseDefer<void>;
|
||||
protected ssoAuthenticationDeferred?: PromiseDefer<void>;
|
||||
protected isKeyboardShown = false;
|
||||
protected keyboardOpening = false;
|
||||
protected keyboardClosing = false;
|
||||
protected backActions: {callback: () => boolean; priority: number}[] = [];
|
||||
protected mainMenuId = 0;
|
||||
protected mainMenuOpen: number;
|
||||
protected mainMenuOpen?: number;
|
||||
protected forceOffline = false;
|
||||
|
||||
// Variables for DB.
|
||||
|
@ -224,7 +224,7 @@ export class CoreAppProvider {
|
|||
* @param storesConfig Config params to send the user to the right place.
|
||||
* @return Store URL.
|
||||
*/
|
||||
getAppStoreUrl(storesConfig: CoreStoreConfig): string {
|
||||
getAppStoreUrl(storesConfig: CoreStoreConfig): string | null {
|
||||
if (this.isMac() && storesConfig.mac) {
|
||||
return 'itms-apps://itunes.apple.com/app/' + storesConfig.mac;
|
||||
}
|
||||
|
@ -332,6 +332,8 @@ export class CoreAppProvider {
|
|||
|
||||
try {
|
||||
// @todo return require('os').platform().indexOf('linux') === 0;
|
||||
|
||||
return false;
|
||||
} catch (ex) {
|
||||
return false;
|
||||
}
|
||||
|
@ -349,6 +351,8 @@ export class CoreAppProvider {
|
|||
|
||||
try {
|
||||
// @todo return require('os').platform().indexOf('darwin') === 0;
|
||||
|
||||
return false;
|
||||
} catch (ex) {
|
||||
return false;
|
||||
}
|
||||
|
@ -439,6 +443,8 @@ export class CoreAppProvider {
|
|||
|
||||
try {
|
||||
// @todo return require('os').platform().indexOf('win') === 0;
|
||||
|
||||
return false;
|
||||
} catch (ex) {
|
||||
return false;
|
||||
}
|
||||
|
@ -521,7 +527,9 @@ export class CoreAppProvider {
|
|||
* @return Promise resolved once SSO authentication finishes.
|
||||
*/
|
||||
async waitForSSOAuthentication(): Promise<void> {
|
||||
await this.ssoAuthenticationDeferred && this.ssoAuthenticationDeferred.promise;
|
||||
const promise = this.ssoAuthenticationDeferred?.promise;
|
||||
|
||||
await promise;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -530,7 +538,7 @@ export class CoreAppProvider {
|
|||
* @param timeout Maximum time to wait, use null to wait forever.
|
||||
*/
|
||||
async waitForResume(timeout: number | null = null): Promise<void> {
|
||||
let deferred = CoreUtils.instance.promiseDefer<void>();
|
||||
let deferred: PromiseDefer<void> | null = CoreUtils.instance.promiseDefer<void>();
|
||||
|
||||
const stopWaiting = () => {
|
||||
if (!deferred) {
|
||||
|
@ -556,13 +564,13 @@ export class CoreAppProvider {
|
|||
* @return Object with siteid, state, params and timemodified.
|
||||
*/
|
||||
getRedirect<Params extends Record<string, unknown> = Record<string, unknown>>(): CoreRedirectData<Params> {
|
||||
if (localStorage && localStorage.getItem) {
|
||||
if (localStorage?.getItem) {
|
||||
try {
|
||||
const paramsJson = localStorage.getItem('CoreRedirectParams');
|
||||
const data: CoreRedirectData<Params> = {
|
||||
siteId: localStorage.getItem('CoreRedirectSiteId'),
|
||||
page: localStorage.getItem('CoreRedirectState'),
|
||||
timemodified: parseInt(localStorage.getItem('CoreRedirectTime'), 10),
|
||||
siteId: localStorage.getItem('CoreRedirectSiteId') || undefined,
|
||||
page: localStorage.getItem('CoreRedirectState') || undefined,
|
||||
timemodified: parseInt(localStorage.getItem('CoreRedirectTime') || '0', 10),
|
||||
};
|
||||
|
||||
if (paramsJson) {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
|
||||
import { CoreUtils, PromiseDefer, OrderedPromiseData } from '@services/utils/utils';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
import { makeSingleton } from '@singletons/core.singletons';
|
||||
|
||||
|
@ -56,7 +56,7 @@ export class CoreInitDelegate {
|
|||
|
||||
protected initProcesses: { [s: string]: CoreInitHandler } = {};
|
||||
protected logger: CoreLogger;
|
||||
protected readiness: CoreInitReadinessPromiseDefer<void>;
|
||||
protected readiness?: CoreInitReadinessPromiseDefer<void>;
|
||||
|
||||
constructor() {
|
||||
this.logger = CoreLogger.getInstance('CoreInitDelegate');
|
||||
|
@ -68,7 +68,7 @@ export class CoreInitDelegate {
|
|||
* Reserved for core use, do not call directly.
|
||||
*/
|
||||
executeInitProcesses(): void {
|
||||
let ordered = [];
|
||||
const ordered: CoreInitHandler[] = [];
|
||||
|
||||
if (typeof this.readiness == 'undefined') {
|
||||
this.initReadiness();
|
||||
|
@ -78,15 +78,15 @@ export class CoreInitDelegate {
|
|||
for (const name in this.initProcesses) {
|
||||
ordered.push(this.initProcesses[name]);
|
||||
}
|
||||
ordered.sort((a, b) => b.priority - a.priority);
|
||||
ordered.sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
||||
|
||||
ordered = ordered.map((data: CoreInitHandler) => ({
|
||||
const orderedPromises: OrderedPromiseData[] = ordered.map((data: CoreInitHandler) => ({
|
||||
function: this.prepareProcess.bind(this, data),
|
||||
blocking: !!data.blocking,
|
||||
}));
|
||||
|
||||
// Execute all the processes in order to solve dependencies.
|
||||
CoreUtils.instance.executeOrderedPromises(ordered).finally(this.readiness.resolve);
|
||||
CoreUtils.instance.executeOrderedPromises(orderedPromises).finally(this.readiness!.resolve);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,7 +94,9 @@ export class CoreInitDelegate {
|
|||
*/
|
||||
protected initReadiness(): void {
|
||||
this.readiness = CoreUtils.instance.promiseDefer();
|
||||
this.readiness.promise.then(() => this.readiness.resolved = true);
|
||||
|
||||
// eslint-disable-next-line promise/catch-or-return
|
||||
this.readiness.promise.then(() => this.readiness!.resolved = true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,7 +105,7 @@ export class CoreInitDelegate {
|
|||
* @return Whether it's ready.
|
||||
*/
|
||||
isReady(): boolean {
|
||||
return this.readiness.resolved;
|
||||
return this.readiness?.resolved || false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,7 +135,7 @@ export class CoreInitDelegate {
|
|||
this.initReadiness();
|
||||
}
|
||||
|
||||
await this.readiness.promise;
|
||||
await this.readiness!.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,9 +30,9 @@ export class CoreLangProvider {
|
|||
|
||||
protected fallbackLanguage = 'en'; // Always use English as fallback language since it contains all strings.
|
||||
protected defaultLanguage = CoreConfigConstants.default_lang || 'en'; // Lang to use if device lang not valid or is forced.
|
||||
protected currentLanguage: string; // Save current language in a variable to speed up the get function.
|
||||
protected currentLanguage?: string; // Save current language in a variable to speed up the get function.
|
||||
protected customStrings: CoreLanguageObject = {}; // Strings defined using the admin tool.
|
||||
protected customStringsRaw: string;
|
||||
protected customStringsRaw?: string;
|
||||
protected sitePluginsStrings: CoreLanguageObject = {}; // Strings defined by site plugins.
|
||||
|
||||
constructor() {
|
||||
|
@ -123,7 +123,7 @@ export class CoreLangProvider {
|
|||
* @return Promise resolved when the change is finished.
|
||||
*/
|
||||
async changeCurrentLanguage(language: string): Promise<void> {
|
||||
const promises = [];
|
||||
const promises: Promise<unknown>[] = [];
|
||||
|
||||
// Change the language, resolving the promise when we receive the first value.
|
||||
promises.push(new Promise((resolve, reject) => {
|
||||
|
@ -363,8 +363,8 @@ export class CoreLangProvider {
|
|||
if (currentLangChanged) {
|
||||
// Some lang strings have changed, emit an event to update the pipes.
|
||||
Translate.instance.onLangChange.emit({
|
||||
lang: this.currentLanguage,
|
||||
translations: Translate.instance.translations[this.currentLanguage],
|
||||
lang: this.currentLanguage!,
|
||||
translations: Translate.instance.translations[this.currentLanguage!],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ export class CoreIframeUtilsProvider {
|
|||
}
|
||||
|
||||
// Remove the warning and show the iframe
|
||||
CoreDomUtils.instance.removeElement(element.parentElement, 'div.core-iframe-offline-warning');
|
||||
CoreDomUtils.instance.removeElement(element.parentElement!, 'div.core-iframe-offline-warning');
|
||||
element.classList.remove('core-iframe-offline-disabled');
|
||||
|
||||
if (isSubframe) {
|
||||
|
@ -131,9 +131,9 @@ export class CoreIframeUtilsProvider {
|
|||
* @param element Element to treat (iframe, embed, ...).
|
||||
* @return Window and Document.
|
||||
*/
|
||||
getContentWindowAndDocument(element: CoreFrameElement): { window: Window; document: Document } {
|
||||
let contentWindow: Window = 'contentWindow' in element ? element.contentWindow : undefined;
|
||||
let contentDocument: Document;
|
||||
getContentWindowAndDocument(element: CoreFrameElement): { window: Window | null; document: Document | null } {
|
||||
let contentWindow: Window | null = 'contentWindow' in element ? element.contentWindow : null;
|
||||
let contentDocument: Document | null = null;
|
||||
|
||||
try {
|
||||
contentDocument = 'contentDocument' in element && element.contentDocument
|
||||
|
@ -209,7 +209,8 @@ export class CoreIframeUtilsProvider {
|
|||
contentWindow.open = (url: string, name: string) => {
|
||||
this.windowOpen(url, name, element, navCtrl);
|
||||
|
||||
return null;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return null as any;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -233,31 +234,35 @@ export class CoreIframeUtilsProvider {
|
|||
* @param navCtrl NavController to use if a link can be opened in the app.
|
||||
*/
|
||||
treatFrame(element: CoreFrameElement, isSubframe?: boolean, navCtrl?: NavController): void {
|
||||
if (element) {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
const treatElement = (sendResizeEvent: boolean = false) => {
|
||||
this.checkOnlineFrameInOffline(element, isSubframe);
|
||||
|
||||
let winAndDoc = this.getContentWindowAndDocument(element);
|
||||
const { window, document } = this.getContentWindowAndDocument(element);
|
||||
|
||||
// Redefine window.open in this element and sub frames, it might have been loaded already.
|
||||
this.redefineWindowOpen(element, winAndDoc.window, winAndDoc.document, navCtrl);
|
||||
if (window && document) {
|
||||
this.redefineWindowOpen(element, window, document, navCtrl);
|
||||
}
|
||||
|
||||
// Treat links.
|
||||
this.treatFrameLinks(element, winAndDoc.document);
|
||||
if (document) {
|
||||
this.treatFrameLinks(element, document);
|
||||
}
|
||||
|
||||
element.addEventListener('load', () => {
|
||||
this.checkOnlineFrameInOffline(element, isSubframe);
|
||||
// Send a resize events to the iframe so it calculates the right size if needed.
|
||||
if (window && sendResizeEvent) {
|
||||
setTimeout(() => window.dispatchEvent(new Event('resize')), 1000);
|
||||
}
|
||||
};
|
||||
|
||||
// Element loaded, redefine window.open and treat links again.
|
||||
winAndDoc = this.getContentWindowAndDocument(element);
|
||||
this.redefineWindowOpen(element, winAndDoc.window, winAndDoc.document, navCtrl);
|
||||
this.treatFrameLinks(element, winAndDoc.document);
|
||||
treatElement();
|
||||
|
||||
if (winAndDoc.window) {
|
||||
// Send a resize events to the iframe so it calculates the right size if needed.
|
||||
setTimeout(() => {
|
||||
winAndDoc.window.dispatchEvent(new Event('resize'));
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Element loaded, redefine window.open and treat links again.
|
||||
element.addEventListener('load', () => treatElement(true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -279,7 +284,7 @@ export class CoreIframeUtilsProvider {
|
|||
}
|
||||
|
||||
// Find the link being clicked.
|
||||
let el = <Element> event.target;
|
||||
let el: Element | null = event.target as Element;
|
||||
while (el && el.tagName !== 'A') {
|
||||
el = el.parentElement;
|
||||
}
|
||||
|
@ -386,19 +391,24 @@ export class CoreIframeUtilsProvider {
|
|||
}
|
||||
|
||||
const urlParts = CoreUrl.parse(link.href);
|
||||
if (!link.href || (urlParts.protocol && urlParts.protocol == 'javascript')) {
|
||||
if (!link.href || !urlParts || (urlParts.protocol && urlParts.protocol == 'javascript')) {
|
||||
// Links with no URL and Javascript links are ignored.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CoreUrlUtils.instance.isLocalFileUrlScheme(urlParts.protocol)) {
|
||||
if (urlParts.protocol && !CoreUrlUtils.instance.isLocalFileUrlScheme(urlParts.protocol)) {
|
||||
// Scheme suggests it's an external resource.
|
||||
event && event.preventDefault();
|
||||
|
||||
const frameSrc = element && ((<HTMLFrameElement> element).src || (<HTMLObjectElement> element).data);
|
||||
|
||||
// If the frame is not local, check the target to identify how to treat the link.
|
||||
if (element && !CoreUrlUtils.instance.isLocalFileUrl(frameSrc) && (!link.target || link.target == '_self')) {
|
||||
if (
|
||||
element &&
|
||||
frameSrc &&
|
||||
!CoreUrlUtils.instance.isLocalFileUrl(frameSrc) &&
|
||||
(!link.target || link.target == '_self')
|
||||
) {
|
||||
// Load the link inside the frame itself.
|
||||
if (element.tagName.toLowerCase() == 'object') {
|
||||
element.setAttribute('data', link.href);
|
||||
|
@ -455,8 +465,8 @@ export class CoreIframeUtilsProvider {
|
|||
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({
|
||||
userScriptWindow.WKUserScript?.addScript({ id: 'CoreIframeUtilsLinksScript', file: linksPath });
|
||||
userScriptWindow.WKUserScript?.addScript({
|
||||
id: 'CoreIframeUtilsRecaptchaScript',
|
||||
file: recaptchaPath,
|
||||
injectionTime: WKUserScriptInjectionTime.END,
|
||||
|
|
|
@ -116,7 +116,7 @@ export class CoreMimetypeUtilsProvider {
|
|||
*/
|
||||
protected fillGroupMimeInfo(group: string): void {
|
||||
const mimetypes = {}; // Use an object to prevent duplicates.
|
||||
const extensions = []; // Extensions are unique.
|
||||
const extensions: string[] = []; // Extensions are unique.
|
||||
|
||||
for (const extension in this.extToMime) {
|
||||
const data = this.extToMime[extension];
|
||||
|
@ -140,13 +140,13 @@ export class CoreMimetypeUtilsProvider {
|
|||
* @param url URL of the file. It will be used if there's more than one possible extension.
|
||||
* @return Extension.
|
||||
*/
|
||||
getExtension(mimetype: string, url?: string): string {
|
||||
getExtension(mimetype: string, url?: string): string | undefined {
|
||||
mimetype = mimetype || '';
|
||||
mimetype = mimetype.split(';')[0]; // Remove codecs from the mimetype if any.
|
||||
|
||||
if (mimetype == 'application/x-forcedownload' || mimetype == 'application/forcedownload') {
|
||||
// Couldn't get the right mimetype, try to guess it.
|
||||
return this.guessExtensionFromUrl(url);
|
||||
return url && this.guessExtensionFromUrl(url);
|
||||
}
|
||||
|
||||
const extensions = this.mimeToExt[mimetype];
|
||||
|
@ -154,7 +154,7 @@ export class CoreMimetypeUtilsProvider {
|
|||
if (extensions.length > 1 && url) {
|
||||
// There's more than one possible extension. Check if the URL has extension.
|
||||
const candidate = this.guessExtensionFromUrl(url);
|
||||
if (extensions.indexOf(candidate) != -1) {
|
||||
if (candidate && extensions.indexOf(candidate) != -1) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
@ -173,19 +173,22 @@ export class CoreMimetypeUtilsProvider {
|
|||
const filename = CoreUtils.instance.isFileEntry(file) ? (file as FileEntry).name : file.filename;
|
||||
const extension = !CoreUtils.instance.isFileEntry(file) && file.mimetype
|
||||
? this.getExtension(file.mimetype)
|
||||
: this.getFileExtension(filename);
|
||||
const mimeType = !CoreUtils.instance.isFileEntry(file) && file.mimetype ? file.mimetype : this.getMimeType(extension);
|
||||
: (filename && this.getFileExtension(filename));
|
||||
const mimeType = !CoreUtils.instance.isFileEntry(file) && file.mimetype
|
||||
? file.mimetype
|
||||
: (extension && this.getMimeType(extension));
|
||||
|
||||
// @todo linting: See if this can be removed
|
||||
(file as CoreWSExternalFile).mimetype = mimeType;
|
||||
|
||||
if (this.canBeEmbedded(extension)) {
|
||||
if (extension && this.canBeEmbedded(extension)) {
|
||||
const embedType = this.getExtensionType(extension);
|
||||
|
||||
// @todo linting: See if this can be removed
|
||||
(file as { embedType: string }).embedType = embedType;
|
||||
(file as { embedType?: string }).embedType = embedType;
|
||||
|
||||
path = CoreFile.instance.convertFileSrc(path ?? (CoreUtils.instance.isFileEntry(file) ? file.toURL() : file.fileurl));
|
||||
path = path ?? (CoreUtils.instance.isFileEntry(file) ? file.toURL() : file.fileurl);
|
||||
path = path && CoreFile.instance.convertFileSrc(path);
|
||||
|
||||
switch (embedType) {
|
||||
case 'image':
|
||||
|
@ -223,7 +226,7 @@ export class CoreMimetypeUtilsProvider {
|
|||
* @param extension Extension.
|
||||
* @return Icon. Undefined if not found.
|
||||
*/
|
||||
getExtensionIconName(extension: string): string {
|
||||
getExtensionIconName(extension: string): string | undefined {
|
||||
if (this.extToMime[extension]) {
|
||||
if (this.extToMime[extension].icon) {
|
||||
return this.extToMime[extension].icon;
|
||||
|
@ -242,7 +245,7 @@ export class CoreMimetypeUtilsProvider {
|
|||
* @param extension Extension.
|
||||
* @return Type of the extension.
|
||||
*/
|
||||
getExtensionType(extension: string): string {
|
||||
getExtensionType(extension: string): string | undefined {
|
||||
extension = this.cleanExtension(extension);
|
||||
|
||||
if (this.extToMime[extension] && this.extToMime[extension].string) {
|
||||
|
@ -270,8 +273,8 @@ export class CoreMimetypeUtilsProvider {
|
|||
* @return The path to a file icon.
|
||||
*/
|
||||
getFileIcon(filename: string): string {
|
||||
const ext = this.getFileExtension(filename);
|
||||
const icon = this.getExtensionIconName(ext) || 'unknown';
|
||||
const extension = this.getFileExtension(filename);
|
||||
const icon = (extension && this.getExtensionIconName(extension)) || 'unknown';
|
||||
|
||||
return this.getFileIconForType(icon);
|
||||
}
|
||||
|
@ -302,14 +305,14 @@ export class CoreMimetypeUtilsProvider {
|
|||
* @param fileUrl The file URL.
|
||||
* @return The lowercased extension without the dot, or undefined.
|
||||
*/
|
||||
guessExtensionFromUrl(fileUrl: string): string {
|
||||
guessExtensionFromUrl(fileUrl: string): string | undefined {
|
||||
const split = fileUrl.split('.');
|
||||
let candidate;
|
||||
let extension;
|
||||
let position;
|
||||
|
||||
if (split.length > 1) {
|
||||
candidate = split.pop().toLowerCase();
|
||||
candidate = split.pop()!.toLowerCase();
|
||||
// Remove params if any.
|
||||
position = candidate.indexOf('?');
|
||||
if (position > -1) {
|
||||
|
@ -338,7 +341,7 @@ export class CoreMimetypeUtilsProvider {
|
|||
* @param filename The file name.
|
||||
* @return The lowercased extension, or undefined.
|
||||
*/
|
||||
getFileExtension(filename: string): string {
|
||||
getFileExtension(filename: string): string | undefined {
|
||||
const dot = filename.lastIndexOf('.');
|
||||
let ext;
|
||||
|
||||
|
@ -382,7 +385,7 @@ export class CoreMimetypeUtilsProvider {
|
|||
* @param extension Extension.
|
||||
* @return Mimetype.
|
||||
*/
|
||||
getMimeType(extension: string): string {
|
||||
getMimeType(extension: string): string | undefined {
|
||||
extension = this.cleanExtension(extension);
|
||||
|
||||
if (this.extToMime[extension] && this.extToMime[extension].type) {
|
||||
|
@ -400,9 +403,9 @@ export class CoreMimetypeUtilsProvider {
|
|||
*/
|
||||
getMimetypeDescription(obj: FileEntry | { filename: string; mimetype: string } | string, capitalise?: boolean): string {
|
||||
const langPrefix = 'assets.mimetypes.';
|
||||
let filename = '';
|
||||
let mimetype = '';
|
||||
let extension = '';
|
||||
let filename: string | undefined = '';
|
||||
let mimetype: string | undefined = '';
|
||||
let extension: string | undefined = '';
|
||||
|
||||
if (typeof obj == 'object' && CoreUtils.instance.isFileEntry(obj)) {
|
||||
// It's a FileEntry. Don't use the file function because it's asynchronous and the type isn't reliable.
|
||||
|
@ -419,7 +422,7 @@ export class CoreMimetypeUtilsProvider {
|
|||
|
||||
if (!mimetype) {
|
||||
// Try to calculate the mimetype using the extension.
|
||||
mimetype = this.getMimeType(extension);
|
||||
mimetype = extension && this.getMimeType(extension);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,7 +481,7 @@ export class CoreMimetypeUtilsProvider {
|
|||
* @param mimetype Mimetype.
|
||||
* @return Type of the mimetype.
|
||||
*/
|
||||
getMimetypeType(mimetype: string): string {
|
||||
getMimetypeType(mimetype: string): string | undefined {
|
||||
mimetype = mimetype.split(';')[0]; // Remove codecs from the mimetype if any.
|
||||
|
||||
const extensions = this.mimeToExt[mimetype];
|
||||
|
@ -542,9 +545,9 @@ export class CoreMimetypeUtilsProvider {
|
|||
isExtensionInGroup(extension: string, groups: string[]): boolean {
|
||||
extension = this.cleanExtension(extension);
|
||||
|
||||
if (groups && groups.length && this.extToMime[extension] && this.extToMime[extension].groups) {
|
||||
for (let i = 0; i < this.extToMime[extension].groups.length; i++) {
|
||||
const group = this.extToMime[extension].groups[i];
|
||||
if (groups?.length && this.extToMime[extension]?.groups) {
|
||||
for (let i = 0; i < this.extToMime[extension].groups!.length; i++) {
|
||||
const group = this.extToMime[extension].groups![i];
|
||||
if (groups.indexOf(group) != -1) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -175,11 +175,11 @@ export class CoreTextUtilsProvider {
|
|||
// Filter invalid messages, and convert them to messages in case they're errors.
|
||||
const messages: string[] = [];
|
||||
|
||||
paragraphs.forEach((paragraph) => {
|
||||
paragraphs.forEach(paragraph => {
|
||||
// If it's an error, get its message.
|
||||
const message = this.getErrorMessageFromError(paragraph);
|
||||
|
||||
if (paragraph) {
|
||||
if (paragraph && message) {
|
||||
messages.push(message);
|
||||
}
|
||||
});
|
||||
|
@ -248,8 +248,7 @@ export class CoreTextUtilsProvider {
|
|||
// First, we use a regexpr.
|
||||
text = text.replace(/(<([^>]+)>)/ig, '');
|
||||
// Then, we rely on the browser. We need to wrap the text to be sure is HTML.
|
||||
const element = this.convertToElement(text);
|
||||
text = element.textContent;
|
||||
text = this.convertToElement(text).textContent!;
|
||||
// Recover or remove new lines.
|
||||
text = this.replaceNewLines(text, singleLine ? ' ' : '<br>');
|
||||
|
||||
|
@ -326,7 +325,7 @@ export class CoreTextUtilsProvider {
|
|||
text = text.replace(/_/gi, ' ');
|
||||
|
||||
// This RegEx will detect any word change including Unicode chars. Some languages without spaces won't be counted fine.
|
||||
return text.match(/\S+/gi).length;
|
||||
return text.match(/\S+/gi)?.length || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -359,8 +358,7 @@ export class CoreTextUtilsProvider {
|
|||
*/
|
||||
decodeHTMLEntities(text: string): string {
|
||||
if (text) {
|
||||
const element = this.convertToElement(text);
|
||||
text = element.textContent;
|
||||
text = this.convertToElement(text).textContent!;
|
||||
}
|
||||
|
||||
return text;
|
||||
|
@ -512,7 +510,7 @@ export class CoreTextUtilsProvider {
|
|||
if (clean) {
|
||||
formatted = this.cleanTags(formatted, singleLine);
|
||||
}
|
||||
if (shortenLength > 0) {
|
||||
if (shortenLength && shortenLength > 0) {
|
||||
formatted = this.shortenText(formatted, shortenLength);
|
||||
}
|
||||
if (highlight) {
|
||||
|
@ -529,10 +527,11 @@ export class CoreTextUtilsProvider {
|
|||
* @param error Error object.
|
||||
* @return Error message, undefined if not found.
|
||||
*/
|
||||
getErrorMessageFromError(error: string | CoreError | CoreTextErrorObject): string {
|
||||
getErrorMessageFromError(error?: string | CoreError | CoreTextErrorObject): string | undefined {
|
||||
if (typeof error == 'string') {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (error instanceof CoreError) {
|
||||
return error.message;
|
||||
}
|
||||
|
@ -546,12 +545,12 @@ export class CoreTextUtilsProvider {
|
|||
* @param files Files to extract the URL from. They need to have the URL in a 'url' or 'fileurl' attribute.
|
||||
* @return Pluginfile URL, undefined if no files found.
|
||||
*/
|
||||
getTextPluginfileUrl(files: CoreWSExternalFile[]): string {
|
||||
if (files && files.length) {
|
||||
getTextPluginfileUrl(files: CoreWSExternalFile[]): string | undefined {
|
||||
if (files?.length) {
|
||||
const url = files[0].fileurl;
|
||||
|
||||
// Remove text after last slash (encoded or not).
|
||||
return url.substr(0, Math.max(url.lastIndexOf('/'), url.lastIndexOf('%2F')));
|
||||
return url?.substr(0, Math.max(url.lastIndexOf('/'), url.lastIndexOf('%2F')));
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
@ -876,7 +875,7 @@ export class CoreTextUtilsProvider {
|
|||
// Current lang not found. Try to find the first language.
|
||||
const matches = text.match(anyLangRegEx);
|
||||
if (matches && matches[0]) {
|
||||
language = matches[0].match(/lang="([a-zA-Z0-9_-]+)"/)[1];
|
||||
language = matches[0].match(/lang="([a-zA-Z0-9_-]+)"/)![1];
|
||||
currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)</(?:lang|span)>', 'g');
|
||||
} else {
|
||||
// No multi-lang tag found, stop.
|
||||
|
|
|
@ -42,9 +42,9 @@ export class CoreUtilsProvider {
|
|||
protected readonly DONT_CLONE = ['[object FileEntry]', '[object DirectoryEntry]', '[object DOMFileSystem]'];
|
||||
|
||||
protected logger: CoreLogger;
|
||||
protected iabInstance: InAppBrowserObject;
|
||||
protected iabInstance?: InAppBrowserObject;
|
||||
protected uniqueIds: {[name: string]: number} = {};
|
||||
protected qrScanData: {deferred: PromiseDefer<string>; observable: Subscription};
|
||||
protected qrScanData?: {deferred: PromiseDefer<string>; observable: Subscription};
|
||||
|
||||
constructor(protected zone: NgZone) {
|
||||
this.logger = CoreLogger.getInstance('CoreUtilsProvider');
|
||||
|
@ -61,22 +61,14 @@ export class CoreUtilsProvider {
|
|||
* @return New error message.
|
||||
*/
|
||||
addDataNotDownloadedError(error: Error | string, defaultError?: string): string {
|
||||
let errorMessage = error;
|
||||
const errorMessage = CoreTextUtils.instance.getErrorMessageFromError(error) || defaultError || '';
|
||||
|
||||
if (error && typeof error != 'string') {
|
||||
errorMessage = CoreTextUtils.instance.getErrorMessageFromError(error);
|
||||
if (this.isWebServiceError(error)) {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
if (typeof errorMessage != 'string') {
|
||||
errorMessage = defaultError || '';
|
||||
}
|
||||
|
||||
if (!this.isWebServiceError(error)) {
|
||||
// Local error. Add an extra warning.
|
||||
errorMessage += '<br><br>' + Translate.instance.instant('core.errorsomedatanotdownloaded');
|
||||
}
|
||||
|
||||
return errorMessage;
|
||||
// Local error. Add an extra warning.
|
||||
return errorMessage + '<br><br>' + Translate.instance.instant('core.errorsomedatanotdownloaded');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,12 +108,16 @@ export class CoreUtilsProvider {
|
|||
* @param result Object where to put the properties. If not defined, a new object will be created.
|
||||
* @return The object.
|
||||
*/
|
||||
arrayToObject(array: unknown[], propertyName?: string, result?: unknown): unknown {
|
||||
result = result || {};
|
||||
array.forEach((entry) => {
|
||||
arrayToObject<T extends Record<string, unknown> | string>(
|
||||
array: T[],
|
||||
propertyName?: string,
|
||||
result: Record<string, T> = {},
|
||||
): Record<string, T> {
|
||||
for (const entry of array) {
|
||||
const key = propertyName ? entry[propertyName] : entry;
|
||||
|
||||
result[key] = entry;
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -144,7 +140,7 @@ export class CoreUtilsProvider {
|
|||
maxLevels: number = 0,
|
||||
level: number = 0,
|
||||
undefinedIsNull: boolean = true,
|
||||
): boolean {
|
||||
): boolean | undefined {
|
||||
if (typeof itemA == 'function' || typeof itemB == 'function') {
|
||||
return true; // Don't compare functions.
|
||||
} else if (typeof itemA == 'object' && typeof itemB == 'object') {
|
||||
|
@ -266,9 +262,9 @@ export class CoreUtilsProvider {
|
|||
}
|
||||
|
||||
return newArray;
|
||||
} else if (typeof source == 'object' && source !== null) {
|
||||
} else if (this.isObject(source)) {
|
||||
// Check if the object shouldn't be copied.
|
||||
if (source && source.toString && this.DONT_CLONE.indexOf(source.toString()) != -1) {
|
||||
if (source.toString && this.DONT_CLONE.indexOf(source.toString()) != -1) {
|
||||
// Object shouldn't be copied, return it as it is.
|
||||
return source;
|
||||
}
|
||||
|
@ -365,7 +361,7 @@ export class CoreUtilsProvider {
|
|||
* @return Promise resolved when all promises are resolved.
|
||||
*/
|
||||
executeOrderedPromises(orderedPromisesData: OrderedPromiseData[]): Promise<void> {
|
||||
const promises = [];
|
||||
const promises: Promise<void>[] = [];
|
||||
let dependency = Promise.resolve();
|
||||
|
||||
// Execute all the processes in order.
|
||||
|
@ -465,8 +461,8 @@ export class CoreUtilsProvider {
|
|||
checkAll?: boolean,
|
||||
...args: P
|
||||
): Promise<string[]> {
|
||||
const promises = [];
|
||||
const enabledSites = [];
|
||||
const promises: Promise<false | number>[] = [];
|
||||
const enabledSites: string[] = [];
|
||||
|
||||
for (const i in siteIds) {
|
||||
const siteId = siteIds[i];
|
||||
|
@ -626,7 +622,7 @@ export class CoreUtilsProvider {
|
|||
// Get the keys of the countries.
|
||||
return this.getCountryList().then((countries) => {
|
||||
// Sort translations.
|
||||
const sortedCountries = [];
|
||||
const sortedCountries: { code: string; name: string }[] = [];
|
||||
|
||||
Object.keys(countries).sort((a, b) => countries[a].localeCompare(countries[b])).forEach((key) => {
|
||||
sortedCountries.push({ code: key, name: countries[key] });
|
||||
|
@ -669,7 +665,7 @@ export class CoreUtilsProvider {
|
|||
const table = await CoreLang.instance.getTranslationTable(lang);
|
||||
|
||||
// Gather all the keys for countries,
|
||||
const keys = [];
|
||||
const keys: string[] = [];
|
||||
|
||||
for (const name in table) {
|
||||
if (name.indexOf('assets.countries.') === 0) {
|
||||
|
@ -696,7 +692,7 @@ export class CoreUtilsProvider {
|
|||
getMimeTypeFromUrl(url: string): Promise<string> {
|
||||
// First check if it can be guessed from the URL.
|
||||
const extension = CoreMimetypeUtils.instance.guessExtensionFromUrl(url);
|
||||
const mimetype = CoreMimetypeUtils.instance.getMimeType(extension);
|
||||
const mimetype = extension && CoreMimetypeUtils.instance.getMimeType(extension);
|
||||
|
||||
if (mimetype) {
|
||||
return Promise.resolve(mimetype);
|
||||
|
@ -730,6 +726,16 @@ export class CoreUtilsProvider {
|
|||
return 'isFile' in file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a value is an object.
|
||||
*
|
||||
* @param object Variable.
|
||||
* @return Type guard indicating if this is an object.
|
||||
*/
|
||||
isObject(object: unknown): object is Record<string, unknown> {
|
||||
return typeof object === 'object' && object !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of files, check if there are repeated names.
|
||||
*
|
||||
|
@ -741,12 +747,12 @@ export class CoreUtilsProvider {
|
|||
return false;
|
||||
}
|
||||
|
||||
const names = [];
|
||||
const names: string[] = [];
|
||||
|
||||
// Check if there are 2 files with the same name.
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
const name = this.isFileEntry(file) ? file.name : file.filename;
|
||||
const name = (this.isFileEntry(file) ? file.name : file.filename) || '';
|
||||
|
||||
if (names.indexOf(name) > -1) {
|
||||
return Translate.instance.instant('core.filenameexist', { $a: name });
|
||||
|
@ -885,7 +891,7 @@ export class CoreUtilsProvider {
|
|||
path = CoreFile.instance.unconvertFileSrc(path);
|
||||
|
||||
const extension = CoreMimetypeUtils.instance.getFileExtension(path);
|
||||
const mimetype = CoreMimetypeUtils.instance.getMimeType(extension);
|
||||
const mimetype = extension && CoreMimetypeUtils.instance.getMimeType(extension);
|
||||
|
||||
if (mimetype == 'text/html' && CoreApp.instance.isAndroid()) {
|
||||
// Open HTML local files in InAppBrowser, in system browser some embedded files aren't loaded.
|
||||
|
@ -902,7 +908,7 @@ export class CoreUtilsProvider {
|
|||
}
|
||||
|
||||
try {
|
||||
await FileOpener.instance.open(path, mimetype);
|
||||
await FileOpener.instance.open(path, mimetype || '');
|
||||
} catch (error) {
|
||||
this.logger.error('Error opening file ' + path + ' with mimetype ' + mimetype);
|
||||
this.logger.error('Error: ', JSON.stringify(error));
|
||||
|
@ -924,7 +930,7 @@ export class CoreUtilsProvider {
|
|||
* @param options Override default options passed to InAppBrowser.
|
||||
* @return The opened window.
|
||||
*/
|
||||
openInApp(url: string, options?: InAppBrowserOptions): InAppBrowserObject {
|
||||
openInApp(url: string, options?: InAppBrowserOptions): InAppBrowserObject | undefined {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
@ -950,7 +956,7 @@ export class CoreUtilsProvider {
|
|||
|
||||
if (CoreApp.instance.isDesktop() || CoreApp.instance.isMobile()) {
|
||||
let loadStopSubscription;
|
||||
const loadStartUrls = [];
|
||||
const loadStartUrls: string[] = [];
|
||||
|
||||
// Trigger global events when a url is loaded or the window is closed. This is to make it work like in Ionic 1.
|
||||
const loadStartSubscription = this.iabInstance.on('loadstart').subscribe((event) => {
|
||||
|
@ -1076,10 +1082,10 @@ export class CoreUtilsProvider {
|
|||
if (typeof value == 'undefined' || value == null) {
|
||||
// Filter undefined and null values.
|
||||
return;
|
||||
} else if (typeof value == 'object') {
|
||||
} else if (this.isObject(value)) {
|
||||
// It's an object, return at least an entry for each property.
|
||||
const keys = Object.keys(value);
|
||||
let entries = [];
|
||||
let entries: unknown[] = [];
|
||||
|
||||
keys.forEach((key) => {
|
||||
const newElKey = elKey ? elKey + '[' + key + ']' : key;
|
||||
|
@ -1110,9 +1116,9 @@ export class CoreUtilsProvider {
|
|||
if (sortByKey || sortByValue) {
|
||||
return entries.sort((a, b) => {
|
||||
if (sortByKey) {
|
||||
return a[keyName] >= b[keyName] ? 1 : -1;
|
||||
return (a[keyName] as number) >= (b[keyName] as number) ? 1 : -1;
|
||||
} else {
|
||||
return a[valueName] >= b[valueName] ? 1 : -1;
|
||||
return (a[valueName] as number) >= (b[valueName] as number) ? 1 : -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1135,7 +1141,7 @@ export class CoreUtilsProvider {
|
|||
keyName: string,
|
||||
valueName: string,
|
||||
keyPrefix?: string,
|
||||
): {[name: string]: unknown} {
|
||||
): {[name: string]: unknown} | undefined {
|
||||
if (!objects) {
|
||||
return;
|
||||
}
|
||||
|
@ -1206,13 +1212,13 @@ export class CoreUtilsProvider {
|
|||
* @return The deferred promise.
|
||||
*/
|
||||
promiseDefer<T>(): PromiseDefer<T> {
|
||||
const deferred: PromiseDefer<T> = {};
|
||||
const deferred: Partial<PromiseDefer<T>> = {};
|
||||
deferred.promise = new Promise((resolve, reject): void => {
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
|
||||
return deferred;
|
||||
return deferred as PromiseDefer<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1257,7 +1263,11 @@ export class CoreUtilsProvider {
|
|||
* @param key Key to check.
|
||||
* @return Whether the two objects/arrays have the same value (or lack of one) for a given key.
|
||||
*/
|
||||
sameAtKeyMissingIsBlank(obj1: unknown, obj2: unknown, key: string): boolean {
|
||||
sameAtKeyMissingIsBlank(
|
||||
obj1: Record<string, unknown> | unknown[],
|
||||
obj2: Record<string, unknown> | unknown[],
|
||||
key: string,
|
||||
): boolean {
|
||||
let value1 = typeof obj1[key] != 'undefined' ? obj1[key] : '';
|
||||
let value2 = typeof obj2[key] != 'undefined' ? obj2[key] : '';
|
||||
|
||||
|
@ -1426,19 +1436,19 @@ export class CoreUtilsProvider {
|
|||
* @return Array without duplicate values.
|
||||
*/
|
||||
uniqueArray<T>(array: T[], key?: string): T[] {
|
||||
const filtered = [];
|
||||
const unique = {}; // Use an object to make it faster to check if it's duplicate.
|
||||
|
||||
array.forEach((entry) => {
|
||||
return array.filter(entry => {
|
||||
const value = key ? entry[key] : entry;
|
||||
|
||||
if (!unique[value]) {
|
||||
if (value in unique) {
|
||||
unique[value] = true;
|
||||
filtered.push(entry);
|
||||
}
|
||||
});
|
||||
|
||||
return filtered;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1487,7 +1497,14 @@ export class CoreUtilsProvider {
|
|||
*
|
||||
* @return Promise resolved with the QR string, rejected if error or cancelled.
|
||||
*/
|
||||
async startScanQR(): Promise<string> {
|
||||
async startScanQR(): Promise<string | undefined> {
|
||||
try {
|
||||
return this.startScanQR();
|
||||
} catch (error) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
if (!CoreApp.instance.isMobile()) {
|
||||
return Promise.reject('QRScanner isn\'t available in desktop apps.');
|
||||
}
|
||||
|
@ -1613,21 +1630,21 @@ export type PromiseDefer<T> = {
|
|||
/**
|
||||
* The promise.
|
||||
*/
|
||||
promise?: Promise<T>;
|
||||
promise: Promise<T>;
|
||||
|
||||
/**
|
||||
* Function to resolve the promise.
|
||||
*
|
||||
* @param value The resolve value.
|
||||
*/
|
||||
resolve?: (value?: T) => void; // Function to resolve the promise.
|
||||
resolve: (value?: T) => void; // Function to resolve the promise.
|
||||
|
||||
/**
|
||||
* Function to reject the promise.
|
||||
*
|
||||
* @param reason The reject param.
|
||||
*/
|
||||
reject?: (reason?: unknown) => void;
|
||||
reject: (reason?: unknown) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,6 +15,12 @@
|
|||
import moment from 'moment';
|
||||
import { environment } from '@/environments/environment';
|
||||
|
||||
|
||||
/**
|
||||
* Log function type.
|
||||
*/
|
||||
type LogFunction = (...data: unknown[]) => void;
|
||||
|
||||
/**
|
||||
* Helper service to display messages in the console.
|
||||
*
|
||||
|
@ -34,9 +40,13 @@ export class CoreLogger {
|
|||
debug: LogFunction;
|
||||
error: LogFunction;
|
||||
|
||||
// Avoid creating singleton instances.
|
||||
private constructor() {
|
||||
// Nothing to do.
|
||||
// Avoid creating instances.
|
||||
private constructor(log: LogFunction, info: LogFunction, warn: LogFunction, debug: LogFunction, error: LogFunction) {
|
||||
this.log = log;
|
||||
this.info = info;
|
||||
this.warn = warn;
|
||||
this.debug = debug;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,29 +64,23 @@ export class CoreLogger {
|
|||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const muted = () => {};
|
||||
|
||||
return {
|
||||
log: muted,
|
||||
info: muted,
|
||||
warn: muted,
|
||||
debug: muted,
|
||||
error: muted,
|
||||
};
|
||||
return new CoreLogger(muted, muted, muted, muted, muted);
|
||||
}
|
||||
|
||||
className = className || '';
|
||||
|
||||
return {
|
||||
return new CoreLogger(
|
||||
// eslint-disable-next-line no-console
|
||||
log: CoreLogger.prepareLogFn(console.log.bind(console), className),
|
||||
CoreLogger.prepareLogFn(console.log.bind(console), className),
|
||||
// eslint-disable-next-line no-console
|
||||
info: CoreLogger.prepareLogFn(console.info.bind(console), className),
|
||||
CoreLogger.prepareLogFn(console.info.bind(console), className),
|
||||
// eslint-disable-next-line no-console
|
||||
warn: CoreLogger.prepareLogFn(console.warn.bind(console), className),
|
||||
CoreLogger.prepareLogFn(console.warn.bind(console), className),
|
||||
// eslint-disable-next-line no-console
|
||||
debug: CoreLogger.prepareLogFn(console.debug.bind(console), className),
|
||||
CoreLogger.prepareLogFn(console.debug.bind(console), className),
|
||||
// eslint-disable-next-line no-console
|
||||
error: CoreLogger.prepareLogFn(console.error.bind(console), className),
|
||||
};
|
||||
CoreLogger.prepareLogFn(console.error.bind(console), className),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,8 +100,3 @@ export class CoreLogger {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Log function type.
|
||||
*/
|
||||
type LogFunction = (...data: unknown[]) => void;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"strictNullChecks": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
|
|
Loading…
Reference in New Issue