diff --git a/config.xml b/config.xml index 6ef8e5cf3..1d98b154e 100644 --- a/config.xml +++ b/config.xml @@ -43,7 +43,6 @@ - diff --git a/src/addon/mod/scorm/providers/scorm.ts b/src/addon/mod/scorm/providers/scorm.ts index a8424dc3f..b02df74fc 100644 --- a/src/addon/mod/scorm/providers/scorm.ts +++ b/src/addon/mod/scorm/providers/scorm.ts @@ -22,6 +22,7 @@ import { CoreSyncProvider } from '@providers/sync'; import { CoreWSProvider } from '@providers/ws'; import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTimeUtilsProvider } from '@providers/utils/time'; +import { CoreUrlUtils } from '@providers/utils/url'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { AddonModScormOfflineProvider } from './scorm-offline'; import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; @@ -1403,7 +1404,7 @@ export class AddonModScormProvider { protected isExternalLink(link: string): boolean { link = link.toLowerCase(); - if (link.match(/https?:\/\//)) { + if (link.match(/^https?:\/\//i) && !CoreUrlUtils.instance.isLocalFileUrl(link)) { return true; } else if (link.substr(0, 4) == 'www.') { return true; diff --git a/src/components/file/file.ts b/src/components/file/file.ts index 22534fe16..5df003e25 100644 --- a/src/components/file/file.ts +++ b/src/components/file/file.ts @@ -162,10 +162,10 @@ export class CoreFileComponent implements OnInit, OnDestroy { // Local file. this.utils.openFile(this.file.toURL()); } else if (this.fileUrl) { - if (this.fileUrl.indexOf('http') === 0) { - this.utils.openOnlineFile(this.urlUtils.unfixPluginfileURL(this.fileUrl)); - } else { + if (this.urlUtils.isLocalFileUrl(this.fileUrl)) { this.utils.openFile(this.fileUrl); + } else { + this.utils.openOnlineFile(this.urlUtils.unfixPluginfileURL(this.fileUrl)); } } diff --git a/src/components/iframe/iframe.ts b/src/components/iframe/iframe.ts index 8f7ce3b49..58e63b551 100644 --- a/src/components/iframe/iframe.ts +++ b/src/components/iframe/iframe.ts @@ -70,7 +70,7 @@ export class CoreIframeComponent implements OnInit, OnChanges { this.allowFullscreen = this.utils.isTrueOrOne(this.allowFullscreen); // Show loading only with external URLs. - this.loading = !this.src || !!this.src.match(/^https?:\/\//i); + this.loading = !this.src || !this.urlUtils.isLocalFileUrl(this.src); const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl; this.iframeUtils.treatFrame(iframe, false, navCtrl); diff --git a/src/config.json b/src/config.json index 0822e6f69..092153a34 100644 --- a/src/config.json +++ b/src/config.json @@ -95,7 +95,7 @@ "enableanalytics": false, "enableonboarding": true, "forceColorScheme": "", - "webviewscheme": "moodleappfs", + "ioswebviewscheme": "moodleappfs", "appstores": { "android": "com.moodle.moodlemobile", "ios": "id633359593", diff --git a/src/core/course/providers/helper.ts b/src/core/course/providers/helper.ts index c94e9752e..606e913b2 100644 --- a/src/core/course/providers/helper.ts +++ b/src/core/course/providers/helper.ts @@ -24,6 +24,7 @@ import { CoreSitesProvider } from '@providers/sites'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTimeUtilsProvider } from '@providers/utils/time'; +import { CoreUrlUtils } from '@providers/utils/url'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay, CoreCourseOptionsMenuHandlerToDisplay } from './options-delegate'; @@ -615,7 +616,8 @@ export class CoreCourseHelperProvider { // File shouldn't be opened in browser. Download the module if it needs to be downloaded. return this.downloadModuleWithMainFileIfNeeded(module, courseId, component, componentId, files, siteId) .then((result) => { - if (result.path.indexOf('http') === 0) { + + if (!CoreUrlUtils.instance.isLocalFileUrl(result.path)) { /* In iOS, if we use the same URL in embedded browser and background download then the download only downloads a few bytes (cached ones). Add a hash to the URL so both URLs are different. */ result.path = result.path + '#moodlemobile-embedded'; diff --git a/src/directives/external-content.ts b/src/directives/external-content.ts index 47b4c776e..a4809cef5 100644 --- a/src/directives/external-content.ts +++ b/src/directives/external-content.ts @@ -214,7 +214,9 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges { } - if (!url || !url.match(/^https?:\/\//i) || (tagName === 'A' && !this.urlUtils.isDownloadableUrl(url))) { + if (!url || !url.match(/^https?:\/\//i) || this.urlUtils.isLocalFileUrl(url) || + (tagName === 'A' && !this.urlUtils.isDownloadableUrl(url))) { + this.logger.debug('Ignoring non-downloadable URL: ' + url); if (tagName === 'SOURCE') { // Restoring original src. @@ -244,7 +246,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges { finalUrl = CoreFile.instance.convertFileSrc(finalUrl); } - if (finalUrl.match(/^https?:\/\//i)) { + if (!this.urlUtils.isLocalFileUrl(finalUrl)) { /* In iOS, if we use the same URL in embedded file and background download then the download only downloads a few bytes (cached ones). Add a hash to the URL so both URLs are different. */ finalUrl = finalUrl + '#moodlemobile-embedded'; @@ -264,7 +266,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges { } // Set events to download big files (not downloaded automatically). - if (finalUrl.indexOf('http') === 0 && targetAttr != 'poster' && + if (!this.urlUtils.isLocalFileUrl(finalUrl) && targetAttr != 'poster' && (tagName == 'VIDEO' || tagName == 'AUDIO' || tagName == 'A' || tagName == 'SOURCE')) { const eventName = tagName == 'A' ? 'click' : 'play'; let clickableEl = this.element; diff --git a/src/providers/file-helper.ts b/src/providers/file-helper.ts index 31a2e6e70..ee3a3111d 100644 --- a/src/providers/file-helper.ts +++ b/src/providers/file-helper.ts @@ -21,6 +21,7 @@ import { CoreFilepoolProvider } from './filepool'; import { CoreSitesProvider } from './sites'; import { CoreWSProvider } from './ws'; import { CoreDomUtilsProvider } from './utils/dom'; +import { CoreUrlUtils } from './utils/url'; import { CoreUtilsProvider } from './utils/utils'; import { CoreConstants } from '@core/constants'; import { FileEntry } from '@ionic-native/file'; @@ -74,7 +75,7 @@ export class CoreFileHelperProvider { return; } - if (url.indexOf('http') === 0) { + if (!CoreUrlUtils.instance.isLocalFileUrl(url)) { /* In iOS, if we use the same URL in embedded browser and background download then the download only downloads a few bytes (cached ones). Add a hash to the URL so both URLs are different. */ url = url + '#moodlemobile-embedded'; diff --git a/src/providers/file.ts b/src/providers/file.ts index 5bc9140e8..06137afa9 100644 --- a/src/providers/file.ts +++ b/src/providers/file.ts @@ -1319,7 +1319,9 @@ export class CoreFileProvider { return src; } - return src.replace(CoreConfigConstants.webviewscheme + '://localhost/_app_file_', 'file://'); + const scheme = this.platform.is('ios') ? CoreConfigConstants.ioswebviewscheme : 'http'; + + return src.replace(scheme + '://localhost/_app_file_', 'file://'); } } diff --git a/src/providers/filepool.ts b/src/providers/filepool.ts index 0f939b65d..e26d4d15b 100644 --- a/src/providers/filepool.ts +++ b/src/providers/filepool.ts @@ -3179,7 +3179,7 @@ export class CoreFilepoolProvider { urls.forEach((url) => { // Download the file only if it's an online URL. - if (url.indexOf('http') == 0) { + if (!this.urlUtils.isLocalFileUrl(url)) { promises.push(this.downloadUrl(siteId, url, false, component, componentId, 0, undefined, undefined, undefined, revision).then((fileUrl) => { diff --git a/src/providers/utils/iframe.ts b/src/providers/utils/iframe.ts index 69c4251f8..df872eb49 100644 --- a/src/providers/utils/iframe.ts +++ b/src/providers/utils/iframe.ts @@ -26,6 +26,7 @@ import { CoreUrlUtilsProvider } from './url'; import { CoreUtilsProvider } from './utils'; import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; import { makeSingleton } from '@singletons/core.singletons'; +import { CoreUrl } from '@singletons/url'; /* * "Utils" service with helper functions for iframes, embed and similar. @@ -54,7 +55,7 @@ export class CoreIframeUtilsProvider { checkOnlineFrameInOffline(element: any, isSubframe?: boolean): boolean { const src = element.src || element.data; - if (src && src.match(/^https?:\/\//i) && !this.appProvider.isOnline()) { + if (src && !this.urlUtils.isLocalFileUrl(src) && !this.appProvider.isOnline()) { if (element.classList.contains('core-iframe-offline-disabled')) { // Iframe already hidden, stop. return true; @@ -347,13 +348,13 @@ export class CoreIframeUtilsProvider { return; } - const scheme = this.urlUtils.getUrlScheme(link.href); - if (!link.href || (scheme && scheme == 'javascript')) { + const urlParts = CoreUrl.parse(link.href); + if (!link.href || (urlParts.protocol && urlParts.protocol == 'javascript')) { // Links with no URL and Javascript links are ignored. return; } - if (!this.urlUtils.isLocalFileUrlScheme(scheme)) { + if (!this.urlUtils.isLocalFileUrlScheme(urlParts.protocol, urlParts.domain)) { // Scheme suggests it's an external resource. event.preventDefault(); diff --git a/src/providers/utils/url.ts b/src/providers/utils/url.ts index 7700b6e18..a335d082e 100644 --- a/src/providers/utils/url.ts +++ b/src/providers/utils/url.ts @@ -17,6 +17,7 @@ import { CoreLangProvider } from '../lang'; import { CoreTextUtilsProvider } from './text'; import { makeSingleton } from '@singletons/core.singletons'; import { CoreConfigConstants } from '../../configconstants'; +import { CoreUrl } from '@singletons/url'; /* * "Utils" service with helper functions for URLs. @@ -432,17 +433,28 @@ export class CoreUrlUtilsProvider { * @return Whether the URL belongs to a local file. */ isLocalFileUrl(url: string): boolean { - return this.isLocalFileUrlScheme(this.getUrlScheme(url)); + const urlParts = CoreUrl.parse(url); + + return this.isLocalFileUrlScheme(urlParts.protocol, urlParts.domain); } /** * Check whether a URL scheme belongs to a local file. * * @param scheme Scheme to check. + * @param domain The domain. Needed because in Android the WebView scheme is http. * @return Whether the scheme belongs to a local file. */ - isLocalFileUrlScheme(scheme: string): boolean { - return scheme == 'cdvfile' || scheme == 'file' || scheme == 'filesystem' || scheme == CoreConfigConstants.webviewscheme; + isLocalFileUrlScheme(scheme: string, domain: string): boolean { + if (scheme) { + scheme = scheme.toLowerCase(); + } + + return scheme == 'cdvfile' || + scheme == 'file' || + scheme == 'filesystem' || + scheme == CoreConfigConstants.ioswebviewscheme || + (scheme == 'http' && domain == 'localhost'); } /**