MOBILE-2995 qr: Improve handling of custom URL scheme links
parent
c3f39abafa
commit
f9df95c727
|
@ -1269,14 +1269,17 @@ export class CoreCourseHelperProvider {
|
|||
// Get the module.
|
||||
return this.courseProvider.getModule(moduleId, courseId, sectionId, false, false, siteId, modName);
|
||||
}).then((module) => {
|
||||
module.handlerData = this.moduleDelegate.getModuleDataFor(module.modname, module, courseId, sectionId, false);
|
||||
|
||||
if (navCtrl && module.handlerData && module.handlerData.action) {
|
||||
if (navCtrl && this.sitesProvider.isLoggedIn() && this.sitesProvider.getCurrentSiteId() == site.getId()) {
|
||||
// If the link handler for this module passed through navCtrl, we can use the module's handler to navigate cleanly.
|
||||
// Otherwise, we will redirect below.
|
||||
modal.dismiss();
|
||||
module.handlerData = this.moduleDelegate.getModuleDataFor(module.modname, module, courseId, sectionId, false);
|
||||
|
||||
return module.handlerData.action(new Event('click'), navCtrl, module, courseId, undefined, modParams);
|
||||
if (module.handlerData && module.handlerData.action) {
|
||||
modal.dismiss();
|
||||
|
||||
return module.handlerData.action(new Event('click'), navCtrl, module, courseId, undefined, modParams);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.warn('navCtrl was not passed to navigateToModule by the link handler for ' + module.modname);
|
||||
|
|
|
@ -17,6 +17,7 @@ import { IonicPage, NavController, ModalController, AlertController, NavParams }
|
|||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreSitesProvider, CoreSiteCheckResponse, CoreLoginSiteInfo } from '@providers/sites';
|
||||
import { CoreCustomURLSchemesProvider } from '@providers/urlschemes';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreUrlUtilsProvider } from '@providers/utils/url';
|
||||
|
@ -72,7 +73,8 @@ export class CoreLoginSitePage {
|
|||
protected domUtils: CoreDomUtilsProvider,
|
||||
protected eventsProvider: CoreEventsProvider,
|
||||
protected translate: TranslateService,
|
||||
protected utils: CoreUtilsProvider) {
|
||||
protected utils: CoreUtilsProvider,
|
||||
private urlSchemesProvider: CoreCustomURLSchemesProvider) {
|
||||
|
||||
this.showKeyboard = !!navParams.get('showKeyboard');
|
||||
this.showScanQR = this.utils.canScanQR();
|
||||
|
@ -365,9 +367,14 @@ export class CoreLoginSitePage {
|
|||
// Scan for a QR code.
|
||||
this.utils.scanQR().then((text) => {
|
||||
if (text) {
|
||||
this.siteForm.controls.siteUrl.setValue(text);
|
||||
if (this.urlSchemesProvider.isCustomURL(text)) {
|
||||
this.urlSchemesProvider.handleCustomURL(text);
|
||||
} else {
|
||||
// Not a custom URL scheme, put the text in the field.
|
||||
this.siteForm.controls.siteUrl.setValue(text);
|
||||
|
||||
this.connect(new Event('click'), text);
|
||||
this.connect(new Event('click'), text);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import { Component, OnDestroy } from '@angular/core';
|
|||
import { IonicPage, NavController } from 'ionic-angular';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreCustomURLSchemesProvider } from '@providers/urlschemes';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreMainMenuDelegate, CoreMainMenuHandlerData } from '../../providers/delegate';
|
||||
|
@ -50,16 +51,17 @@ export class CoreMainMenuMorePage implements OnDestroy {
|
|||
protected langObserver;
|
||||
protected updateSiteObserver;
|
||||
|
||||
constructor(private menuDelegate: CoreMainMenuDelegate,
|
||||
private sitesProvider: CoreSitesProvider,
|
||||
private navCtrl: NavController,
|
||||
private mainMenuProvider: CoreMainMenuProvider,
|
||||
constructor(protected menuDelegate: CoreMainMenuDelegate,
|
||||
protected sitesProvider: CoreSitesProvider,
|
||||
protected navCtrl: NavController,
|
||||
protected mainMenuProvider: CoreMainMenuProvider,
|
||||
eventsProvider: CoreEventsProvider,
|
||||
private loginHelper: CoreLoginHelperProvider,
|
||||
private utils: CoreUtilsProvider,
|
||||
private linkHelper: CoreContentLinksHelperProvider,
|
||||
private textUtils: CoreTextUtilsProvider,
|
||||
private translate: TranslateService) {
|
||||
protected loginHelper: CoreLoginHelperProvider,
|
||||
protected utils: CoreUtilsProvider,
|
||||
protected linkHelper: CoreContentLinksHelperProvider,
|
||||
protected textUtils: CoreTextUtilsProvider,
|
||||
protected urlSchemesProvider: CoreCustomURLSchemesProvider,
|
||||
protected translate: TranslateService) {
|
||||
|
||||
this.langObserver = eventsProvider.on(CoreEventsProvider.LANGUAGE_CHANGED, this.loadSiteInfo.bind(this));
|
||||
this.updateSiteObserver = eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.loadSiteInfo.bind(this),
|
||||
|
@ -175,8 +177,10 @@ export class CoreMainMenuMorePage implements OnDestroy {
|
|||
// Scan for a QR code.
|
||||
this.utils.scanQR().then((text) => {
|
||||
if (text) {
|
||||
// Check if it's a URL. We basically check it has a protocol and doesn't include any space.
|
||||
if (/^[^:]{2,}:\/\/[^ ]+$/i.test(text)) {
|
||||
if (this.urlSchemesProvider.isCustomURL(text)) {
|
||||
// Is a custom URL scheme, handle it.
|
||||
this.urlSchemesProvider.handleCustomURL(text);
|
||||
} else if (/^[^:]{2,}:\/\/[^ ]+$/i.test(text)) { // Check if it's a URL.
|
||||
// Check if the app can handle the URL.
|
||||
this.linkHelper.handleLink(text, undefined, this.navCtrl, true, true).then((treated) => {
|
||||
if (!treated) {
|
||||
|
|
|
@ -35,6 +35,7 @@ import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
|||
import { CoreFilterProvider, CoreFilterFilter, CoreFilterFormatTextOptions } from '@core/filter/providers/filter';
|
||||
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
|
||||
import { CoreFilterDelegate } from '@core/filter/providers/delegate';
|
||||
import { CoreCustomURLSchemesProvider } from '@providers/urlschemes';
|
||||
|
||||
/**
|
||||
* Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective
|
||||
|
@ -87,13 +88,14 @@ export class CoreFormatTextDirective implements OnChanges {
|
|||
protected contentLinksHelper: CoreContentLinksHelperProvider,
|
||||
@Optional() protected navCtrl: NavController,
|
||||
@Optional() protected content: Content, @Optional()
|
||||
protected svComponent: CoreSplitViewComponent,
|
||||
@Optional() protected svComponent: CoreSplitViewComponent,
|
||||
protected iframeUtils: CoreIframeUtilsProvider,
|
||||
protected eventsProvider: CoreEventsProvider,
|
||||
protected filterProvider: CoreFilterProvider,
|
||||
protected filterHelper: CoreFilterHelperProvider,
|
||||
protected filterDelegate: CoreFilterDelegate,
|
||||
protected viewContainerRef: ViewContainerRef,
|
||||
protected urlSchemesProvider: CoreCustomURLSchemesProvider
|
||||
) {
|
||||
|
||||
this.element = element.nativeElement;
|
||||
|
@ -467,7 +469,7 @@ export class CoreFormatTextDirective implements OnChanges {
|
|||
anchors.forEach((anchor) => {
|
||||
// Angular 2 doesn't let adding directives dynamically. Create the CoreLinkDirective manually.
|
||||
const linkDir = new CoreLinkDirective(anchor, this.domUtils, this.utils, this.sitesProvider, this.urlUtils,
|
||||
this.contentLinksHelper, this.navCtrl, this.content, this.svComponent, this.textUtils);
|
||||
this.contentLinksHelper, this.navCtrl, this.content, this.svComponent, this.textUtils, this.urlSchemesProvider);
|
||||
linkDir.capture = true;
|
||||
linkDir.ngOnInit();
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
|||
import { CoreUrlUtilsProvider } from '@providers/utils/url';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
||||
import { CoreConfigConstants } from '../configconstants';
|
||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreCustomURLSchemesProvider } from '@providers/urlschemes';
|
||||
|
||||
/**
|
||||
* Directive to open a link in external browser.
|
||||
|
@ -39,11 +39,17 @@ export class CoreLinkDirective implements OnInit {
|
|||
|
||||
protected element: HTMLElement;
|
||||
|
||||
constructor(element: ElementRef, private domUtils: CoreDomUtilsProvider, private utils: CoreUtilsProvider,
|
||||
private sitesProvider: CoreSitesProvider, private urlUtils: CoreUrlUtilsProvider,
|
||||
private contentLinksHelper: CoreContentLinksHelperProvider, @Optional() private navCtrl: NavController,
|
||||
@Optional() private content: Content, @Optional() private svComponent: CoreSplitViewComponent,
|
||||
private textUtils: CoreTextUtilsProvider) {
|
||||
constructor(element: ElementRef,
|
||||
protected domUtils: CoreDomUtilsProvider,
|
||||
protected utils: CoreUtilsProvider,
|
||||
protected sitesProvider: CoreSitesProvider,
|
||||
protected urlUtils: CoreUrlUtilsProvider,
|
||||
protected contentLinksHelper: CoreContentLinksHelperProvider,
|
||||
@Optional() protected navCtrl: NavController,
|
||||
@Optional() protected content: Content,
|
||||
@Optional() protected svComponent: CoreSplitViewComponent,
|
||||
protected textUtils: CoreTextUtilsProvider,
|
||||
protected urlSchemesProvider: CoreCustomURLSchemesProvider) {
|
||||
// This directive can be added dynamically. In that case, the first param is the anchor HTMLElement.
|
||||
this.element = element.nativeElement || element;
|
||||
}
|
||||
|
@ -90,7 +96,6 @@ export class CoreLinkDirective implements OnInit {
|
|||
* @param href HREF to be opened.
|
||||
*/
|
||||
protected navigate(href: string): void {
|
||||
const contentLinksScheme = CoreConfigConstants.customurlscheme + '://link=';
|
||||
|
||||
if (this.urlUtils.isLocalFileUrl(href)) {
|
||||
// We have a local file.
|
||||
|
@ -107,10 +112,8 @@ export class CoreLinkDirective implements OnInit {
|
|||
// Look for id or name.
|
||||
this.domUtils.scrollToElementBySelector(this.content, '#' + href + ', [name=\'' + href + '\']');
|
||||
}
|
||||
} else if (href.indexOf(contentLinksScheme) === 0) {
|
||||
// Link should be treated by Custom URL Scheme. Encode the right part, otherwise ':' is removed in iOS.
|
||||
href = contentLinksScheme + encodeURIComponent(href.replace(contentLinksScheme, ''));
|
||||
this.utils.openInBrowser(href);
|
||||
} else if (this.urlSchemesProvider.isCustomURL(href)) {
|
||||
this.urlSchemesProvider.handleCustomURL(href);
|
||||
} else {
|
||||
|
||||
// It's an external link, we will open with browser. Check if we need to auto-login.
|
||||
|
|
|
@ -54,12 +54,19 @@ export class CoreCustomURLSchemesProvider {
|
|||
protected logger;
|
||||
protected lastUrls = {};
|
||||
|
||||
constructor(logger: CoreLoggerProvider, private appProvider: CoreAppProvider, private utils: CoreUtilsProvider,
|
||||
private loginHelper: CoreLoginHelperProvider, private linksHelper: CoreContentLinksHelperProvider,
|
||||
private initDelegate: CoreInitDelegate, private domUtils: CoreDomUtilsProvider, private urlUtils: CoreUrlUtilsProvider,
|
||||
private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider,
|
||||
private linksDelegate: CoreContentLinksDelegate, private translate: TranslateService,
|
||||
private sitePluginsProvider: CoreSitePluginsProvider) {
|
||||
constructor(logger: CoreLoggerProvider,
|
||||
protected appProvider: CoreAppProvider,
|
||||
protected utils: CoreUtilsProvider,
|
||||
protected loginHelper: CoreLoginHelperProvider,
|
||||
protected linksHelper: CoreContentLinksHelperProvider,
|
||||
protected initDelegate: CoreInitDelegate,
|
||||
protected domUtils: CoreDomUtilsProvider,
|
||||
protected urlUtils: CoreUrlUtilsProvider,
|
||||
protected sitesProvider: CoreSitesProvider,
|
||||
protected textUtils: CoreTextUtilsProvider,
|
||||
protected linksDelegate: CoreContentLinksDelegate,
|
||||
protected translate: TranslateService,
|
||||
protected sitePluginsProvider: CoreSitePluginsProvider) {
|
||||
this.logger = logger.getInstance('CoreCustomURLSchemesProvider');
|
||||
}
|
||||
|
||||
|
@ -282,8 +289,7 @@ export class CoreCustomURLSchemesProvider {
|
|||
* @return Promise resolved with the data.
|
||||
*/
|
||||
protected getCustomURLData(url: string): Promise<CoreCustomURLSchemesParams> {
|
||||
const urlScheme = CoreConfigConstants.customurlscheme + '://';
|
||||
if (url.indexOf(urlScheme) == -1) {
|
||||
if (!this.isCustomURL(url)) {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
|
@ -291,7 +297,7 @@ export class CoreCustomURLSchemesProvider {
|
|||
this.logger.debug('Treating custom URL scheme: ' + url);
|
||||
|
||||
// Delete the sso scheme from the URL.
|
||||
url = url.replace(urlScheme, '');
|
||||
url = this.removeCustomURLScheme(url);
|
||||
|
||||
// Detect if there's a user specified.
|
||||
const username = this.urlUtils.getUsernameFromUrl(url);
|
||||
|
@ -344,8 +350,7 @@ export class CoreCustomURLSchemesProvider {
|
|||
* @return Promise resolved with the data.
|
||||
*/
|
||||
protected getCustomURLLinkData(url: string): Promise<CoreCustomURLSchemesParams> {
|
||||
const contentLinksScheme = CoreConfigConstants.customurlscheme + '://link=';
|
||||
if (url.indexOf(contentLinksScheme) == -1) {
|
||||
if (!this.isCustomURLLink(url)) {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
|
@ -353,7 +358,7 @@ export class CoreCustomURLSchemesProvider {
|
|||
this.logger.debug('Treating custom URL scheme with link param: ' + url);
|
||||
|
||||
// Delete the sso scheme from the URL.
|
||||
url = url.replace(contentLinksScheme, '');
|
||||
url = this.removeCustomURLLinkScheme(url);
|
||||
|
||||
// Detect if there's a user specified.
|
||||
const username = this.urlUtils.getUsernameFromUrl(url);
|
||||
|
@ -408,8 +413,7 @@ export class CoreCustomURLSchemesProvider {
|
|||
* @return Promise resolved with the data.
|
||||
*/
|
||||
protected getCustomURLTokenData(url: string): Promise<CoreCustomURLSchemesParams> {
|
||||
const ssoScheme = CoreConfigConstants.customurlscheme + '://token=';
|
||||
if (url.indexOf(ssoScheme) == -1) {
|
||||
if (!this.isCustomURLToken(url)) {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
|
@ -428,7 +432,7 @@ export class CoreCustomURLSchemesProvider {
|
|||
this.logger.debug('App launched by URL with an SSO');
|
||||
|
||||
// Delete the sso scheme from the URL.
|
||||
url = url.replace(ssoScheme, '');
|
||||
url = this.removeCustomURLTokenScheme(url);
|
||||
|
||||
// Some platforms like Windows add a slash at the end. Remove it.
|
||||
// Some sites add a # at the end of the URL. If it's there, remove it.
|
||||
|
@ -488,6 +492,36 @@ export class CoreCustomURLSchemesProvider {
|
|||
|
||||
return url.indexOf(CoreConfigConstants.customurlscheme + '://token=') != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the scheme from a custom URL.
|
||||
*
|
||||
* @param url URL to treat.
|
||||
* @return URL without scheme.
|
||||
*/
|
||||
removeCustomURLScheme(url: string): string {
|
||||
return url.replace(CoreConfigConstants.customurlscheme + '://', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the scheme and the "link=" prefix from a link custom URL.
|
||||
*
|
||||
* @param url URL to treat.
|
||||
* @return URL without scheme and prefix.
|
||||
*/
|
||||
removeCustomURLLinkScheme(url: string): string {
|
||||
return url.replace(CoreConfigConstants.customurlscheme + '://link=', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the scheme and the "token=" prefix from a token custom URL.
|
||||
*
|
||||
* @param url URL to treat.
|
||||
* @return URL without scheme and prefix.
|
||||
*/
|
||||
removeCustomURLTokenScheme(url: string): string {
|
||||
return url.replace(CoreConfigConstants.customurlscheme + '://token=', '');
|
||||
}
|
||||
}
|
||||
|
||||
export class CoreCustomURLSchemes extends makeSingleton(CoreCustomURLSchemesProvider) {}
|
||||
|
|
Loading…
Reference in New Issue