MOBILE-4653 utils: Move opener related utils functions

main
Pau Ferrer Ocaña 2024-11-15 13:06:55 +01:00
parent 8ba784564b
commit e72fea3630
36 changed files with 598 additions and 510 deletions

View File

@ -22,7 +22,7 @@ import { CoreWSError } from '@classes/errors/wserror';
import { makeSingleton, Translate } from '@singletons'; import { makeSingleton, Translate } from '@singletons';
import { CoreEvents, CoreEventSiteData } from '@singletons/events'; import { CoreEvents, CoreEventSiteData } from '@singletons/events';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from '@singletons/opener';
import { CorePath } from '@singletons/path'; import { CorePath } from '@singletons/path';
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
@ -222,7 +222,7 @@ export class AddonMessageOutputAirnotifierProvider {
); );
// Don't try auto-login, admins cannot use it. // Don't try auto-login, admins cannot use it.
CoreUtils.openInBrowser(url, { CoreOpener.openInBrowser(url, {
showBrowserWarning: false, showBrowserWarning: false,
}); });
}, },

View File

@ -35,6 +35,7 @@ import { ADDON_MOD_BBB_COMPONENT } from '../../constants';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { convertTextToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreOpener } from '@singletons/opener';
/** /**
* Component that displays a Big Blue Button activity. * Component that displays a Big Blue Button activity.
@ -303,7 +304,7 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
try { try {
const joinUrl = await AddonModBBB.getJoinUrl(this.module.id, this.groupId); const joinUrl = await AddonModBBB.getJoinUrl(this.module.id, this.groupId);
await CoreUtils.openInBrowser(joinUrl, { await CoreOpener.openInBrowser(joinUrl, {
showBrowserWarning: false, showBrowserWarning: false,
}); });

View File

@ -23,12 +23,11 @@ import { CorePlatform } from '@services/platform';
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites'; import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { CoreUrl } from '@singletons/url'; import { CoreUrl } from '@singletons/url';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from '@singletons/opener';
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
import { makeSingleton, Translate } from '@singletons'; import { makeSingleton, Translate } from '@singletons';
import { ADDON_MOD_LTI_COMPONENT } from '../constants'; import { ADDON_MOD_LTI_COMPONENT } from '../constants';
import { CoreCacheUpdateFrequency } from '@/core/constants'; import { CoreCacheUpdateFrequency } from '@/core/constants';
import { CoreInAppBrowser } from '@singletons/iab';
/** /**
* Service that provides some features for LTI. * Service that provides some features for LTI.
@ -254,10 +253,10 @@ export class AddonModLtiProvider {
const launcherUrl = await this.generateLauncher(url, params); const launcherUrl = await this.generateLauncher(url, params);
if (CorePlatform.isMobile()) { if (CorePlatform.isMobile()) {
CoreInAppBrowser.open(launcherUrl); CoreOpener.openInApp(launcherUrl);
} else { } else {
// In desktop open in browser, we found some cases where inapp caused JS issues. // In desktop open in browser, we found some cases where inapp caused JS issues.
CoreUtils.openInBrowser(launcherUrl); CoreOpener.openInBrowser(launcherUrl);
} }
} }

View File

@ -25,7 +25,6 @@ import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { CoreUtils, OpenFileAction } from '@services/utils/utils';
import { NgZone, Translate } from '@singletons'; import { NgZone, Translate } from '@singletons';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { import {
@ -36,6 +35,7 @@ import { AddonModResourceHelper } from '../../services/resource-helper';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { ADDON_MOD_RESOURCE_COMPONENT } from '../../constants'; import { ADDON_MOD_RESOURCE_COMPONENT } from '../../constants';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
import { OpenFileAction } from '@singletons/opener';
/** /**
* Component that displays a resource. * Component that displays a resource.
@ -176,7 +176,7 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
this.readableSize = CoreText.bytesToSize(this.module.contentsinfo.filessize, 1); this.readableSize = CoreText.bytesToSize(this.module.contentsinfo.filessize, 1);
this.timemodified = this.module.contentsinfo.lastmodified * 1000; this.timemodified = this.module.contentsinfo.lastmodified * 1000;
} else { } else {
mimetype = await CoreUtils.getMimeTypeFromUrl(CoreFileHelper.getFileUrl(contents[0])); mimetype = await CoreMimetypeUtils.getMimeTypeFromUrl(CoreFileHelper.getFileUrl(contents[0]));
this.readableSize = CoreText.bytesToSize(contents[0].filesize, 1); this.readableSize = CoreText.bytesToSize(contents[0].filesize, 1);
this.timemodified = contents[0].timemodified * 1000; this.timemodified = contents[0].timemodified * 1000;
} }

View File

@ -24,7 +24,6 @@ import { CoreFilepool } from '@services/filepool';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreUtilsOpenFileOptions } from '@services/utils/utils';
import { makeSingleton, Translate } from '@singletons'; import { makeSingleton, Translate } from '@singletons';
import { CorePath } from '@singletons/path'; import { CorePath } from '@singletons/path';
import { AddonModResource, AddonModResourceCustomData } from './resource'; import { AddonModResource, AddonModResourceCustomData } from './resource';
@ -33,6 +32,7 @@ import { CoreText } from '@singletons/text';
import { CoreTimeUtils } from '@services/utils/time'; import { CoreTimeUtils } from '@services/utils/time';
import { ADDON_MOD_RESOURCE_COMPONENT } from '../constants'; import { ADDON_MOD_RESOURCE_COMPONENT } from '../constants';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { CoreOpenerOpenFileOptions } from '@singletons/opener';
/** /**
* Service that provides helper functions for resources. * Service that provides helper functions for resources.
@ -190,7 +190,7 @@ export class AddonModResourceHelperProvider {
* @param options Options to open the file. * @param options Options to open the file.
* @returns Resolved when done. * @returns Resolved when done.
*/ */
async openModuleFile(module: CoreCourseModuleData, courseId: number, options: CoreUtilsOpenFileOptions = {}): Promise<void> { async openModuleFile(module: CoreCourseModuleData, courseId: number, options: CoreOpenerOpenFileOptions = {}): Promise<void> {
const modal = await CoreLoadings.show(); const modal = await CoreLoadings.show();
try { try {

View File

@ -58,6 +58,7 @@ import {
AddonModWorkshopPhase, AddonModWorkshopPhase,
} from '@addons/mod/workshop/constants'; } from '@addons/mod/workshop/constants';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreOpener } from '@singletons/opener';
/** /**
* Component that displays a workshop index page. * Component that displays a workshop index page.
@ -363,7 +364,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
if (task.code == 'submit') { if (task.code == 'submit') {
this.gotoSubmit(); this.gotoSubmit();
} else if (task.link) { } else if (task.link) {
CoreUtils.openInBrowser(task.link); CoreOpener.openInBrowser(task.link);
} }
} }

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from '@singletons/opener';
import { ModalController } from '@singletons'; import { ModalController } from '@singletons';
import { AddonModWorkshopPhaseData, AddonModWorkshopPhaseTaskData } from '../../services/workshop'; import { AddonModWorkshopPhaseData, AddonModWorkshopPhaseTaskData } from '../../services/workshop';
import { AddonModWorkshopPhase } from '../../constants'; import { AddonModWorkshopPhase } from '../../constants';
@ -69,7 +69,7 @@ export class AddonModWorkshopPhaseInfoModalComponent implements OnInit {
// This will close the modal and go to the submit. // This will close the modal and go to the submit.
ModalController.dismiss(true); ModalController.dismiss(true);
} else if (task.link) { } else if (task.link) {
CoreUtils.openInBrowser(task.link); CoreOpener.openInBrowser(task.link);
} }
} }

View File

@ -24,8 +24,8 @@ import { AddonNotifications } from '../notifications';
import { AddonNotificationsMainMenuHandlerService } from './mainmenu'; import { AddonNotificationsMainMenuHandlerService } from './mainmenu';
import { AddonNotificationsHelper } from '../notifications-helper'; import { AddonNotificationsHelper } from '../notifications-helper';
import { CoreViewer } from '@features/viewer/services/viewer'; import { CoreViewer } from '@features/viewer/services/viewer';
import { CoreInAppBrowser } from '@singletons/iab';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreOpener } from '@singletons/opener';
/** /**
* Handler for non-messaging push notifications clicks. * Handler for non-messaging push notifications clicks.
@ -91,12 +91,12 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
switch (notification.customdata.appurlopenin) { switch (notification.customdata.appurlopenin) {
case 'inapp': case 'inapp':
CoreInAppBrowser.open(url); CoreOpener.openInApp(url);
return; return;
case 'browser': case 'browser':
return CoreUtils.openInBrowser(url); return CoreOpener.openInBrowser(url);
default: { default: {
const treated = await CoreContentLinksHelper.handleLink(url, undefined, undefined, true); const treated = await CoreContentLinksHelper.handleLink(url, undefined, undefined, true);

View File

@ -22,12 +22,12 @@ import { CoreApp } from '@services/app';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreSubscriptions } from '@singletons/subscriptions'; import { CoreSubscriptions } from '@singletons/subscriptions';
import { CoreWindow } from '@singletons/window'; import { CoreWindow } from '@singletons/window';
import { CoreInAppBrowser } from '@singletons/iab';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
import { CorePromisedValue } from '@classes/promised-value'; import { CorePromisedValue } from '@classes/promised-value';
import { register } from 'swiper/element/bundle'; import { register } from 'swiper/element/bundle';
import { CoreWait } from '@singletons/wait'; import { CoreWait } from '@singletons/wait';
import { CoreOpener } from '@singletons/opener';
register(); register();
@ -51,7 +51,7 @@ export class AppComponent implements OnInit, AfterViewInit {
CorePlatform.resume.subscribe(() => { CorePlatform.resume.subscribe(() => {
// Wait a second before setting it to false since in iOS there could be some frozen WS calls. // Wait a second before setting it to false since in iOS there could be some frozen WS calls.
setTimeout(() => { setTimeout(() => {
if (CoreLoginHelper.isWaitingForBrowser() && !CoreInAppBrowser.isInAppBrowserOpen()) { if (CoreLoginHelper.isWaitingForBrowser() && !CoreOpener.isInAppBrowserOpen()) {
CoreLoginHelper.stopWaitingForBrowser(); CoreLoginHelper.stopWaitingForBrowser();
CoreLoginHelper.checkLogout(); CoreLoginHelper.checkLogout();
} }

View File

@ -27,7 +27,7 @@ import {
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreTimeUtils } from '@services/utils/time'; import { CoreTimeUtils } from '@services/utils/time';
import { CoreUrl } from '@singletons/url'; import { CoreUrl } from '@singletons/url';
import { CoreUtils, CoreUtilsOpenInBrowserOptions } from '@services/utils/utils'; import { CoreOpener, CoreOpenerOpenInBrowserOptions } from '@singletons/opener';
import { CoreConstants } from '@/core/constants'; import { CoreConstants } from '@/core/constants';
import { SQLiteDB } from '@classes/sqlitedb'; import { SQLiteDB } from '@classes/sqlitedb';
import { CoreError } from '@classes/errors/error'; import { CoreError } from '@classes/errors/error';
@ -55,7 +55,6 @@ import { CoreAuthenticatedSite, CoreAuthenticatedSiteOptionalData, CoreSiteWSPre
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { CoreInAppBrowser } from '@singletons/iab';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
/** /**
@ -472,7 +471,7 @@ export class CoreSite extends CoreAuthenticatedSite {
async openInBrowserWithAutoLogin( async openInBrowserWithAutoLogin(
url: string, url: string,
alertMessage?: string, alertMessage?: string,
options: CoreUtilsOpenInBrowserOptions = {}, options: CoreOpenerOpenInBrowserOptions = {},
): Promise<void> { ): Promise<void> {
await this.openWithAutoLogin(false, url, options, alertMessage); await this.openWithAutoLogin(false, url, options, alertMessage);
} }
@ -503,7 +502,7 @@ export class CoreSite extends CoreAuthenticatedSite {
async openWithAutoLogin( async openWithAutoLogin(
inApp: boolean, inApp: boolean,
url: string, url: string,
options: InAppBrowserOptions & CoreUtilsOpenInBrowserOptions = {}, options: InAppBrowserOptions & CoreOpenerOpenInBrowserOptions = {},
alertMessage?: string, alertMessage?: string,
): Promise<InAppBrowserObject | void> { ): Promise<InAppBrowserObject | void> {
// Get the URL to open. // Get the URL to open.
@ -537,9 +536,9 @@ export class CoreSite extends CoreAuthenticatedSite {
options.clearsessioncache = 'yes'; options.clearsessioncache = 'yes';
} }
return CoreInAppBrowser.open(autoLoginUrl, options); return CoreOpener.openInApp(autoLoginUrl, options);
} else { } else {
return CoreUtils.openInBrowser(autoLoginUrl, options); return CoreOpener.openInBrowser(autoLoginUrl, options);
} }
} }

View File

@ -21,7 +21,6 @@ import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreUrl } from '@singletons/url'; import { CoreUrl } from '@singletons/url';
import { CoreUtils, CoreUtilsOpenFileOptions, OpenFileAction } from '@services/utils/utils';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { DownloadStatus } from '@/core/constants'; import { DownloadStatus } from '@/core/constants';
import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreEventObserver, CoreEvents } from '@singletons/events';
@ -29,6 +28,7 @@ import { CoreWSFile } from '@services/ws';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { toBoolean } from '@/core/transforms/boolean'; import { toBoolean } from '@/core/transforms/boolean';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreOpener, CoreOpenerOpenFileOptions, OpenFileAction } from '@singletons/opener';
/** /**
* Component to handle a remote file. Shows the file name, icon (depending on mimetype) and a button * Component to handle a remote file. Shows the file name, icon (depending on mimetype) and a button
@ -155,7 +155,7 @@ export class CoreFileComponent implements OnInit, OnDestroy {
return; return;
} }
const options: CoreUtilsOpenFileOptions = {}; const options: CoreOpenerOpenFileOptions = {};
if (isOpenButton) { if (isOpenButton) {
// Use the non-default method. // Use the non-default method.
options.iOSOpenFileAction = this.defaultIsOpenWithPicker ? OpenFileAction.OPEN : OpenFileAction.OPEN_WITH; options.iOSOpenFileAction = this.defaultIsOpenWithPicker ? OpenFileAction.OPEN : OpenFileAction.OPEN_WITH;
@ -194,9 +194,9 @@ export class CoreFileComponent implements OnInit, OnDestroy {
if (!this.canDownload || !this.state || this.state === DownloadStatus.NOT_DOWNLOADABLE) { if (!this.canDownload || !this.state || this.state === DownloadStatus.NOT_DOWNLOADABLE) {
// File cannot be downloaded, just open it. // File cannot be downloaded, just open it.
if (CoreUrl.isLocalFileUrl(this.fileUrl)) { if (CoreUrl.isLocalFileUrl(this.fileUrl)) {
CoreUtils.openFile(this.fileUrl); CoreOpener.openFile(this.fileUrl);
} else { } else {
CoreUtils.openOnlineFile(CoreUrl.unfixPluginfileURL(this.fileUrl)); CoreOpener.openOnlineFile(CoreUrl.unfixPluginfileURL(this.fileUrl));
} }
return; return;

View File

@ -23,7 +23,7 @@ import { CoreDomUtils } from '@services/utils/dom';
import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { CoreTimeUtils } from '@services/utils/time'; import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils, CoreUtilsOpenFileOptions, OpenFileAction } from '@services/utils/utils'; import { CoreOpener, CoreOpenerOpenFileOptions, OpenFileAction } from '@singletons/opener';
import { CoreForms } from '@singletons/form'; import { CoreForms } from '@singletons/form';
import { CorePath } from '@singletons/path'; import { CorePath } from '@singletons/path';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
@ -134,13 +134,13 @@ export class CoreLocalFileComponent implements OnInit {
} }
} }
const options: CoreUtilsOpenFileOptions = {}; const options: CoreOpenerOpenFileOptions = {};
if (isOpenButton) { if (isOpenButton) {
// Use the non-default method. // Use the non-default method.
options.iOSOpenFileAction = this.defaultIsOpenWithPicker ? OpenFileAction.OPEN : OpenFileAction.OPEN_WITH; options.iOSOpenFileAction = this.defaultIsOpenWithPicker ? OpenFileAction.OPEN : OpenFileAction.OPEN_WITH;
} }
CoreUtils.openFile(CoreFile.getFileEntryURL(this.file), options); CoreOpener.openFile(CoreFile.getFileEntryURL(this.file), options);
} }
/** /**

View File

@ -17,7 +17,7 @@ import { Component, Input, OnInit } from '@angular/core';
import { CoreLang, CoreLangFormat } from '@services/lang'; import { CoreLang, CoreLangFormat } from '@services/lang';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreInAppBrowser } from '@singletons/iab'; import { CoreOpener } from '@singletons/opener';
import { CorePath } from '@singletons/path'; import { CorePath } from '@singletons/path';
/** /**
@ -66,7 +66,7 @@ export class CoreRecaptchaComponent implements OnInit {
// The app cannot render the recaptcha directly because it has problems with the local protocols and domains. // The app cannot render the recaptcha directly because it has problems with the local protocols and domains.
const src = CorePath.concatenatePaths(this.siteUrl, 'webservice/recaptcha.php?lang=' + this.lang); const src = CorePath.concatenatePaths(this.siteUrl, 'webservice/recaptcha.php?lang=' + this.lang);
const inAppBrowserWindow = CoreInAppBrowser.open(src); const inAppBrowserWindow = CoreOpener.openInApp(src);
if (!inAppBrowserWindow) { if (!inAppBrowserWindow) {
return; return;
} }

View File

@ -19,7 +19,7 @@ import { CoreFileHelper } from '@services/file-helper';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUrl } from '@singletons/url'; import { CoreUrl } from '@singletons/url';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from '@singletons/opener';
import { CoreConstants } from '@/core/constants'; import { CoreConstants } from '@/core/constants';
import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper'; import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper';
import { CoreCustomURLSchemes } from '@services/urlschemes'; import { CoreCustomURLSchemes } from '@services/urlschemes';
@ -28,7 +28,6 @@ import { CoreFilepool } from '@services/filepool';
import { CoreDom } from '@singletons/dom'; import { CoreDom } from '@singletons/dom';
import { toBoolean } from '../transforms/boolean'; import { toBoolean } from '../transforms/boolean';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { CoreInAppBrowser } from '@singletons/iab';
/** /**
* Directive to open a link in external browser or in the app. * Directive to open a link in external browser or in the app.
@ -164,7 +163,7 @@ export class CoreLinkDirective implements OnInit {
} }
try { try {
await CoreUtils.openFile(path); await CoreOpener.openFile(path);
} catch (error) { } catch (error) {
CoreDomUtils.showErrorModal(error); CoreDomUtils.showErrorModal(error);
} }
@ -187,9 +186,9 @@ export class CoreLinkDirective implements OnInit {
if (!CoreSites.isLoggedIn()) { if (!CoreSites.isLoggedIn()) {
// Not logged in, cannot auto-login. // Not logged in, cannot auto-login.
if (openInApp) { if (openInApp) {
CoreInAppBrowser.open(href); CoreOpener.openInApp(href);
} else { } else {
CoreUtils.openInBrowser(href, { showBrowserWarning: this.showBrowserWarning }); CoreOpener.openInBrowser(href, { showBrowserWarning: this.showBrowserWarning });
} }
return; return;
@ -228,9 +227,9 @@ export class CoreLinkDirective implements OnInit {
} }
} else { } else {
if (openInApp) { if (openInApp) {
CoreInAppBrowser.open(href); CoreOpener.openInApp(href);
} else { } else {
CoreUtils.openInBrowser(href, { showBrowserWarning: this.showBrowserWarning }); CoreOpener.openInBrowser(href, { showBrowserWarning: this.showBrowserWarning });
} }
} }
} }

View File

@ -17,8 +17,8 @@ import { Directive, Input, OnInit, ElementRef } from '@angular/core';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreCourse, CoreCourseModuleContentFile } from '@features/course/services/course'; import { CoreCourse, CoreCourseModuleContentFile } from '@features/course/services/course';
import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper'; import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper';
import { CoreUtilsOpenFileOptions } from '@services/utils/utils';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { CoreOpenerOpenFileOptions } from '@singletons/opener';
/** /**
* Directive to allow downloading and open the main file of a module. * Directive to allow downloading and open the main file of a module.
@ -38,7 +38,7 @@ export class CoreCourseDownloadModuleMainFileDirective implements OnInit {
@Input() component?: string; // Component to link the file to. @Input() component?: string; // Component to link the file to.
@Input() componentId?: string | number; // Component ID to use in conjunction with the component. If not defined, use moduleId. @Input() componentId?: string | number; // Component ID to use in conjunction with the component. If not defined, use moduleId.
@Input() files?: CoreCourseModuleContentFile[]; // List of files of the module. If not provided, use module.contents. @Input() files?: CoreCourseModuleContentFile[]; // List of files of the module. If not provided, use module.contents.
@Input() options?: CoreUtilsOpenFileOptions = {}; @Input() options?: CoreOpenerOpenFileOptions = {};
protected element: HTMLElement; protected element: HTMLElement;

View File

@ -32,7 +32,7 @@ import { CoreLogger } from '@singletons/logger';
import { ApplicationInit, makeSingleton, Translate } from '@singletons'; import { ApplicationInit, makeSingleton, Translate } from '@singletons';
import { CoreFilepool } from '@services/filepool'; import { CoreFilepool } from '@services/filepool';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils, CoreUtilsOpenFileOptions } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { import {
CoreCourseAnyCourseData, CoreCourseAnyCourseData,
CoreCourseBasicData, CoreCourseBasicData,
@ -83,6 +83,7 @@ import {
CORE_COURSE_COMPONENT, CORE_COURSE_COMPONENT,
} from '../constants'; } from '../constants';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreOpener, CoreOpenerOpenFileOptions } from '@singletons/opener';
/** /**
* Prefetch info of a module. * Prefetch info of a module.
@ -640,7 +641,7 @@ export class CoreCourseHelperProvider {
componentId?: string | number, componentId?: string | number,
files?: CoreCourseModuleContentFile[], files?: CoreCourseModuleContentFile[],
siteId?: string, siteId?: string,
options: CoreUtilsOpenFileOptions = {}, options: CoreOpenerOpenFileOptions = {},
): Promise<void> { ): Promise<void> {
siteId = siteId || CoreSites.getCurrentSiteId(); siteId = siteId || CoreSites.getCurrentSiteId();
@ -678,7 +679,7 @@ export class CoreCourseHelperProvider {
); );
if (CoreUrl.isLocalFileUrl(result.path)) { if (CoreUrl.isLocalFileUrl(result.path)) {
return CoreUtils.openFile(result.path, options); return CoreOpener.openFile(result.path, options);
} }
/* In iOS, if we use the same URL in embedded browser and background download then the download only /* In iOS, if we use the same URL in embedded browser and background download then the download only
@ -686,7 +687,7 @@ export class CoreCourseHelperProvider {
result.path = result.path + '#moodlemobile-embedded'; result.path = result.path + '#moodlemobile-embedded';
try { try {
await CoreUtils.openOnlineFile(result.path); await CoreOpener.openOnlineFile(result.path);
} catch (error) { } catch (error) {
// Error opening the file, some apps don't allow opening online files. // Error opening the file, some apps don't allow opening online files.
if (!CoreFile.isAvailable()) { if (!CoreFile.isAvailable()) {
@ -706,7 +707,7 @@ export class CoreCourseHelperProvider {
path = await CoreFilepool.getInternalUrlByUrl(siteId, mainFile.fileurl); path = await CoreFilepool.getInternalUrlByUrl(siteId, mainFile.fileurl);
} }
await CoreUtils.openFile(path, options); await CoreOpener.openFile(path, options);
} }
} }
@ -731,7 +732,7 @@ export class CoreCourseHelperProvider {
component?: string, component?: string,
componentId?: string | number, componentId?: string | number,
files?: CoreCourseModuleContentFile[], files?: CoreCourseModuleContentFile[],
options: CoreUtilsOpenFileOptions = {}, options: CoreOpenerOpenFileOptions = {},
): Promise<void> { ): Promise<void> {
if (!CoreNetwork.isOnline()) { if (!CoreNetwork.isOnline()) {
// Not online, get the offline file. It will fail if not found. // Not online, get the offline file. It will fail if not found.
@ -742,7 +743,7 @@ export class CoreCourseHelperProvider {
throw new CoreNetworkError(); throw new CoreNetworkError();
} }
return CoreUtils.openFile(path, options); return CoreOpener.openFile(path, options);
} }
// Open in browser. // Open in browser.
@ -754,7 +755,7 @@ export class CoreCourseHelperProvider {
// Remove forcedownload when not followed by any param. // Remove forcedownload when not followed by any param.
fixedUrl = fixedUrl.replace(/[?|&]forcedownload=\d+/, ''); fixedUrl = fixedUrl.replace(/[?|&]forcedownload=\d+/, '');
CoreUtils.openInBrowser(fixedUrl); CoreOpener.openInBrowser(fixedUrl);
if (CoreFile.isAvailable()) { if (CoreFile.isAvailable()) {
// Download the file if needed (file outdated or not downloaded). // Download the file if needed (file outdated or not downloaded).
@ -783,7 +784,7 @@ export class CoreCourseHelperProvider {
componentId?: string | number, componentId?: string | number,
files?: CoreCourseModuleContentFile[], files?: CoreCourseModuleContentFile[],
siteId?: string, siteId?: string,
options: CoreUtilsOpenFileOptions = {}, options: CoreOpenerOpenFileOptions = {},
): Promise<{ fixedUrl: string; path: string; status?: DownloadStatus }> { ): Promise<{ fixedUrl: string; path: string; status?: DownloadStatus }> {
siteId = siteId || CoreSites.getCurrentSiteId(); siteId = siteId || CoreSites.getCurrentSiteId();
@ -881,7 +882,7 @@ export class CoreCourseHelperProvider {
component?: string, component?: string,
componentId?: string | number, componentId?: string | number,
siteId?: string, siteId?: string,
options: CoreUtilsOpenFileOptions = {}, options: CoreOpenerOpenFileOptions = {},
): Promise<string> { ): Promise<string> {
siteId = siteId || CoreSites.getCurrentSiteId(); siteId = siteId || CoreSites.getCurrentSiteId();

View File

@ -15,7 +15,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { CoreConfig } from '@services/config'; import { CoreConfig } from '@services/config';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from '@singletons/opener';
import { GET_STARTED_URL, ONBOARDING_DONE } from '@features/login/constants'; import { GET_STARTED_URL, ONBOARDING_DONE } from '@features/login/constants';
import { ModalController } from '@singletons'; import { ModalController } from '@singletons';
import { CoreSharedModule } from '@/core/shared.module'; import { CoreSharedModule } from '@/core/shared.module';
@ -84,7 +84,7 @@ export class CoreLoginSiteOnboardingComponent {
this.saveOnboardingDone(); this.saveOnboardingDone();
CoreUtils.openInBrowser(GET_STARTED_URL, { showBrowserWarning: false }); CoreOpener.openInBrowser(GET_STARTED_URL, { showBrowserWarning: false });
ModalController.dismiss(); ModalController.dismiss();
} }

View File

@ -19,8 +19,8 @@ import { CoreLoginHelper } from '@features/login/services/login-helper';
import { Translate } from '@singletons'; import { Translate } from '@singletons';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreInAppBrowser } from '@singletons/iab';
import { CoreUserSupport } from '@features/user/services/support'; import { CoreUserSupport } from '@features/user/services/support';
import { CoreOpener } from '@singletons/opener';
/** /**
* Page that shows instructions to change the password. * Page that shows instructions to change the password.
@ -94,7 +94,7 @@ export class CoreLoginChangePasswordPage implements OnDestroy {
this.urlLoadedObserver = CoreEvents.on(CoreEvents.IAB_LOAD_STOP, (event) => { this.urlLoadedObserver = CoreEvents.on(CoreEvents.IAB_LOAD_STOP, (event) => {
if (event.url.match(/\/login\/change_password\.php.*return=1/)) { if (event.url.match(/\/login\/change_password\.php.*return=1/)) {
// Password has changed, close the IAB now. // Password has changed, close the IAB now.
CoreInAppBrowser.closeInAppBrowser(); CoreOpener.closeInAppBrowser();
this.login(); this.login();
return; return;
@ -105,7 +105,7 @@ export class CoreLoginChangePasswordPage implements OnDestroy {
} }
// Use a script to check if the user changed the password, in some platforms we cannot tell using the URL. // Use a script to check if the user changed the password, in some platforms we cannot tell using the URL.
CoreInAppBrowser.getInAppBrowserInstance()?.executeScript({ CoreOpener.getInAppBrowserInstance()?.executeScript({
code: ` code: `
if ( if (
document.querySelector('input[type="password"]') === null && document.querySelector('input[type="password"]') === null &&
@ -119,7 +119,7 @@ export class CoreLoginChangePasswordPage implements OnDestroy {
this.messageObserver = CoreEvents.on(CoreEvents.IAB_MESSAGE, (data) => { this.messageObserver = CoreEvents.on(CoreEvents.IAB_MESSAGE, (data) => {
if (data.passwordChanged) { if (data.passwordChanged) {
CoreInAppBrowser.closeInAppBrowser(); CoreOpener.closeInAppBrowser();
this.login(); this.login();
} }
}); });

View File

@ -39,6 +39,7 @@ import { CoreInputErrorsMessages } from '@components/input-errors/input-errors';
import { CoreViewer } from '@features/viewer/services/viewer'; import { CoreViewer } from '@features/viewer/services/viewer';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreOpener } from '@singletons/opener';
/** /**
* Page to signup using email. * Page to signup using email.
@ -395,7 +396,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
* Show contact information on site (we have to display again the age verification form). * Show contact information on site (we have to display again the age verification form).
*/ */
showContactOnSite(): void { showContactOnSite(): void {
CoreUtils.openInBrowser( CoreOpener.openInBrowser(
CorePath.concatenatePaths(this.site.getURL(), '/login/verify_age_location.php'), CorePath.concatenatePaths(this.site.getURL(), '/login/verify_age_location.php'),
{ showBrowserWarning: false }, { showBrowserWarning: false },
); );

View File

@ -62,8 +62,8 @@ import { CoreQRScan } from '@services/qrscan';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { CoreErrorHelper } from '@services/error-helper'; import { CoreErrorHelper } from '@services/error-helper';
import { CoreSSO } from '@singletons/sso'; import { CoreSSO } from '@singletons/sso';
import { CoreInAppBrowser } from '@singletons/iab';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreOpener } from '@singletons/opener';
/** /**
* Helper provider that provides some common features regarding authentication. * Helper provider that provides some common features regarding authentication.
@ -174,7 +174,7 @@ export class CoreLoginHelperProvider {
async forgottenPasswordClicked(siteUrl: string, username: string, siteConfig?: CoreSitePublicConfigResponse): Promise<void> { async forgottenPasswordClicked(siteUrl: string, username: string, siteConfig?: CoreSitePublicConfigResponse): Promise<void> {
if (siteConfig && siteConfig.forgottenpasswordurl) { if (siteConfig && siteConfig.forgottenpasswordurl) {
// URL set, open it. // URL set, open it.
CoreInAppBrowser.open(siteConfig.forgottenpasswordurl); CoreOpener.openInApp(siteConfig.forgottenpasswordurl);
return; return;
} }
@ -628,7 +628,7 @@ export class CoreLoginHelperProvider {
}); });
// Always open it in browser because the user might have the session stored in there. // Always open it in browser because the user might have the session stored in there.
CoreUtils.openInBrowser(loginUrl, { showBrowserWarning: false }); CoreOpener.openInBrowser(loginUrl, { showBrowserWarning: false });
CoreApp.closeApp(); CoreApp.closeApp();
return true; return true;
@ -665,12 +665,12 @@ export class CoreLoginHelperProvider {
this.logger.debug('openBrowserForSSOLogin loginUrl:', loginUrl); this.logger.debug('openBrowserForSSOLogin loginUrl:', loginUrl);
if (this.isSSOEmbeddedBrowser(typeOfLogin)) { if (this.isSSOEmbeddedBrowser(typeOfLogin)) {
CoreInAppBrowser.open(loginUrl, { CoreOpener.openInApp(loginUrl, {
clearsessioncache: 'yes', // Clear the session cache to allow for multiple logins. clearsessioncache: 'yes', // Clear the session cache to allow for multiple logins.
closebuttoncaption: Translate.instant('core.login.cancel'), closebuttoncaption: Translate.instant('core.login.cancel'),
}); });
} else { } else {
CoreUtils.openInBrowser(loginUrl, { showBrowserWarning: false }); CoreOpener.openInBrowser(loginUrl, { showBrowserWarning: false });
CoreApp.closeApp(); CoreApp.closeApp();
} }
} catch (error) { } catch (error) {
@ -692,7 +692,7 @@ export class CoreLoginHelperProvider {
await alert.onDidDismiss(); await alert.onDidDismiss();
CoreInAppBrowser.open(siteUrl + '/login/change_password.php'); CoreOpener.openInApp(siteUrl + '/login/change_password.php');
} }
/** /**
@ -701,7 +701,7 @@ export class CoreLoginHelperProvider {
* @param siteUrl URL of the site. * @param siteUrl URL of the site.
*/ */
openForgottenPassword(siteUrl: string): void { openForgottenPassword(siteUrl: string): void {
CoreInAppBrowser.open(siteUrl + '/login/forgot_password.php'); CoreOpener.openInApp(siteUrl + '/login/forgot_password.php');
} }
/** /**
@ -977,7 +977,7 @@ export class CoreLoginHelperProvider {
async openInBrowserFallback(siteUrl: string, debug?: CoreSiteErrorDebug): Promise<void> { async openInBrowserFallback(siteUrl: string, debug?: CoreSiteErrorDebug): Promise<void> {
CoreEvents.trigger(APP_UNSUPPORTED_CHURN, { siteUrl, debug }); CoreEvents.trigger(APP_UNSUPPORTED_CHURN, { siteUrl, debug });
await CoreUtils.openInBrowser(siteUrl, { showBrowserWarning: false }); await CoreOpener.openInBrowser(siteUrl, { showBrowserWarning: false });
} }
/** /**

View File

@ -16,7 +16,6 @@ import { ChangeDetectorRef, Component, ElementRef, OnDestroy, OnInit, ViewChild
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreSite } from '@classes/sites/site'; import { CoreSite } from '@classes/sites/site';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
@ -141,7 +140,7 @@ export class CorePolicySitePolicyPage implements OnInit, OnDestroy {
// Try to get the mime type. // Try to get the mime type.
try { try {
const mimeType = await CoreUtils.getMimeTypeFromUrl(this.sitePoliciesURL); const mimeType = await CoreMimetypeUtils.getMimeTypeFromUrl(this.sitePoliciesURL);
const extension = CoreMimetypeUtils.getExtension(mimeType, this.sitePoliciesURL); const extension = CoreMimetypeUtils.getExtension(mimeType, this.sitePoliciesURL);
this.showInline = extension == 'html' || extension == 'htm'; this.showInline = extension == 'html' || extension == 'htm';

View File

@ -27,7 +27,7 @@ import { CoreScreen } from '@services/screen';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreErrorObject } from '@services/error-helper'; import { CoreErrorObject } from '@services/error-helper';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from '@singletons/opener';
import { Translate } from '@singletons'; import { Translate } from '@singletons';
import { CoreTime } from '@singletons/time'; import { CoreTime } from '@singletons/time';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
@ -150,7 +150,7 @@ export class CoreReportBuilderReportDetailComponent implements OnInit {
handler: async () => { handler: async () => {
const site = CoreSites.getRequiredCurrentSite(); const site = CoreSites.getRequiredCurrentSite();
const href = `${site.getURL()}/reportbuilder/view.php?id=${this.reportId}`; const href = `${site.getURL()}/reportbuilder/view.php?id=${this.reportId}`;
await CoreUtils.openInBrowser(href, { showBrowserWarning: false }); await CoreOpener.openInBrowser(href, { showBrowserWarning: false });
await CoreNavigator.back(); await CoreNavigator.back();
}, },
}, },

View File

@ -19,8 +19,8 @@ import { CoreLoginHelper } from '@features/login/services/login-helper';
import { Translate } from '@singletons'; import { Translate } from '@singletons';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreInAppBrowser } from '@singletons/iab';
import { CoreUserSupport } from '@features/user/services/support'; import { CoreUserSupport } from '@features/user/services/support';
import { CoreOpener } from '@singletons/opener';
/** /**
* Page that shows instructions to complete the profile. * Page that shows instructions to complete the profile.
@ -93,7 +93,7 @@ export class CoreUserCompleteProfilePage implements OnDestroy {
this.urlLoadedObserver = CoreEvents.on(CoreEvents.IAB_LOAD_START, (event) => { this.urlLoadedObserver = CoreEvents.on(CoreEvents.IAB_LOAD_START, (event) => {
if (event.url.match(/\/user\/preferences.php/)) { if (event.url.match(/\/user\/preferences.php/)) {
// Profile should be complete now. // Profile should be complete now.
CoreInAppBrowser.closeInAppBrowser(); CoreOpener.closeInAppBrowser();
this.login(); this.login();
} }
}); });

View File

@ -20,7 +20,7 @@ import {
CoreUserProfileHandlerData, CoreUserProfileHandlerData,
} from '../user-delegate'; } from '../user-delegate';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from '@singletons/opener';
import { CoreUserProfile } from '../user'; import { CoreUserProfile } from '../user';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
@ -60,7 +60,7 @@ export class CoreUserProfileMailHandlerService implements CoreUserProfileHandler
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
CoreUtils.openInBrowser('mailto:' + user.email, { showBrowserWarning: false }); CoreOpener.openInBrowser('mailto:' + user.email, { showBrowserWarning: false });
}, },
}; };
} }

View File

@ -18,7 +18,6 @@ import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/suppo
import { InAppBrowserObject } from '@awesome-cordova-plugins/in-app-browser'; import { InAppBrowserObject } from '@awesome-cordova-plugins/in-app-browser';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreInAppBrowser } from '@singletons/iab';
import { makeSingleton, Translate } from '@singletons'; import { makeSingleton, Translate } from '@singletons';
import { CoreEvents } from '@singletons/events'; import { CoreEvents } from '@singletons/events';
import { CoreSubscriptions } from '@singletons/subscriptions'; import { CoreSubscriptions } from '@singletons/subscriptions';
@ -26,6 +25,7 @@ import { AlertButton } from '@ionic/angular';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreLang } from '@services/lang'; import { CoreLang } from '@services/lang';
import { CoreUserNullSupportConfig } from '@features/user/classes/support/null-support-config'; import { CoreUserNullSupportConfig } from '@features/user/classes/support/null-support-config';
import { CoreOpener } from '@singletons/opener';
/** /**
* Handle site support. * Handle site support.
@ -42,7 +42,7 @@ export class CoreUserSupportService {
const supportConfig = options.supportConfig ?? CoreUserAuthenticatedSupportConfig.forCurrentSite(); const supportConfig = options.supportConfig ?? CoreUserAuthenticatedSupportConfig.forCurrentSite();
const supportPageUrl = supportConfig.getSupportPageUrl(); const supportPageUrl = supportConfig.getSupportPageUrl();
const autoLoginUrl = await CoreSites.getCurrentSite()?.getAutoLoginUrl(supportPageUrl, false); const autoLoginUrl = await CoreSites.getCurrentSite()?.getAutoLoginUrl(supportPageUrl, false);
const browser = CoreInAppBrowser.open(autoLoginUrl ?? supportPageUrl); const browser = CoreOpener.openInApp(autoLoginUrl ?? supportPageUrl);
if (supportPageUrl.endsWith('/user/contactsitesupport.php')) { if (supportPageUrl.endsWith('/user/contactsitesupport.php')) {
this.populateSupportForm(browser, options.subject, options.message); this.populateSupportForm(browser, options.subject, options.message);

View File

@ -20,10 +20,9 @@ import { CoreSites } from '@services/sites';
import { CoreCustomURLSchemes } from '@services/urlschemes'; import { CoreCustomURLSchemes } from '@services/urlschemes';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUrl } from '@singletons/url'; import { CoreUrl } from '@singletons/url';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from '@singletons/opener';
import { Translate } from '@singletons'; import { Translate } from '@singletons';
import { CoreEvents } from '@singletons/events'; import { CoreEvents } from '@singletons/events';
import { CoreInAppBrowser } from '@singletons/iab';
let lastInAppUrl: string | null = null; let lastInAppUrl: string | null = null;
@ -44,14 +43,14 @@ export default function(): void {
CoreCustomURLSchemes.handleCustomURL(url).catch((error) => { CoreCustomURLSchemes.handleCustomURL(url).catch((error) => {
CoreCustomURLSchemes.treatHandleCustomURLError(error); CoreCustomURLSchemes.treatHandleCustomURLError(error);
}); });
CoreInAppBrowser.closeInAppBrowser(); CoreOpener.closeInAppBrowser();
return; return;
} }
if (isExternalApp && url.includes('://token=')) { if (isExternalApp && url.includes('://token=')) {
// It's an SSO token for another app. Close the IAB and show an error. // It's an SSO token for another app. Close the IAB and show an error.
CoreInAppBrowser.closeInAppBrowser(); CoreOpener.closeInAppBrowser();
CoreDomUtils.showErrorModal(new CoreSiteError({ CoreDomUtils.showErrorModal(new CoreSiteError({
supportConfig: CoreSites.getCurrentSite() supportConfig: CoreSites.getCurrentSite()
? CoreUserAuthenticatedSupportConfig.forCurrentSite() ? CoreUserAuthenticatedSupportConfig.forCurrentSite()
@ -69,15 +68,15 @@ export default function(): void {
} }
// Open in browser should launch the right app if found and do nothing if not found. // Open in browser should launch the right app if found and do nothing if not found.
CoreUtils.openInBrowser(url, { showBrowserWarning: false }); CoreOpener.openInBrowser(url, { showBrowserWarning: false });
// At this point, URL schemes will stop working in IAB, and in Android the IAB is showing a "Webpage not available" error. // At this point, URL schemes will stop working in IAB, and in Android the IAB is showing a "Webpage not available" error.
// Re-loading the page inside the existing IAB doesn't fix it, we need to re-load the whole IAB. // Re-loading the page inside the existing IAB doesn't fix it, we need to re-load the whole IAB.
if (lastInAppUrl) { if (lastInAppUrl) {
CoreInAppBrowser.open(lastInAppUrl); CoreOpener.openInApp(lastInAppUrl);
} else { } else {
// No last URL loaded, close the InAppBrowser. // No last URL loaded, close the InAppBrowser.
CoreInAppBrowser.closeInAppBrowser(); CoreOpener.closeInAppBrowser();
} }
}); });

View File

@ -23,7 +23,7 @@ import { CoreSites } from '@services/sites';
import { CoreWS, CoreWSFile } from '@services/ws'; import { CoreWS, CoreWSFile } from '@services/ws';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUrl } from '@singletons/url'; import { CoreUrl } from '@singletons/url';
import { CoreUtils, CoreUtilsOpenFileOptions, OpenFileAction } from '@services/utils/utils'; import { CoreOpener, CoreOpenerOpenFileOptions, OpenFileAction } from '@singletons/opener';
import { CoreConstants, DownloadStatus } from '@/core/constants'; import { CoreConstants, DownloadStatus } from '@/core/constants';
import { CoreError } from '@classes/errors/error'; import { CoreError } from '@classes/errors/error';
import { makeSingleton, Translate } from '@singletons'; import { makeSingleton, Translate } from '@singletons';
@ -69,7 +69,7 @@ export class CoreFileHelperProvider {
state?: DownloadStatus, state?: DownloadStatus,
onProgress?: CoreFileHelperOnProgress, onProgress?: CoreFileHelperOnProgress,
siteId?: string, siteId?: string,
options: CoreUtilsOpenFileOptions = {}, options: CoreOpenerOpenFileOptions = {},
): Promise<void> { ): Promise<void> {
siteId = siteId || CoreSites.getCurrentSiteId(); siteId = siteId || CoreSites.getCurrentSiteId();
@ -102,7 +102,7 @@ export class CoreFileHelperProvider {
url = url + '#moodlemobile-embedded'; url = url + '#moodlemobile-embedded';
try { try {
await CoreUtils.openOnlineFile(url); await CoreOpener.openOnlineFile(url);
return; return;
} catch (error) { } catch (error) {
@ -130,7 +130,7 @@ export class CoreFileHelperProvider {
} }
} }
return CoreUtils.openFile(url, options); return CoreOpener.openFile(url, options);
} }
/** /**
@ -156,7 +156,7 @@ export class CoreFileHelperProvider {
state?: DownloadStatus, state?: DownloadStatus,
onProgress?: CoreFileHelperOnProgress, onProgress?: CoreFileHelperOnProgress,
siteId?: string, siteId?: string,
options: CoreUtilsOpenFileOptions = {}, options: CoreOpenerOpenFileOptions = {},
): Promise<string> { ): Promise<string> {
siteId = siteId || CoreSites.getCurrentSiteId(); siteId = siteId || CoreSites.getCurrentSiteId();

View File

@ -27,7 +27,7 @@ import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { CoreTimeUtils } from '@services/utils/time'; import { CoreTimeUtils } from '@services/utils/time';
import { CoreUrl, CoreUrlPartNames } from '@singletons/url'; import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
import { CoreUtils, CoreUtilsOpenFileOptions } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreError } from '@classes/errors/error'; import { CoreError } from '@classes/errors/error';
import { DownloadStatus } from '@/core/constants'; import { DownloadStatus } from '@/core/constants';
import { ApplicationInit, makeSingleton, NgZone, Translate } from '@singletons'; import { ApplicationInit, makeSingleton, NgZone, Translate } from '@singletons';
@ -60,6 +60,7 @@ import { CorePromisedValue } from '@classes/promised-value';
import { CoreAnalytics, CoreAnalyticsEventType } from './analytics'; import { CoreAnalytics, CoreAnalyticsEventType } from './analytics';
import { convertTextToHTMLElement } from '../utils/create-html-element'; import { convertTextToHTMLElement } from '../utils/create-html-element';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreOpener, CoreOpenerOpenFileOptions } from '@singletons/opener';
/* /*
* Factory for handling downloading files and retrieve downloaded files. * Factory for handling downloading files and retrieve downloaded files.
@ -2949,18 +2950,18 @@ export class CoreFilepoolProvider {
* - The file cannot be streamed. * - The file cannot be streamed.
* If the file is big and can be streamed, the promise returned by this function will be rejected. * If the file is big and can be streamed, the promise returned by this function will be rejected.
*/ */
async shouldDownloadFileBeforeOpen(url: string, size: number, options: CoreUtilsOpenFileOptions = {}): Promise<boolean> { async shouldDownloadFileBeforeOpen(url: string, size: number, options: CoreOpenerOpenFileOptions = {}): Promise<boolean> {
if (size >= 0 && size <= CoreFilepoolProvider.DOWNLOAD_THRESHOLD) { if (size >= 0 && size <= CoreFilepoolProvider.DOWNLOAD_THRESHOLD) {
// The file is small, download it. // The file is small, download it.
return true; return true;
} }
if (CoreUtils.shouldOpenWithDialog(options)) { if (CoreOpener.shouldOpenWithDialog(options)) {
// Open with dialog needs a local file. // Open with dialog needs a local file.
return true; return true;
} }
const mimetype = await CoreUtils.getMimeTypeFromUrl(url); const mimetype = await CoreMimetypeUtils.getMimeTypeFromUrl(url);
// If the file is streaming (audio or video), return false. // If the file is streaming (audio or video), return false.
return !CoreMimetypeUtils.isStreamedMimetype(mimetype); return !CoreMimetypeUtils.isStreamedMimetype(mimetype);

View File

@ -71,6 +71,7 @@ import { CoreQueueRunner } from '@classes/queue-runner';
import { CoreAppDB } from './app-db'; import { CoreAppDB } from './app-db';
import { CoreRedirects } from '@singletons/redirects'; import { CoreRedirects } from '@singletons/redirects';
import { CorePromiseUtils } from '@singletons/promise-utils'; import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreOpener } from '@singletons/opener';
export const CORE_SITE_SCHEMAS = new InjectionToken<CoreSiteSchema[]>('CORE_SITE_SCHEMAS'); export const CORE_SITE_SCHEMAS = new InjectionToken<CoreSiteSchema[]>('CORE_SITE_SCHEMAS');
export const CORE_SITE_CURRENT_SITE_ID_CONFIG = 'current_site_id'; export const CORE_SITE_CURRENT_SITE_ID_CONFIG = 'current_site_id';
@ -947,7 +948,7 @@ export class CoreSitesProvider {
Translate.instant('core.updaterequired'), Translate.instant('core.updaterequired'),
Translate.instant('core.download'), Translate.instant('core.download'),
Translate.instant(siteId ? 'core.mainmenu.logout' : 'core.cancel'), Translate.instant(siteId ? 'core.mainmenu.logout' : 'core.cancel'),
).then(() => CoreUtils.openInBrowser(downloadUrl, { showBrowserWarning: false })).catch(() => { ).then(() => CoreOpener.openInBrowser(downloadUrl, { showBrowserWarning: false })).catch(() => {
// Do nothing. // Do nothing.
}); });
} else { } else {

View File

@ -22,7 +22,7 @@ import { CoreFile } from '@services/file';
import { CoreWSExternalWarning } from '@services/ws'; import { CoreWSExternalWarning } from '@services/ws';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { CoreUrl, CoreUrlPartNames } from '@singletons/url'; import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from '@singletons/opener';
import { CoreConstants } from '@/core/constants'; import { CoreConstants } from '@/core/constants';
import { CoreIonLoadingElement } from '@classes/ion-loading'; import { CoreIonLoadingElement } from '@classes/ion-loading';
import { CoreCanceledError } from '@classes/errors/cancelederror'; import { CoreCanceledError } from '@classes/errors/cancelederror';
@ -1199,7 +1199,7 @@ export class CoreDomUtilsProvider {
buttons.push({ buttons.push({
text: Translate.instant('core.download'), text: Translate.instant('core.download'),
handler: (): void => { handler: (): void => {
CoreUtils.openInBrowser(link, { showBrowserWarning: false }); CoreOpener.openInBrowser(link, { showBrowserWarning: false });
}, },
}); });
} }
@ -1428,7 +1428,7 @@ export class CoreDomUtilsProvider {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
CoreUtils.openInBrowser(href); CoreOpener.openInBrowser(href);
} }
}); });
}); });

View File

@ -22,7 +22,7 @@ import { CoreFileHelper } from '@services/file-helper';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUrl } from '@singletons/url'; import { CoreUrl } from '@singletons/url';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from '@singletons/opener';
import { makeSingleton, NgZone, Translate } from '@singletons'; import { makeSingleton, NgZone, Translate } from '@singletons';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
@ -520,7 +520,7 @@ export class CoreIframeUtilsProvider {
// The frame is local or the link needs to be opened in a new window. Open in browser. // The frame is local or the link needs to be opened in a new window. Open in browser.
if (!CoreSites.isLoggedIn()) { if (!CoreSites.isLoggedIn()) {
CoreUtils.openInBrowser(link.href); CoreOpener.openInBrowser(link.href);
} else { } else {
await CoreSites.getCurrentSite()?.openInBrowserWithAutoLogin(link.href); await CoreSites.getCurrentSite()?.openInBrowserWithAutoLogin(link.href);
} }
@ -539,7 +539,7 @@ export class CoreIframeUtilsProvider {
} }
try { try {
await CoreUtils.openFile(link.href); await CoreOpener.openFile(link.href);
} catch (error) { } catch (error) {
CoreDomUtils.showErrorModal(error); CoreDomUtils.showErrorModal(error);
} }
@ -687,7 +687,7 @@ export class CoreIframeUtilsProvider {
undefined; undefined;
if (localUrl) { if (localUrl) {
CoreUtils.openFile(localUrl); CoreOpener.openFile(localUrl);
} else { } else {
CoreDomUtils.showErrorModal('core.networkerrormsg', true); CoreDomUtils.showErrorModal('core.networkerrormsg', true);
} }
@ -695,11 +695,11 @@ export class CoreIframeUtilsProvider {
return; return;
} }
const mimetype = await CorePromiseUtils.ignoreErrors(CoreUtils.getMimeTypeFromUrl(url)); const mimetype = await CorePromiseUtils.ignoreErrors(CoreMimetypeUtils.getMimeTypeFromUrl(url));
if (!mimetype || mimetype === 'text/html' || mimetype === 'text/plain') { if (!mimetype || mimetype === 'text/html' || mimetype === 'text/plain') {
// It's probably a web page, open in browser. // It's probably a web page, open in browser.
options.site ? options.site.openInBrowserWithAutoLogin(url) : CoreUtils.openInBrowser(url); options.site ? options.site.openInBrowserWithAutoLogin(url) : CoreOpener.openInBrowser(url);
return; return;
} }
@ -711,7 +711,7 @@ export class CoreIframeUtilsProvider {
url = await options.site.checkAndFixPluginfileURL(url); url = await options.site.checkAndFixPluginfileURL(url);
} }
CoreUtils.openOnlineFile(url); CoreOpener.openOnlineFile(url);
} finally { } finally {
modal.dismiss(); modal.dismiss();

View File

@ -20,7 +20,7 @@ import { CoreFileUtils } from '@singletons/file-utils';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { makeSingleton, Translate } from '@singletons'; import { makeSingleton, Translate } from '@singletons';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
import { CoreWSFile } from '@services/ws'; import { CoreWS, CoreWSFile } from '@services/ws';
import extToMime from '@/assets/exttomime.json'; import extToMime from '@/assets/exttomime.json';
import mimeToExt from '@/assets/mimetoext.json'; import mimeToExt from '@/assets/mimetoext.json';
@ -538,6 +538,30 @@ export class CoreMimetypeUtilsProvider {
return this.getFileIconForType(icon); return this.getFileIconForType(icon);
} }
/**
* Get the mimetype of a file given its URL. It'll try to guess it using the URL, if that fails then it'll
* perform a HEAD request to get it. It's done in this order because pluginfile.php can return wrong mimetypes.
* This function is in here instead of MimetypeUtils to prevent circular dependencies.
*
* @param url The URL of the file.
* @returns Promise resolved with the mimetype.
*/
async getMimeTypeFromUrl(url: string): Promise<string> {
// First check if it can be guessed from the URL.
const extension = CoreMimetypeUtils.guessExtensionFromUrl(url);
const mimetype = extension && CoreMimetypeUtils.getMimeType(extension);
// Ignore PHP extension for now, it could be serving a file.
if (mimetype && extension !== 'php') {
return mimetype;
}
// Can't be guessed, get the remote mimetype.
const remoteMimetype = await CoreWS.getRemoteFileMimeType(url);
return remoteMimetype || mimetype || '';
}
/** /**
* Given a group name, return the translated name. * Given a group name, return the translated name.
* *

View File

@ -15,30 +15,21 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { InAppBrowserObject } from '@awesome-cordova-plugins/in-app-browser'; import { InAppBrowserObject } from '@awesome-cordova-plugins/in-app-browser';
import { FileEntry } from '@awesome-cordova-plugins/file/ngx'; import { FileEntry } from '@awesome-cordova-plugins/file/ngx';
import { CoreFile } from '@services/file';
import { CoreFileUtils } from '@singletons/file-utils'; import { CoreFileUtils } from '@singletons/file-utils';
import { CoreLang, CoreLangFormat } from '@services/lang'; import { CoreLang } from '@services/lang';
import { CoreWS } from '@services/ws'; import { CoreWS } from '@services/ws';
import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { makeSingleton, FileOpener, WebIntent, Translate } from '@singletons'; import { makeSingleton, Translate } from '@singletons';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
import { CoreFileEntry } from '@services/file-helper'; import { CoreFileEntry } from '@services/file-helper';
import { CoreConstants } from '@/core/constants';
import { CoreWindow } from '@singletons/window';
import { CorePlatform } from '@services/platform';
import { CoreErrorWithOptions } from '@classes/errors/errorwithoptions';
import { CoreFilepool } from '@services/filepool';
import { CoreSites } from '@services/sites';
import { CoreCancellablePromise } from '@classes/cancellable-promise'; import { CoreCancellablePromise } from '@classes/cancellable-promise';
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
import { CoreUrl } from '@singletons/url';
import { CoreArray } from '@singletons/array'; import { CoreArray } from '@singletons/array';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { CoreWait, CoreWaitOptions } from '@singletons/wait'; import { CoreWait, CoreWaitOptions } from '@singletons/wait';
import { CoreQRScan } from '@services/qrscan'; import { CoreQRScan } from '@services/qrscan';
import { CoreErrorHelper } from '@services/error-helper'; import { CoreErrorHelper } from '@services/error-helper';
import { CoreInAppBrowser, CoreInAppBrowserOpenOptions } from '@singletons/iab';
import { CorePromiseUtils, OrderedPromiseData } from '@singletons/promise-utils'; import { CorePromiseUtils, OrderedPromiseData } from '@singletons/promise-utils';
import { CoreOpener, CoreOpenerOpenFileOptions, CoreOpenerOpenInBrowserOptions } from '@singletons/opener';
export type TreeNode<T> = T & { children: TreeNode<T>[] }; export type TreeNode<T> = T & { children: TreeNode<T>[] };
@ -248,30 +239,30 @@ export class CoreUtilsProvider {
/** /**
* Close the InAppBrowser window. * Close the InAppBrowser window.
* *
* @deprecated since 5.0. Use CoreInAppBrowser.closeInAppBrowser instead. * @deprecated since 5.0. Use CoreOpener.closeInAppBrowser instead.
*/ */
closeInAppBrowser(): void { closeInAppBrowser(): void {
CoreInAppBrowser.closeInAppBrowser(); CoreOpener.closeInAppBrowser();
} }
/** /**
* Get inapp browser instance (if any). * Get inapp browser instance (if any).
* *
* @returns IAB instance, undefined if not open. * @returns IAB instance, undefined if not open.
* @deprecated since 5.0. Use CoreInAppBrowser.getInAppBrowserInstance instead. * @deprecated since 5.0. Use CoreOpener.getInAppBrowserInstance instead.
*/ */
getInAppBrowserInstance(): InAppBrowserObject | undefined { getInAppBrowserInstance(): InAppBrowserObject | undefined {
return CoreInAppBrowser.getInAppBrowserInstance(); return CoreOpener.getInAppBrowserInstance();
} }
/** /**
* Check if inapp browser is open. * Check if inapp browser is open.
* *
* @returns Whether it's open. * @returns Whether it's open.
* @deprecated since 5.0. Use CoreInAppBrowser.isInAppBrowserOpen instead. * @deprecated since 5.0. Use CoreOpener.isInAppBrowserOpen instead.
*/ */
isInAppBrowserOpen(): boolean { isInAppBrowserOpen(): boolean {
return CoreInAppBrowser.isInAppBrowserOpen(); return CoreOpener.isInAppBrowserOpen();
} }
/** /**
@ -898,129 +889,35 @@ export class CoreUtilsProvider {
* *
* @param path The local path of the file to be open. * @param path The local path of the file to be open.
* @param options Options. * @param options Options.
* @returns Promise resolved when done. * @deprecated since 5.0. Use CoreOpener.openFile instead.
*/ */
async openFile(path: string, options: CoreUtilsOpenFileOptions = {}): Promise<void> { async openFile(path: string, options: CoreOpenerOpenFileOptions = {}): Promise<void> {
// Convert the path to a native path if needed. await CoreOpener.openFile(path, options);
path = CoreFile.unconvertFileSrc(path);
const extension = CoreMimetypeUtils.getFileExtension(path);
const mimetype = extension && CoreMimetypeUtils.getMimeType(extension);
if (mimetype == 'text/html' && CorePlatform.isAndroid()) {
// Open HTML local files in InAppBrowser, in system browser some embedded files aren't loaded.
CoreInAppBrowser.open(path);
return;
} else if (extension === 'apk' && CorePlatform.isAndroid()) {
const url = await CorePromiseUtils.ignoreErrors(
CoreFilepool.getFileUrlByPath(CoreSites.getCurrentSiteId(), CoreFile.removeBasePath(path)),
);
// @todo MOBILE-4167: Handle urls with expired tokens.
throw new CoreErrorWithOptions(
Translate.instant('core.cannotinstallapkinfo'),
Translate.instant('core.cannotinstallapk'),
url
? [
{
text: Translate.instant('core.openinbrowser'),
handler: () => this.openInBrowser(url),
},
{
text: Translate.instant('core.cancel'),
role: 'cancel',
},
]
: undefined,
);
}
// Path needs to be decoded, the file won't be opened if the path has %20 instead of spaces and so.
try {
path = decodeURIComponent(path);
} catch {
// Error, use the original path.
}
const openFile = async (mimetype?: string) => {
if (this.shouldOpenWithDialog(options)) {
await FileOpener.showOpenWithDialog(path, mimetype || '');
} else {
await FileOpener.open(path, mimetype || '');
}
};
try {
try {
await openFile(mimetype);
} catch (error) {
if (!extension || !error || Number(error.status) !== 9) {
throw error;
}
// Cannot open mimetype. Check if there is a deprecated mimetype for the extension.
const deprecatedMimetype = CoreMimetypeUtils.getDeprecatedMimeType(extension);
if (!deprecatedMimetype || deprecatedMimetype === mimetype) {
throw error;
}
await openFile(deprecatedMimetype);
}
} catch (error) {
this.logger.error('Error opening file ' + path + ' with mimetype ' + mimetype);
this.logger.error('Error: ', JSON.stringify(error));
if (!extension || extension.indexOf('/') > -1 || extension.indexOf('\\') > -1) {
// Extension not found.
throw new Error(Translate.instant('core.erroropenfilenoextension'));
}
throw new Error(Translate.instant('core.erroropenfilenoapp'));
}
} }
/** /**
* Open a URL using InAppBrowser. * Open a URL using InAppBrowser.
* Do not use for files, refer to {@link CoreUtils.openFile}. * Do not use for files, refer to {@link CoreOpener.openFile}.
* *
* @param url The URL to open. * @param url The URL to open.
* @param options Override default options passed to InAppBrowser. * @param options Override default options passed to InAppBrowser.
* @returns The opened window. * @returns The opened window.
* *
* @deprecated since 5.0. Use CoreInAppBrowser.openInApp instead. * @deprecated since 5.0. Use CoreOpener.openInApp instead.
*/ */
openInApp(url: string, options?: CoreInAppBrowserOpenOptions): InAppBrowserObject { openInApp(url: string, options?: CoreOpenerOpenFileOptions): InAppBrowserObject {
return CoreInAppBrowser.open(url, options); return CoreOpener.openInApp(url, options);
} }
/** /**
* Open a URL using a browser. * Open a URL using a browser.
* Do not use for files, refer to {@link CoreUtilsProvider.openFile}.
* *
* @param url The URL to open. * @param url The URL to open.
* @param options Options. * @param options Options.
* @deprecated since 5.0. Use CoreOpener.openInBrowser instead.
*/ */
async openInBrowser(url: string, options: CoreUtilsOpenInBrowserOptions = {}): Promise<void> { async openInBrowser(url: string, options: CoreOpenerOpenInBrowserOptions = {}): Promise<void> {
// eslint-disable-next-line deprecation/deprecation await CoreOpener.openInBrowser(url, options);
const originaUrl = CoreUrl.unfixPluginfileURL(options.originalUrl ?? options.browserWarningUrl ?? url);
if (options.showBrowserWarning || options.showBrowserWarning === undefined) {
try {
await CoreWindow.confirmOpenBrowserIfNeeded(originaUrl);
} catch {
return; // Cancelled, stop.
}
}
const site = CoreSites.getCurrentSite();
CoreAnalytics.logEvent({ type: CoreAnalyticsEventType.OPEN_LINK, link: originaUrl });
window.open(
site?.containsUrl(url)
? CoreUrl.addParamsToUrl(url, { lang: await CoreLang.getCurrentLanguage(CoreLangFormat.LMS) })
: url,
'_system',
);
} }
/** /**
@ -1028,43 +925,10 @@ export class CoreUtilsProvider {
* Specially useful for audio and video since they can be streamed. * Specially useful for audio and video since they can be streamed.
* *
* @param url The URL of the file. * @param url The URL of the file.
* @returns Promise resolved when opened. * @deprecated since 5.0. Use CoreOpener.openOnlineFile instead.
*/ */
async openOnlineFile(url: string): Promise<void> { async openOnlineFile(url: string): Promise<void> {
if (CorePlatform.isAndroid()) { await CoreOpener.openOnlineFile(url);
// In Android we need the mimetype to open it.
const mimetype = await CorePromiseUtils.ignoreErrors(this.getMimeTypeFromUrl(url));
if (!mimetype) {
// Couldn't retrieve mimetype. Return error.
throw new Error(Translate.instant('core.erroropenfilenoextension'));
}
const options = {
action: WebIntent.ACTION_VIEW,
url,
type: mimetype,
};
try {
await WebIntent.startActivity(options);
CoreAnalytics.logEvent({
type: CoreAnalyticsEventType.OPEN_LINK,
link: CoreUrl.unfixPluginfileURL(url),
});
return;
} catch (error) {
this.logger.error('Error opening online file ' + url + ' with mimetype ' + mimetype);
this.logger.error('Error: ', JSON.stringify(error));
throw new Error(Translate.instant('core.erroropenfilenoapp'));
}
}
// In the rest of platforms we need to open them in InAppBrowser.
CoreInAppBrowser.open(url);
} }
/** /**
@ -1558,11 +1422,10 @@ export class CoreUtilsProvider {
* *
* @param options Options. * @param options Options.
* @returns Boolean. * @returns Boolean.
* @deprecated since 5.0. Use CoreOpener.shouldOpenWithDialog instead.
*/ */
shouldOpenWithDialog(options: CoreUtilsOpenFileOptions = {}): boolean { shouldOpenWithDialog(options: CoreOpenerOpenFileOptions = {}): boolean {
const openFileAction = options.iOSOpenFileAction ?? CoreConstants.CONFIG.iOSDefaultOpenFileAction; return CoreOpener.shouldOpenWithDialog(options);
return CorePlatform.isIOS() && openFileAction == OpenFileAction.OPEN_WITH;
} }
} }
@ -1585,36 +1448,9 @@ export type CoreMenuItem<T = number> = {
value: T | number; value: T | number;
}; };
/**
* Options for opening a file.
*/
export type CoreUtilsOpenFileOptions = {
iOSOpenFileAction?: OpenFileAction; // Action to do when opening a file.
};
/**
* Options for opening in browser.
*/
export type CoreUtilsOpenInBrowserOptions = {
showBrowserWarning?: boolean; // Whether to display a warning before opening in browser. Defaults to true.
originalUrl?: string; // Original URL to open (in case the URL was treated, e.g. to add a token or an auto-login).
/**
* @deprecated since 4.3. Use originalUrl instead.
*/
browserWarningUrl?: string;
};
/** /**
* Options for waiting. * Options for waiting.
* *
* @deprecated since 4.5. Use CoreWaitOptions instead. * @deprecated since 4.5. Use CoreWaitOptions instead.
*/ */
export type CoreUtilsWaitOptions = CoreWaitOptions; export type CoreUtilsWaitOptions = CoreWaitOptions;
/**
* Possible default picker actions.
*/
export enum OpenFileAction {
OPEN = 'open',
OPEN_WITH = 'open-with',
}

View File

@ -1,182 +0,0 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { InAppBrowserObject, InAppBrowserOptions } from '@awesome-cordova-plugins/in-app-browser';
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
import { CorePlatform } from '@services/platform';
import { InAppBrowser, NgZone } from '@singletons';
import { CoreEvents } from '@singletons/events';
import { CoreUrl } from './url';
import { CoreConstants } from '../constants';
import { CoreColors } from './colors';
/**
* Singleton with helper functions for InAppBrowser.
*/
export class CoreInAppBrowser {
private static iabInstance?: InAppBrowserObject;
/**
* Close the InAppBrowser window.
*/
static closeInAppBrowser(): void {
if (!CoreInAppBrowser.iabInstance) {
return;
}
CoreInAppBrowser.iabInstance.close();
}
/**
* Get inapp browser instance (if any).
*
* @returns IAB instance, undefined if not open.
*/
static getInAppBrowserInstance(): InAppBrowserObject | undefined {
return CoreInAppBrowser.iabInstance;
}
/**
* Check if inapp browser is open.
*
* @returns Whether it's open.
*/
static isInAppBrowserOpen(): boolean {
return !!CoreInAppBrowser.iabInstance;
}
/**
* Open a URL using InAppBrowser.
* Do not use for files, refer to CoreUtils.openFile.
*
* @param url The URL to open.
* @param options Override default options passed to InAppBrowser.
* @returns The opened window.
*/
static open(url: string, options?: CoreInAppBrowserOpenOptions): InAppBrowserObject {
options = options || {};
options.usewkwebview = 'yes'; // Force WKWebView in iOS.
options.enableViewPortScale = options.enableViewPortScale ?? 'yes'; // Enable zoom on iOS by default.
options.allowInlineMediaPlayback = options.allowInlineMediaPlayback ?? 'yes'; // Allow playing inline videos in iOS.
if (!options.location && CorePlatform.isIOS() && url.indexOf('file://') === 0) {
// The URL uses file protocol, don't show it on iOS.
// In Android we keep it because otherwise we lose the whole toolbar.
options.location = 'no';
}
CoreInAppBrowser.setInAppBrowserToolbarColors(options);
CoreInAppBrowser.iabInstance = InAppBrowser.create(url, '_blank', options);
if (CorePlatform.isMobile()) {
const loadStartUrls: string[] = [];
const loadStartSubscription = CoreInAppBrowser.iabInstance.on('loadstart').subscribe((event) => {
NgZone.run(() => {
// Store the last loaded URLs (max 10).
loadStartUrls.push(event.url);
if (loadStartUrls.length > 10) {
loadStartUrls.shift();
}
CoreEvents.trigger(CoreEvents.IAB_LOAD_START, event);
});
});
const loadStopSubscription = CoreInAppBrowser.iabInstance.on('loadstop').subscribe((event) => {
NgZone.run(() => {
CoreEvents.trigger(CoreEvents.IAB_LOAD_STOP, event);
});
});
const messageSubscription = CoreInAppBrowser.iabInstance.on('message').subscribe((event) => {
NgZone.run(() => {
CoreEvents.trigger(CoreEvents.IAB_MESSAGE, event.data);
});
});
const exitSubscription = CoreInAppBrowser.iabInstance.on('exit').subscribe((event) => {
NgZone.run(() => {
loadStartSubscription.unsubscribe();
loadStopSubscription.unsubscribe();
messageSubscription.unsubscribe();
exitSubscription.unsubscribe();
CoreInAppBrowser.iabInstance = undefined;
CoreEvents.trigger(CoreEvents.IAB_EXIT, event);
});
});
}
CoreAnalytics.logEvent({
type: CoreAnalyticsEventType.OPEN_LINK,
link: CoreUrl.unfixPluginfileURL(options.originalUrl ?? url),
});
return CoreInAppBrowser.iabInstance;
}
/**
* Given some IAB options, set the toolbar colors properties to the right values.
*
* @param options Options to change.
* @returns Changed options.
*/
protected static setInAppBrowserToolbarColors(options: InAppBrowserOptions): InAppBrowserOptions {
if (options.toolbarcolor) {
// Color already set.
return options;
}
// Color not set. Check if it needs to be changed automatically.
let bgColor: string | undefined;
let textColor: string | undefined;
if (CoreConstants.CONFIG.iabToolbarColors === 'auto') {
bgColor = CoreColors.getToolbarBackgroundColor();
} else if (CoreConstants.CONFIG.iabToolbarColors && typeof CoreConstants.CONFIG.iabToolbarColors === 'object') {
bgColor = CoreConstants.CONFIG.iabToolbarColors.background;
textColor = CoreConstants.CONFIG.iabToolbarColors.text;
}
if (!bgColor) {
// Use default color. In iOS, use black background color since the default is transparent and doesn't look good.
options.locationcolor = '#000000';
return options;
}
if (!textColor) {
textColor = CoreColors.isWhiteContrastingBetter(bgColor) ? '#ffffff' : '#000000';
}
options.toolbarcolor = bgColor;
options.closebuttoncolor = textColor;
options.navigationbuttoncolor = textColor;
options.locationcolor = bgColor;
options.locationtextcolor = textColor;
return options;
}
}
/**
* Options for opening in InAppBrowser.
*/
export type CoreInAppBrowserOpenOptions = InAppBrowserOptions & {
originalUrl?: string; // Original URL to open (in case the URL was treated, e.g. to add a token or an auto-login).
};

View File

@ -0,0 +1,433 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { InAppBrowserObject, InAppBrowserOptions } from '@awesome-cordova-plugins/in-app-browser';
import { CoreErrorWithOptions } from '@classes/errors/errorwithoptions';
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
import { CoreFilepool } from '@services/filepool';
import { CoreLang, CoreLangFormat } from '@services/lang';
import { CorePlatform } from '@services/platform';
import { CoreSites } from '@services/sites';
import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { Translate, FileOpener, WebIntent, InAppBrowser, NgZone } from '@singletons';
import { CoreConstants } from '../constants';
import { CoreFile } from '@services/file';
import { CorePromiseUtils } from './promise-utils';
import { CoreUrl } from './url';
import { CoreLogger } from './logger';
import { CoreConfig } from '@services/config';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreEvents } from '@singletons/events';
import { CoreColors } from './colors';
/**
* Singleton with helper functions to handler open files and urls.
*/
export class CoreOpener {
protected static logger = CoreLogger.getInstance('CoreOpener');
// Avoid creating singleton instances.
private constructor() {
// Nothing to do.
}
/**
* Show a confirm before opening a link in browser, unless the user previously marked to not show again.
*
* @param url URL to open.
*/
protected static async confirmOpenBrowserIfNeeded(url: string): Promise<void> {
if (!CoreUrl.isHttpURL(url)) {
// Only ask confirm for http(s), other cases usually launch external apps.
return;
}
// Check if the user decided not to see the warning.
const dontShowWarning = await CoreConfig.get(CoreConstants.SETTINGS_DONT_SHOW_EXTERNAL_LINK_WARN, 0);
if (dontShowWarning) {
return;
}
// Remove common sensitive information from the URL.
url = url
.replace(/token=[^&#]+/gi, 'token=secret')
.replace(/tokenpluginfile\.php\/[^/]+/gi, 'tokenpluginfile.php/secret');
const dontShowAgain = await CoreDomUtils.showPrompt(
Translate.instant('core.warnopeninbrowser', { url }),
undefined,
Translate.instant('core.dontshowagain'),
'checkbox',
);
if (dontShowAgain) {
CoreConfig.set(CoreConstants.SETTINGS_DONT_SHOW_EXTERNAL_LINK_WARN, 1);
}
}
/**
* Open a file using platform specific method.
*
* @param path The local path of the file to be open.
* @param options Options.
* @returns Promise resolved when done.
*/
static async openFile(path: string, options: CoreOpenerOpenFileOptions = {}): Promise<void> {
// Convert the path to a native path if needed.
path = CoreFile.unconvertFileSrc(path);
const extension = CoreMimetypeUtils.getFileExtension(path);
const mimetype = extension && CoreMimetypeUtils.getMimeType(extension);
if (mimetype == 'text/html' && CorePlatform.isAndroid()) {
// Open HTML local files in InAppBrowser, in system browser some embedded files aren't loaded.
CoreOpener.openInApp(path);
return;
} else if (extension === 'apk' && CorePlatform.isAndroid()) {
const url = await CorePromiseUtils.ignoreErrors(
CoreFilepool.getFileUrlByPath(CoreSites.getCurrentSiteId(), CoreFile.removeBasePath(path)),
);
// @todo MOBILE-4167: Handle urls with expired tokens.
throw new CoreErrorWithOptions(
Translate.instant('core.cannotinstallapkinfo'),
Translate.instant('core.cannotinstallapk'),
url
? [
{
text: Translate.instant('core.openinbrowser'),
handler: () => CoreOpener.openInBrowser(url),
},
{
text: Translate.instant('core.cancel'),
role: 'cancel',
},
]
: undefined,
);
}
// Path needs to be decoded, the file won't be opened if the path has %20 instead of spaces and so.
try {
path = decodeURIComponent(path);
} catch {
// Error, use the original path.
}
const openFile = async (mimetype?: string) => {
if (CoreOpener.shouldOpenWithDialog(options)) {
await FileOpener.showOpenWithDialog(path, mimetype || '');
} else {
await FileOpener.open(path, mimetype || '');
}
};
try {
try {
await openFile(mimetype);
} catch (error) {
if (!extension || !error || Number(error.status) !== 9) {
throw error;
}
// Cannot open mimetype. Check if there is a deprecated mimetype for the extension.
const deprecatedMimetype = CoreMimetypeUtils.getDeprecatedMimeType(extension);
if (!deprecatedMimetype || deprecatedMimetype === mimetype) {
throw error;
}
await openFile(deprecatedMimetype);
}
} catch (error) {
CoreOpener.logger.error('Error opening file ' + path + ' with mimetype ' + mimetype);
CoreOpener.logger.error('Error: ', JSON.stringify(error));
if (!extension || extension.indexOf('/') > -1 || extension.indexOf('\\') > -1) {
// Extension not found.
throw new Error(Translate.instant('core.erroropenfilenoextension'));
}
throw new Error(Translate.instant('core.erroropenfilenoapp'));
}
}
/**
* Open a URL using a browser.
* Do not use for files, refer to {@link CoreOpener.openFile}.
*
* @param url The URL to open.
* @param options Options.
*/
static async openInBrowser(url: string, options: CoreOpenerOpenInBrowserOptions = {}): Promise<void> {
// eslint-disable-next-line deprecation/deprecation
const originaUrl = CoreUrl.unfixPluginfileURL(options.originalUrl ?? options.browserWarningUrl ?? url);
if (options.showBrowserWarning || options.showBrowserWarning === undefined) {
try {
await CoreOpener.confirmOpenBrowserIfNeeded(originaUrl);
} catch {
// Cancelled, stop.
return;
}
}
const site = CoreSites.getCurrentSite();
CoreAnalytics.logEvent({ type: CoreAnalyticsEventType.OPEN_LINK, link: originaUrl });
window.open(
site?.containsUrl(url)
? CoreUrl.addParamsToUrl(url, { lang: await CoreLang.getCurrentLanguage(CoreLangFormat.LMS) })
: url,
'_system',
);
}
/**
* Open an online file using platform specific method.
* Specially useful for audio and video since they can be streamed.
*
* @param url The URL of the file.
* @returns Promise resolved when opened.
*/
static async openOnlineFile(url: string): Promise<void> {
if (CorePlatform.isAndroid()) {
// In Android we need the mimetype to open it.
const mimetype = await CorePromiseUtils.ignoreErrors(CoreMimetypeUtils.getMimeTypeFromUrl(url));
if (!mimetype) {
// Couldn't retrieve mimetype. Return error.
throw new Error(Translate.instant('core.erroropenfilenoextension'));
}
const options = {
action: WebIntent.ACTION_VIEW,
url,
type: mimetype,
};
try {
await WebIntent.startActivity(options);
CoreAnalytics.logEvent({
type: CoreAnalyticsEventType.OPEN_LINK,
link: CoreUrl.unfixPluginfileURL(url),
});
return;
} catch (error) {
CoreOpener.logger.error('Error opening online file ' + url + ' with mimetype ' + mimetype);
CoreOpener.logger.error('Error: ', JSON.stringify(error));
throw new Error(Translate.instant('core.erroropenfilenoapp'));
}
}
// In the rest of platforms we need to open them in InAppBrowser.
CoreOpener.openInApp(url);
}
/**
* Given some options, check if a file should be opened with showOpenWithDialog.
*
* @param options Options.
* @returns Boolean.
*/
static shouldOpenWithDialog(options: CoreOpenerOpenFileOptions = {}): boolean {
const openFileAction = options.iOSOpenFileAction ?? CoreConstants.CONFIG.iOSDefaultOpenFileAction;
return CorePlatform.isIOS() && openFileAction == OpenFileAction.OPEN_WITH;
}
private static iabInstance?: InAppBrowserObject;
/**
* Close the InAppBrowser window.
*/
static closeInAppBrowser(): void {
if (!CoreOpener.iabInstance) {
return;
}
CoreOpener.iabInstance.close();
}
/**
* Get inapp browser instance (if any).
*
* @returns IAB instance, undefined if not open.
*/
static getInAppBrowserInstance(): InAppBrowserObject | undefined {
return CoreOpener.iabInstance;
}
/**
* Check if inapp browser is open.
*
* @returns Whether it's open.
*/
static isInAppBrowserOpen(): boolean {
return !!CoreOpener.iabInstance;
}
/**
* Open a URL using InAppBrowser.
* Do not use for files, refer to CoreOpener.openFile.
*
* @param url The URL to open.
* @param options Override default options passed to InAppBrowser.
* @returns The opened window.
*/
static openInApp(url: string, options?: CoreOpenerOpenInAppBrowserOptions): InAppBrowserObject {
options = options || {};
options.usewkwebview = 'yes'; // Force WKWebView in iOS.
options.enableViewPortScale = options.enableViewPortScale ?? 'yes'; // Enable zoom on iOS by default.
options.allowInlineMediaPlayback = options.allowInlineMediaPlayback ?? 'yes'; // Allow playing inline videos in iOS.
if (!options.location && CorePlatform.isIOS() && url.indexOf('file://') === 0) {
// The URL uses file protocol, don't show it on iOS.
// In Android we keep it because otherwise we lose the whole toolbar.
options.location = 'no';
}
CoreOpener.setInAppBrowserToolbarColors(options);
CoreOpener.iabInstance = InAppBrowser.create(url, '_blank', options);
if (CorePlatform.isMobile()) {
const loadStartUrls: string[] = [];
const loadStartSubscription = CoreOpener.iabInstance.on('loadstart').subscribe((event) => {
NgZone.run(() => {
// Store the last loaded URLs (max 10).
loadStartUrls.push(event.url);
if (loadStartUrls.length > 10) {
loadStartUrls.shift();
}
CoreEvents.trigger(CoreEvents.IAB_LOAD_START, event);
});
});
const loadStopSubscription = CoreOpener.iabInstance.on('loadstop').subscribe((event) => {
NgZone.run(() => {
CoreEvents.trigger(CoreEvents.IAB_LOAD_STOP, event);
});
});
const messageSubscription = CoreOpener.iabInstance.on('message').subscribe((event) => {
NgZone.run(() => {
CoreEvents.trigger(CoreEvents.IAB_MESSAGE, event.data);
});
});
const exitSubscription = CoreOpener.iabInstance.on('exit').subscribe((event) => {
NgZone.run(() => {
loadStartSubscription.unsubscribe();
loadStopSubscription.unsubscribe();
messageSubscription.unsubscribe();
exitSubscription.unsubscribe();
CoreOpener.iabInstance = undefined;
CoreEvents.trigger(CoreEvents.IAB_EXIT, event);
});
});
}
CoreAnalytics.logEvent({
type: CoreAnalyticsEventType.OPEN_LINK,
link: CoreUrl.unfixPluginfileURL(options.originalUrl ?? url),
});
return CoreOpener.iabInstance;
}
/**
* Given some IAB options, set the toolbar colors properties to the right values.
*
* @param options Options to change.
* @returns Changed options.
*/
protected static setInAppBrowserToolbarColors(options: InAppBrowserOptions): InAppBrowserOptions {
if (options.toolbarcolor) {
// Color already set.
return options;
}
// Color not set. Check if it needs to be changed automatically.
let bgColor: string | undefined;
let textColor: string | undefined;
if (CoreConstants.CONFIG.iabToolbarColors === 'auto') {
bgColor = CoreColors.getToolbarBackgroundColor();
} else if (CoreConstants.CONFIG.iabToolbarColors && typeof CoreConstants.CONFIG.iabToolbarColors === 'object') {
bgColor = CoreConstants.CONFIG.iabToolbarColors.background;
textColor = CoreConstants.CONFIG.iabToolbarColors.text;
}
if (!bgColor) {
// Use default color. In iOS, use black background color since the default is transparent and doesn't look good.
options.locationcolor = '#000000';
return options;
}
if (!textColor) {
textColor = CoreColors.isWhiteContrastingBetter(bgColor) ? '#ffffff' : '#000000';
}
options.toolbarcolor = bgColor;
options.closebuttoncolor = textColor;
options.navigationbuttoncolor = textColor;
options.locationcolor = bgColor;
options.locationtextcolor = textColor;
return options;
}
}
/**
* Options for opening in InAppBrowser.
*/
export type CoreOpenerOpenInAppBrowserOptions = InAppBrowserOptions & {
originalUrl?: string; // Original URL to open (in case the URL was treated, e.g. to add a token or an auto-login).
};
/**
* Options for opening a file.
*/
export type CoreOpenerOpenFileOptions = {
iOSOpenFileAction?: OpenFileAction; // Action to do when opening a file.
};
/**
* Options for opening in browser.
*/
export type CoreOpenerOpenInBrowserOptions = {
showBrowserWarning?: boolean; // Whether to display a warning before opening in browser. Defaults to true.
originalUrl?: string; // Original URL to open (in case the URL was treated, e.g. to add a token or an auto-login).
/**
* @deprecated since 4.3. Use originalUrl instead.
*/
browserWarningUrl?: string;
};
/**
* Possible default picker actions.
*/
export enum OpenFileAction {
OPEN = 'open',
OPEN_WITH = 'open-with',
}

View File

@ -13,15 +13,11 @@
// limitations under the License. // limitations under the License.
import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper'; import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper';
import { CoreConfig } from '@services/config';
import { CoreFileHelper } from '@services/file-helper'; import { CoreFileHelper } from '@services/file-helper';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUrl } from '@singletons/url'; import { CoreUrl } from '@singletons/url';
import { CoreUtils } from '@services/utils/utils'; import { CoreOpener } from './opener';
import { Translate } from '@singletons';
import { CoreConstants } from '../constants';
/** /**
* Singleton with helper functions for windows. * Singleton with helper functions for windows.
@ -36,36 +32,16 @@ export class CoreWindow {
/** /**
* Show a confirm before opening a link in browser, unless the user previously marked to not show again. * Show a confirm before opening a link in browser, unless the user previously marked to not show again.
* *
* @param url URL to open. * @returns Only shows a deprecation warning.
* @returns Promise resolved if confirmed, rejected if rejected. * @deprecated since 5.0. Not used anymore. Use CoreOpener.openInBrowser and it will confirm if needed.
*/ */
static async confirmOpenBrowserIfNeeded(url: string): Promise<void> { static async confirmOpenBrowserIfNeeded(): Promise<void> {
if (!CoreUrl.isHttpURL(url)) { const { CoreLogger } = await import('@singletons/logger');
// Only ask confirm for http(s), other cases usually launch external apps.
return;
}
// Check if the user decided not to see the warning. CoreLogger.getInstance('CoreWindow')
const dontShowWarning = await CoreConfig.get(CoreConstants.SETTINGS_DONT_SHOW_EXTERNAL_LINK_WARN, 0); .warn('confirmOpenBrowserIfNeeded has been deprecated since 5.0. Not used anymore.\
if (dontShowWarning) { Use CoreOpener.openInBrowser and it will confirm if needed.');
return;
}
// Remove common sensitive information from the URL.
url = url
.replace(/token=[^&#]+/gi, 'token=secret')
.replace(/tokenpluginfile\.php\/[^/]+/gi, 'tokenpluginfile.php/secret');
const dontShowAgain = await CoreDomUtils.showPrompt(
Translate.instant('core.warnopeninbrowser', { url }),
undefined,
Translate.instant('core.dontshowagain'),
'checkbox',
);
if (dontShowAgain) {
CoreConfig.set(CoreConstants.SETTINGS_DONT_SHOW_EXTERNAL_LINK_WARN, 1);
}
} }
/** /**
@ -88,7 +64,7 @@ export class CoreWindow {
} }
} }
await CoreUtils.openFile(url); await CoreOpener.openFile(url);
} else { } else {
let treated = false; let treated = false;
@ -101,7 +77,7 @@ export class CoreWindow {
// Not opened in the app, open with browser. Check if we need to auto-login. // Not opened in the app, open with browser. Check if we need to auto-login.
if (!CoreSites.isLoggedIn()) { if (!CoreSites.isLoggedIn()) {
// Not logged in, cannot auto-login. // Not logged in, cannot auto-login.
CoreUtils.openInBrowser(url); CoreOpener.openInBrowser(url);
} else { } else {
await CoreSites.getRequiredCurrentSite().openInBrowserWithAutoLogin(url); await CoreSites.getRequiredCurrentSite().openInBrowserWithAutoLogin(url);
} }