diff --git a/scripts/langindex.json b/scripts/langindex.json index a3738eb16..db78fc2ed 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -1373,7 +1373,8 @@ "core.cannotconnecttrouble": "local_moodlemobileapp", "core.cannotconnectverify": "local_moodlemobileapp", "core.cannotdownloadfiles": "local_moodlemobileapp", - "core.cannotopeninapp": "moodle", + "core.cannotopeninapp": "local_moodlemobileapp", + "core.cannotopeninappdownload": "local_moodlemobileapp", "core.captureaudio": "local_moodlemobileapp", "core.capturedimage": "local_moodlemobileapp", "core.captureimage": "local_moodlemobileapp", @@ -1526,6 +1527,7 @@ "core.done": "survey", "core.download": "moodle", "core.downloaded": "local_moodlemobileapp", + "core.downloadfile": "moodle", "core.downloading": "local_moodlemobileapp", "core.edit": "moodle", "core.editor.autosavesucceeded": "editor_atto", @@ -1917,7 +1919,7 @@ "core.offline": "message", "core.ok": "moodle", "core.online": "message", - "core.openfile": "moodle", + "core.openfile": "local_moodlemobileapp", "core.openfullimage": "local_moodlemobileapp", "core.openinbrowser": "local_moodlemobileapp", "core.openmodinbrowser": "local_moodlemobileapp", diff --git a/src/components/local-file/local-file.ts b/src/components/local-file/local-file.ts index cd0c573a3..eba54e903 100644 --- a/src/components/local-file/local-file.ts +++ b/src/components/local-file/local-file.ts @@ -15,6 +15,7 @@ import { Component, Input, Output, OnInit, EventEmitter, ViewChild, ElementRef } from '@angular/core'; import { CoreEventsProvider } from '@providers/events'; import { CoreFileProvider } from '@providers/file'; +import { CoreFileHelper } from '@providers/file-helper'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype'; @@ -103,7 +104,7 @@ export class CoreLocalFileComponent implements OnInit { * * @param e Click event. */ - fileClicked(e: Event): void { + async fileClicked(e: Event): Promise { if (this.editMode) { return; } @@ -114,6 +115,14 @@ export class CoreLocalFileComponent implements OnInit { if (this.utils.isTrueOrOne(this.overrideClick) && this.onClick.observers.length) { this.onClick.emit(); } else { + if (!CoreFileHelper.instance.isOpenableInApp(this.file)) { + try { + await CoreFileHelper.instance.showConfirmOpenUnsupportedFile(); + } catch (error) { + return; // Cancelled, stop. + } + } + this.utils.openFile(this.file.toURL()); } } diff --git a/src/directives/link.ts b/src/directives/link.ts index 2384bbefa..9b8e96fe9 100644 --- a/src/directives/link.ts +++ b/src/directives/link.ts @@ -14,6 +14,7 @@ import { Directive, Input, OnInit, ElementRef, Optional } from '@angular/core'; import { NavController, Content } from 'ionic-angular'; +import { CoreFileHelper } from '@providers/file-helper'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreUrlUtilsProvider } from '@providers/utils/url'; @@ -21,7 +22,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; import { CoreSplitViewComponent } from '@components/split-view/split-view'; import { CoreTextUtilsProvider } from '@providers/utils/text'; -import { CoreCustomURLSchemesProvider, CoreCustomURLSchemesHandleError } from '@providers/urlschemes'; +import { CoreCustomURLSchemesProvider } from '@providers/urlschemes'; /** * Directive to open a link in external browser. @@ -94,14 +95,27 @@ export class CoreLinkDirective implements OnInit { * Convenience function to correctly navigate, open file or url in the browser. * * @param href HREF to be opened. + * @return Promise resolved when done. */ - protected navigate(href: string): void { + protected async navigate(href: string): Promise { if (this.urlUtils.isLocalFileUrl(href)) { // We have a local file. - this.utils.openFile(href).catch((error) => { + const filename = href.substr(href.lastIndexOf('/') + 1); + + if (!CoreFileHelper.instance.isOpenableInApp({ filename })) { + try { + await CoreFileHelper.instance.showConfirmOpenUnsupportedFile(); + } catch (error) { + return; // Cancelled, stop. + } + } + + try { + await this.utils.openFile(href); + } catch (error) { this.domUtils.showErrorModal(error); - }); + } } else if (href.charAt(0) == '#') { href = href.substr(1); // In site links @@ -113,9 +127,11 @@ export class CoreLinkDirective implements OnInit { this.domUtils.scrollToElementBySelector(this.content, '#' + href + ', [name=\'' + href + '\']'); } } else if (this.urlSchemesProvider.isCustomURL(href)) { - this.urlSchemesProvider.handleCustomURL(href).catch((error: CoreCustomURLSchemesHandleError) => { + try { + await this.urlSchemesProvider.handleCustomURL(href); + } catch (error) { this.urlSchemesProvider.treatHandleCustomURLError(error); - }); + } } else { // It's an external link, we will open with browser. Check if we need to auto-login. @@ -139,9 +155,9 @@ export class CoreLinkDirective implements OnInit { if (this.autoLogin == 'yes') { if (this.inApp) { - this.sitesProvider.getCurrentSite().openInAppWithAutoLogin(href); + await this.sitesProvider.getCurrentSite().openInAppWithAutoLogin(href); } else { - this.sitesProvider.getCurrentSite().openInBrowserWithAutoLogin(href); + await this.sitesProvider.getCurrentSite().openInBrowserWithAutoLogin(href); } } else if (this.autoLogin == 'no') { if (this.inApp) { @@ -151,9 +167,9 @@ export class CoreLinkDirective implements OnInit { } } else { if (this.inApp) { - this.sitesProvider.getCurrentSite().openInAppWithAutoLoginIfSameSite(href); + await this.sitesProvider.getCurrentSite().openInAppWithAutoLoginIfSameSite(href); } else { - this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(href); + await this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(href); } } } diff --git a/src/providers/file-helper.ts b/src/providers/file-helper.ts index c2c082038..9ec8d77a9 100644 --- a/src/providers/file-helper.ts +++ b/src/providers/file-helper.ts @@ -343,10 +343,10 @@ export class CoreFileHelperProvider { * @param file The file to check. * @return bool. */ - isOpenableInApp(file: any): boolean { + isOpenableInApp(file: {filename?: string, name?: string}): boolean { const re = /(?:\.([^.]+))?$/; - const ext = re.exec(file.filename)[1]; + const ext = re.exec(file.filename || file.name)[1]; return !this.isFileTypeExcludedInApp(ext); } diff --git a/src/providers/utils/iframe.ts b/src/providers/utils/iframe.ts index fc9d3afb9..0fdc5af74 100644 --- a/src/providers/utils/iframe.ts +++ b/src/providers/utils/iframe.ts @@ -18,6 +18,7 @@ import { TranslateService } from '@ngx-translate/core'; import { Network } from '@ionic-native/network'; import { CoreApp, CoreAppProvider } from '../app'; import { CoreFileProvider } from '../file'; +import { CoreFileHelper } from '../file-helper'; import { CoreLoggerProvider } from '../logger'; import { CoreSitesProvider } from '../sites'; import { CoreDomUtilsProvider } from './dom'; @@ -390,6 +391,16 @@ export class CoreIframeUtilsProvider { } } else if (this.urlUtils.isLocalFileUrl(url)) { // It's a local file. + const filename = url.substr(url.lastIndexOf('/') + 1); + + if (!CoreFileHelper.instance.isOpenableInApp({ filename })) { + try { + await CoreFileHelper.instance.showConfirmOpenUnsupportedFile(); + } catch (error) { + return; // Cancelled, stop. + } + } + try { await this.utils.openFile(url); } catch (error) { @@ -409,9 +420,10 @@ export class CoreIframeUtilsProvider { * @param link Data of the link clicked. * @param element Frame element. * @param event Click event. + * @return Promise resolved when done. */ - protected linkClicked(link: {href: string, target?: string}, element?: HTMLFrameElement | HTMLObjectElement, event?: Event) - : void { + protected async linkClicked(link: {href: string, target?: string}, element?: HTMLFrameElement | HTMLObjectElement, + event?: Event): Promise { if (event && event.defaultPrevented) { // Event already prevented by some other code. return; @@ -445,14 +457,27 @@ export class CoreIframeUtilsProvider { if (!this.sitesProvider.isLoggedIn()) { this.utils.openInBrowser(link.href); } else { - this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(link.href); + await this.sitesProvider.getCurrentSite().openInBrowserWithAutoLoginIfSameSite(link.href); } } else if (link.target == '_parent' || link.target == '_top' || link.target == '_blank') { // Opening links with _parent, _top or _blank can break the app. We'll open it in InAppBrowser. event && event.preventDefault(); - this.utils.openFile(link.href).catch((error) => { + + const filename = link.href.substr(link.href.lastIndexOf('/') + 1); + + if (!CoreFileHelper.instance.isOpenableInApp({ filename })) { + try { + await CoreFileHelper.instance.showConfirmOpenUnsupportedFile(); + } catch (error) { + return; // Cancelled, stop. + } + } + + try { + await this.utils.openFile(link.href); + } catch (error) { this.domUtils.showErrorModal(error); - }); + } } else if (CoreApp.instance.isIOS() && (!link.target || link.target == '_self') && element) { // In cordova ios 4.1.0 links inside iframes stopped working. We'll manually treat them. event && event.preventDefault(); diff --git a/src/singletons/window.ts b/src/singletons/window.ts index e95e6dc6e..c17855ab1 100644 --- a/src/singletons/window.ts +++ b/src/singletons/window.ts @@ -13,6 +13,7 @@ // limitations under the License. import { NavController } from 'ionic-angular'; +import { CoreFileHelper } from '@providers/file-helper'; import { CoreSites } from '@providers/sites'; import { CoreUrlUtils } from '@providers/utils/url'; import { CoreUtils } from '@providers/utils/utils'; @@ -43,6 +44,16 @@ export class CoreWindow { */ static async open(url: string, name?: string, options?: CoreWindowOpenOptions): Promise { if (CoreUrlUtils.instance.isLocalFileUrl(url)) { + const filename = url.substr(url.lastIndexOf('/') + 1); + + if (!CoreFileHelper.instance.isOpenableInApp({ filename })) { + try { + await CoreFileHelper.instance.showConfirmOpenUnsupportedFile(); + } catch (error) { + return; // Cancelled, stop. + } + } + await CoreUtils.instance.openFile(url); } else { let treated: boolean;