commit
3f68944a66
|
@ -40,6 +40,7 @@ import { CoreNavigator } from '@services/navigator';
|
||||||
import { AddonCalendarFilter } from './calendar-helper';
|
import { AddonCalendarFilter } from './calendar-helper';
|
||||||
import { AddonCalendarSyncEvents, AddonCalendarSyncProvider } from './calendar-sync';
|
import { AddonCalendarSyncEvents, AddonCalendarSyncProvider } from './calendar-sync';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
const ROOT_CACHE_KEY = 'mmaCalendar:';
|
const ROOT_CACHE_KEY = 'mmaCalendar:';
|
||||||
|
|
||||||
|
@ -1218,7 +1219,7 @@ export class AddonCalendarProvider {
|
||||||
*/
|
*/
|
||||||
async getViewUrl(view: string, time?: number, courseId?: string, siteId?: string): Promise<string> {
|
async getViewUrl(view: string, time?: number, courseId?: string, siteId?: string): Promise<string> {
|
||||||
const site = await CoreSites.getSite(siteId);
|
const site = await CoreSites.getSite(siteId);
|
||||||
let url = CoreTextUtils.concatenatePaths(site.getURL(), 'calendar/view.php?view=' + view);
|
let url = CoreText.concatenatePaths(site.getURL(), 'calendar/view.php?view=' + view);
|
||||||
|
|
||||||
if (time) {
|
if (time) {
|
||||||
url += '&time=' + time;
|
url += '&time=' + time;
|
||||||
|
|
|
@ -23,8 +23,8 @@ 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 { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
const ROOT_CACHE_KEY = 'mmaMessageOutputAirnotifier:';
|
const ROOT_CACHE_KEY = 'mmaMessageOutputAirnotifier:';
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ export class AddonMessageOutputAirnotifierProvider {
|
||||||
handler: (data, resolve) => {
|
handler: (data, resolve) => {
|
||||||
resolve(data[0]);
|
resolve(data[0]);
|
||||||
|
|
||||||
const url = CoreTextUtils.concatenatePaths(
|
const url = CoreText.concatenatePaths(
|
||||||
site.getURL(),
|
site.getURL(),
|
||||||
site.isVersionGreaterEqualThan('3.11') ?
|
site.isVersionGreaterEqualThan('3.11') ?
|
||||||
'message/output/airnotifier/checkconfiguration.php' :
|
'message/output/airnotifier/checkconfiguration.php' :
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { CoreSites } from '@services/sites';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreTimeUtils } from '@services/utils/time';
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { AddonModAssignOutcomes, AddonModAssignSavePluginData } from './assign';
|
import { AddonModAssignOutcomes, AddonModAssignSavePluginData } from './assign';
|
||||||
import {
|
import {
|
||||||
AddonModAssignSubmissionsDBRecord,
|
AddonModAssignSubmissionsDBRecord,
|
||||||
|
@ -236,7 +237,7 @@ export class AddonModAssignOfflineProvider {
|
||||||
const siteFolderPath = CoreFile.getSiteFolder(site.getId());
|
const siteFolderPath = CoreFile.getSiteFolder(site.getId());
|
||||||
const submissionFolderPath = 'offlineassign/' + assignId + '/' + userId;
|
const submissionFolderPath = 'offlineassign/' + assignId + '/' + userId;
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(siteFolderPath, submissionFolderPath);
|
return CoreText.concatenatePaths(siteFolderPath, submissionFolderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -276,7 +277,7 @@ export class AddonModAssignOfflineProvider {
|
||||||
async getSubmissionPluginFolder(assignId: number, pluginName: string, userId?: number, siteId?: string): Promise<string> {
|
async getSubmissionPluginFolder(assignId: number, pluginName: string, userId?: number, siteId?: string): Promise<string> {
|
||||||
const folderPath = await this.getSubmissionFolder(assignId, userId, siteId);
|
const folderPath = await this.getSubmissionFolder(assignId, userId, siteId);
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(folderPath, pluginName);
|
return CoreText.concatenatePaths(folderPath, pluginName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { CoreSites } from '@services/sites';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { AddonModDataAction, AddonModDataEntryWSField } from './data';
|
import { AddonModDataAction, AddonModDataEntryWSField } from './data';
|
||||||
import { AddonModDataEntryDBRecord, DATA_ENTRY_TABLE } from './database/data';
|
import { AddonModDataEntryDBRecord, DATA_ENTRY_TABLE } from './database/data';
|
||||||
|
|
||||||
|
@ -206,7 +207,7 @@ export class AddonModDataOfflineProvider {
|
||||||
const siteFolderPath = CoreFile.getSiteFolder(site.getId());
|
const siteFolderPath = CoreFile.getSiteFolder(site.getId());
|
||||||
const folderPath = 'offlinedatabase/' + dataId;
|
const folderPath = 'offlinedatabase/' + dataId;
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(siteFolderPath, folderPath);
|
return CoreText.concatenatePaths(siteFolderPath, folderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -221,7 +222,7 @@ export class AddonModDataOfflineProvider {
|
||||||
async getEntryFieldFolder(dataId: number, entryId: number, fieldId: number, siteId?: string): Promise<string> {
|
async getEntryFieldFolder(dataId: number, entryId: number, fieldId: number, siteId?: string): Promise<string> {
|
||||||
const folderPath = await this.getDatabaseFolder(dataId, siteId);
|
const folderPath = await this.getDatabaseFolder(dataId, siteId);
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(folderPath, entryId + '_' + fieldId);
|
return CoreText.concatenatePaths(folderPath, entryId + '_' + fieldId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,6 +25,7 @@ import {
|
||||||
DISCUSSIONS_TABLE,
|
DISCUSSIONS_TABLE,
|
||||||
REPLIES_TABLE,
|
REPLIES_TABLE,
|
||||||
} from './database/offline';
|
} from './database/offline';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle offline forum.
|
* Service to handle offline forum.
|
||||||
|
@ -341,7 +342,7 @@ export class AddonModForumOfflineProvider {
|
||||||
const site = await CoreSites.getSite(siteId);
|
const site = await CoreSites.getSite(siteId);
|
||||||
const siteFolderPath = CoreFile.getSiteFolder(site.getId());
|
const siteFolderPath = CoreFile.getSiteFolder(site.getId());
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(siteFolderPath, 'offlineforum/' + forumId);
|
return CoreText.concatenatePaths(siteFolderPath, 'offlineforum/' + forumId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -355,7 +356,7 @@ export class AddonModForumOfflineProvider {
|
||||||
async getNewDiscussionFolder(forumId: number, timeCreated: number, siteId?: string): Promise<string> {
|
async getNewDiscussionFolder(forumId: number, timeCreated: number, siteId?: string): Promise<string> {
|
||||||
const folderPath = await this.getForumFolder(forumId, siteId);
|
const folderPath = await this.getForumFolder(forumId, siteId);
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(folderPath, 'newdisc_' + timeCreated);
|
return CoreText.concatenatePaths(folderPath, 'newdisc_' + timeCreated);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -372,7 +373,7 @@ export class AddonModForumOfflineProvider {
|
||||||
const site = await CoreSites.getSite(siteId);
|
const site = await CoreSites.getSite(siteId);
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(folderPath, 'reply_' + postId + '_' + userId);
|
return CoreText.concatenatePaths(folderPath, 'reply_' + postId + '_' + userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { CoreSites } from '@services/sites';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { AddonModGlossaryOfflineEntryDBRecord, OFFLINE_ENTRIES_TABLE_NAME } from './database/glossary';
|
import { AddonModGlossaryOfflineEntryDBRecord, OFFLINE_ENTRIES_TABLE_NAME } from './database/glossary';
|
||||||
import { AddonModGlossaryDiscardedEntry, AddonModGlossaryEntryOption } from './glossary';
|
import { AddonModGlossaryDiscardedEntry, AddonModGlossaryEntryOption } from './glossary';
|
||||||
|
|
||||||
|
@ -213,7 +214,7 @@ export class AddonModGlossaryOfflineProvider {
|
||||||
const siteFolderPath = CoreFile.getSiteFolder(site.getId());
|
const siteFolderPath = CoreFile.getSiteFolder(site.getId());
|
||||||
const folderPath = 'offlineglossary/' + glossaryId;
|
const folderPath = 'offlineglossary/' + glossaryId;
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(siteFolderPath, folderPath);
|
return CoreText.concatenatePaths(siteFolderPath, folderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -228,7 +229,7 @@ export class AddonModGlossaryOfflineProvider {
|
||||||
async getEntryFolder(glossaryId: number, concept: string, timeCreated: number, siteId?: string): Promise<string> {
|
async getEntryFolder(glossaryId: number, concept: string, timeCreated: number, siteId?: string): Promise<string> {
|
||||||
const folderPath = await this.getGlossaryFolder(glossaryId, siteId);
|
const folderPath = await this.getGlossaryFolder(glossaryId, siteId);
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(folderPath, 'newentry_' + concept + '_' + timeCreated);
|
return CoreText.concatenatePaths(folderPath, 'newentry_' + concept + '_' + timeCreated);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,6 +25,7 @@ import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
|
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
|
||||||
import { makeSingleton, Translate } from '@singletons';
|
import { makeSingleton, Translate } from '@singletons';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
const ROOT_CACHE_KEY = 'mmaModImscp:';
|
const ROOT_CACHE_KEY = 'mmaModImscp:';
|
||||||
|
|
||||||
|
@ -154,7 +155,7 @@ export class AddonModImscpProvider {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = CoreTextUtils.concatenatePaths(item.filepath, item.filename);
|
const filePath = CoreText.concatenatePaths(item.filepath, item.filename);
|
||||||
const filePathAlt = filePath.charAt(0) === '/' ? filePath.substring(1) : '/' + filePath;
|
const filePathAlt = filePath.charAt(0) === '/' ? filePath.substring(1) : '/' + filePath;
|
||||||
|
|
||||||
// Check if it's main file.
|
// Check if it's main file.
|
||||||
|
@ -177,7 +178,7 @@ export class AddonModImscpProvider {
|
||||||
try {
|
try {
|
||||||
const dirPath = await CoreFilepool.getPackageDirUrlByUrl(siteId, module.url || '');
|
const dirPath = await CoreFilepool.getPackageDirUrlByUrl(siteId, module.url || '');
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(dirPath, itemHref);
|
return CoreText.concatenatePaths(dirPath, itemHref);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Error getting directory, there was an error downloading or we're in browser. Return online URL if connected.
|
// Error getting directory, there was an error downloading or we're in browser. Return online URL if connected.
|
||||||
if (CoreApp.isOnline()) {
|
if (CoreApp.isOnline()) {
|
||||||
|
|
|
@ -24,9 +24,9 @@ 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 { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUtilsOpenFileOptions } from '@services/utils/utils';
|
import { CoreUtilsOpenFileOptions } from '@services/utils/utils';
|
||||||
import { makeSingleton, Translate } from '@singletons';
|
import { makeSingleton, Translate } from '@singletons';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { AddonModResource, AddonModResourceProvider } from './resource';
|
import { AddonModResource, AddonModResourceProvider } from './resource';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,7 +77,7 @@ export class AddonModResourceHelperProvider {
|
||||||
const dirPath = await CoreFilepool.getPackageDirUrlByUrl(CoreSites.getCurrentSiteId(), module.url!);
|
const dirPath = await CoreFilepool.getPackageDirUrlByUrl(CoreSites.getCurrentSiteId(), module.url!);
|
||||||
|
|
||||||
// This URL is going to be injected in an iframe, we need trustAsResourceUrl to make it work in a browser.
|
// This URL is going to be injected in an iframe, we need trustAsResourceUrl to make it work in a browser.
|
||||||
return CoreTextUtils.concatenatePaths(dirPath, mainFilePath);
|
return CoreText.concatenatePaths(dirPath, mainFilePath);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Error getting directory, there was an error downloading or we're in browser. Return online URL.
|
// Error getting directory, there was an error downloading or we're in browser. Return online URL.
|
||||||
if (CoreApp.isOnline() && mainFile.fileurl) {
|
if (CoreApp.isOnline() && mainFile.fileurl) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreWS, CoreWSExternalFile, CoreWSExternalWarning, CoreWSFile, CoreWSPreSets } from '@services/ws';
|
import { CoreWS, CoreWSExternalFile, CoreWSExternalWarning, CoreWSFile, CoreWSPreSets } from '@services/ws';
|
||||||
import { makeSingleton, Translate } from '@singletons';
|
import { makeSingleton, Translate } from '@singletons';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { AddonModScormOffline } from './scorm-offline';
|
import { AddonModScormOffline } from './scorm-offline';
|
||||||
import { AddonModScormAutoSyncEventData, AddonModScormSyncProvider } from './scorm-sync';
|
import { AddonModScormAutoSyncEventData, AddonModScormSyncProvider } from './scorm-sync';
|
||||||
|
|
||||||
|
@ -960,7 +961,7 @@ export class AddonModScormProvider {
|
||||||
|
|
||||||
const dirPath = await CoreFilepool.getPackageDirUrlByUrl(siteId, scorm.moduleurl!);
|
const dirPath = await CoreFilepool.getPackageDirUrlByUrl(siteId, scorm.moduleurl!);
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(dirPath, launchUrl);
|
return CoreText.concatenatePaths(dirPath, launchUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -26,10 +26,10 @@ import { CoreGroup, CoreGroups } from '@services/groups';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { Network, Translate, NgZone } from '@singletons';
|
import { Network, Translate, NgZone } from '@singletons';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { Md5 } from 'ts-md5';
|
import { Md5 } from 'ts-md5';
|
||||||
import { AddonModWikiPageDBRecord } from '../../services/database/wiki';
|
import { AddonModWikiPageDBRecord } from '../../services/database/wiki';
|
||||||
|
@ -676,7 +676,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
content = content.trim();
|
content = content.trim();
|
||||||
|
|
||||||
if (content.length > 0) {
|
if (content.length > 0) {
|
||||||
const editUrl = CoreTextUtils.concatenatePaths(CoreSites.getRequiredCurrentSite().getURL(), '/mod/wiki/edit.php');
|
const editUrl = CoreText.concatenatePaths(CoreSites.getRequiredCurrentSite().getURL(), '/mod/wiki/edit.php');
|
||||||
content = content.replace(/href="edit\.php/g, 'href="' + editUrl);
|
content = content.replace(/href="edit\.php/g, 'href="' + editUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreTimeUtils } from '@services/utils/time';
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
import { CoreFormFields } from '@singletons/form';
|
import { CoreFormFields } from '@singletons/form';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import {
|
import {
|
||||||
AddonModWorkshopAssessmentDBRecord,
|
AddonModWorkshopAssessmentDBRecord,
|
||||||
AddonModWorkshopEvaluateAssessmentDBRecord,
|
AddonModWorkshopEvaluateAssessmentDBRecord,
|
||||||
|
@ -629,7 +630,7 @@ export class AddonModWorkshopOfflineProvider {
|
||||||
const siteFolderPath = CoreFile.getSiteFolder(site.getId());
|
const siteFolderPath = CoreFile.getSiteFolder(site.getId());
|
||||||
const workshopFolderPath = 'offlineworkshop/' + workshopId + '/';
|
const workshopFolderPath = 'offlineworkshop/' + workshopId + '/';
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(siteFolderPath, workshopFolderPath);
|
return CoreText.concatenatePaths(siteFolderPath, workshopFolderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -642,7 +643,7 @@ export class AddonModWorkshopOfflineProvider {
|
||||||
async getSubmissionFolder(workshopId: number, siteId?: string): Promise<string> {
|
async getSubmissionFolder(workshopId: number, siteId?: string): Promise<string> {
|
||||||
const folderPath = await this.getWorkshopFolder(workshopId, siteId);
|
const folderPath = await this.getWorkshopFolder(workshopId, siteId);
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(folderPath, 'submission');
|
return CoreText.concatenatePaths(folderPath, 'submission');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -658,7 +659,7 @@ export class AddonModWorkshopOfflineProvider {
|
||||||
|
|
||||||
folderPath += 'assessment/';
|
folderPath += 'assessment/';
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(folderPath, String(assessmentId));
|
return CoreText.concatenatePaths(folderPath, String(assessmentId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ export class AddonRemoteThemesHandlerService implements CoreStyleHandler {
|
||||||
if (style != '') {
|
if (style != '') {
|
||||||
// Treat the CSS.
|
// Treat the CSS.
|
||||||
CoreUtils.ignoreErrors(
|
CoreUtils.ignoreErrors(
|
||||||
CoreFilepool.treatCSSCode(siteId, fileUrl, style, COMPONENT, 1),
|
CoreFilepool.treatCSSCode(siteId, infos.mobilecssurl, style, COMPONENT, 1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -306,13 +306,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
||||||
this.calculateSlides();
|
this.calculateSlides();
|
||||||
});
|
});
|
||||||
|
|
||||||
let selectedTab: T | undefined = this.tabs[this.selectedIndex || 0] || undefined;
|
const selectedTab = this.calculateInitialTab();
|
||||||
|
|
||||||
if (!selectedTab || !selectedTab.enabled) {
|
|
||||||
// The tab is not enabled or not shown. Get the first tab that is enabled.
|
|
||||||
selectedTab = this.tabs.find((tab) => tab.enabled) || undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!selectedTab) {
|
if (!selectedTab) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -329,6 +323,22 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
||||||
this.calculateSlides();
|
this.calculateSlides();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the initial tab to load.
|
||||||
|
*
|
||||||
|
* @return Initial tab, undefined if no valid tab found.
|
||||||
|
*/
|
||||||
|
protected calculateInitialTab(): T | undefined {
|
||||||
|
const selectedTab: T | undefined = this.tabs[this.selectedIndex || 0] || undefined;
|
||||||
|
|
||||||
|
if (selectedTab && selectedTab.enabled) {
|
||||||
|
return selectedTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The tab is not enabled or not shown. Get the first tab that is enabled.
|
||||||
|
return this.tabs.find((tab) => tab.enabled) || undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method executed when the slides are changed.
|
* Method executed when the slides are changed.
|
||||||
*/
|
*/
|
||||||
|
@ -564,8 +574,8 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabToSelect = this.tabs[index];
|
const tabToSelect = this.tabs[index];
|
||||||
if (!tabToSelect || !tabToSelect.enabled || tabToSelect.id == this.selected) {
|
if (!tabToSelect || !tabToSelect.enabled) {
|
||||||
// Already selected or not enabled.
|
// Not enabled.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,17 +588,32 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tabToSelect.id === this.selected) {
|
||||||
|
// Already selected.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const ok = await this.loadTab(tabToSelect);
|
const ok = await this.loadTab(tabToSelect);
|
||||||
|
|
||||||
if (ok !== false) {
|
if (ok !== false) {
|
||||||
this.selectHistory.push(tabToSelect.id!);
|
this.tabSelected(tabToSelect, index);
|
||||||
this.selected = tabToSelect.id;
|
|
||||||
this.selectedIndex = index;
|
|
||||||
|
|
||||||
this.ionChange.emit(tabToSelect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update selected tab.
|
||||||
|
*
|
||||||
|
* @param tab Tab.
|
||||||
|
* @param tabIndex Tab index.
|
||||||
|
*/
|
||||||
|
protected tabSelected(tab: T, tabIndex: number): void {
|
||||||
|
this.selectHistory.push(tab.id ?? '');
|
||||||
|
this.selected = tab.id;
|
||||||
|
this.selectedIndex = tabIndex;
|
||||||
|
|
||||||
|
this.ionChange.emit(tab);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the tab.
|
* Load the tab.
|
||||||
*
|
*
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { CoreTimeUtils } from '@services/utils/time';
|
||||||
import { CoreUtils, CoreUtilsOpenFileOptions, OpenFileAction } from '@services/utils/utils';
|
import { CoreUtils, CoreUtilsOpenFileOptions, OpenFileAction } from '@services/utils/utils';
|
||||||
import { CoreForms } from '@singletons/form';
|
import { CoreForms } from '@singletons/form';
|
||||||
import { CoreApp } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to handle a local file. Only files inside the app folder can be managed.
|
* Component to handle a local file. Only files inside the app folder can be managed.
|
||||||
|
@ -174,7 +175,7 @@ export class CoreLocalFileComponent implements OnInit {
|
||||||
|
|
||||||
const modal = await CoreDomUtils.showModalLoading();
|
const modal = await CoreDomUtils.showModalLoading();
|
||||||
const fileAndDir = CoreFile.getFileAndDirectoryFromPath(this.relativePath!);
|
const fileAndDir = CoreFile.getFileAndDirectoryFromPath(this.relativePath!);
|
||||||
const newPath = CoreTextUtils.concatenatePaths(fileAndDir.directory, newName);
|
const newPath = CoreText.concatenatePaths(fileAndDir.directory, newName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if there's a file with this name.
|
// Check if there's a file with this name.
|
||||||
|
|
|
@ -16,8 +16,8 @@ import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
|
||||||
import { CoreLang } from '@services/lang';
|
import { CoreLang } from '@services/lang';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that allows answering a recaptcha.
|
* Component that allows answering a recaptcha.
|
||||||
|
@ -62,7 +62,7 @@ export class CoreRecaptchaComponent implements OnInit {
|
||||||
// Open the recaptcha challenge in an InAppBrowser.
|
// Open the recaptcha challenge in an InAppBrowser.
|
||||||
// The app used to use an iframe for this, but the app can no longer access the iframe to create the required callbacks.
|
// The app used to use an iframe for this, but the app can no longer access the iframe to create the required callbacks.
|
||||||
// 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 = CoreTextUtils.concatenatePaths(this.siteUrl!, 'webservice/recaptcha.php?lang=' + this.lang);
|
const src = CoreText.concatenatePaths(this.siteUrl!, 'webservice/recaptcha.php?lang=' + this.lang);
|
||||||
|
|
||||||
const inAppBrowserWindow = CoreUtils.openInApp(src);
|
const inAppBrowserWindow = CoreUtils.openInApp(src);
|
||||||
if (!inAppBrowserWindow) {
|
if (!inAppBrowserWindow) {
|
||||||
|
|
|
@ -88,7 +88,7 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent<CoreTabsOutle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View has been initialized.
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
async ngAfterViewInit(): Promise<void> {
|
async ngAfterViewInit(): Promise<void> {
|
||||||
super.ngAfterViewInit();
|
super.ngAfterViewInit();
|
||||||
|
@ -103,12 +103,20 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent<CoreTabsOutle
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search the tab loaded.
|
||||||
|
const tabIndex = this.tabs.findIndex((tab) => tab.page == stackEvent.enteringView.url);
|
||||||
|
const tab = tabIndex >= 0 ? this.tabs[tabIndex] : undefined;
|
||||||
|
|
||||||
// Add tabid to the tab content element.
|
// Add tabid to the tab content element.
|
||||||
if (stackEvent.enteringView.element.id == '') {
|
if (stackEvent.enteringView.element.id == '') {
|
||||||
const tab = this.tabs.find((tab) => tab.page == stackEvent.enteringView.url);
|
|
||||||
stackEvent.enteringView.element.id = tab?.id || '';
|
stackEvent.enteringView.element.id = tab?.id || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tab && this.selected !== tab.id) {
|
||||||
|
// Tab loaded using a navigation, update the selected tab.
|
||||||
|
this.tabSelected(tab, tabIndex);
|
||||||
|
}
|
||||||
|
|
||||||
this.showHideNavBarButtons(stackEvent.enteringView.element.tagName);
|
this.showHideNavBarButtons(stackEvent.enteringView.element.tagName);
|
||||||
|
|
||||||
await this.listenContentScroll(stackEvent.enteringView.element, stackEvent.enteringView.id);
|
await this.listenContentScroll(stackEvent.enteringView.element, stackEvent.enteringView.id);
|
||||||
|
@ -125,7 +133,7 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent<CoreTabsOutle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect changes on input properties.
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
ngOnChanges(changes: Record<string, SimpleChange>): void {
|
ngOnChanges(changes: Record<string, SimpleChange>): void {
|
||||||
if (changes.tabs) {
|
if (changes.tabs) {
|
||||||
|
@ -168,6 +176,21 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent<CoreTabsOutle
|
||||||
this.lastActiveComponent?.ionViewDidLeave?.();
|
this.lastActiveComponent?.ionViewDidLeave?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected calculateInitialTab(): CoreTabsOutletTab | undefined {
|
||||||
|
// Check if a tab should be selected because it was loaded by path.
|
||||||
|
const currentPath = CoreNavigator.getCurrentPath();
|
||||||
|
const currentPathTab = this.tabs.find(tab => tab.page === currentPath);
|
||||||
|
|
||||||
|
if (currentPathTab && currentPathTab.enabled) {
|
||||||
|
return currentPathTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.calculateInitialTab();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get router outlet.
|
* Get router outlet.
|
||||||
*
|
*
|
||||||
|
|
|
@ -44,6 +44,7 @@ import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||||
import { CoreCollapsibleItemDirective } from './collapsible-item';
|
import { CoreCollapsibleItemDirective } from './collapsible-item';
|
||||||
import { CoreCancellablePromise } from '@classes/cancellable-promise';
|
import { CoreCancellablePromise } from '@classes/cancellable-promise';
|
||||||
import { AsyncComponent } from '@classes/async-component';
|
import { AsyncComponent } from '@classes/async-component';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective
|
* Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective
|
||||||
|
@ -689,7 +690,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
||||||
// Check if it's a Vimeo video. If it is, use the wsplayer script instead to make restricted videos work.
|
// Check if it's a Vimeo video. If it is, use the wsplayer script instead to make restricted videos work.
|
||||||
const matches = src.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)([?&]+h=([a-zA-Z0-9]*))?/);
|
const matches = src.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)([?&]+h=([a-zA-Z0-9]*))?/);
|
||||||
if (matches && matches[1]) {
|
if (matches && matches[1]) {
|
||||||
let newUrl = CoreTextUtils.concatenatePaths(site.getURL(), '/media/player/vimeo/wsplayer.php?video=') +
|
let newUrl = CoreText.concatenatePaths(site.getURL(), '/media/player/vimeo/wsplayer.php?video=') +
|
||||||
matches[1] + '&token=' + site.getToken();
|
matches[1] + '&token=' + site.getToken();
|
||||||
|
|
||||||
let privacyHash: string | undefined | null = matches[3];
|
let privacyHash: string | undefined | null = matches[3];
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { CoreContentLinksHelper } from '@features/contentlinks/services/contentl
|
||||||
import { CoreCustomURLSchemes } from '@services/urlschemes';
|
import { CoreCustomURLSchemes } from '@services/urlschemes';
|
||||||
import { DomSanitizer } from '@singletons';
|
import { DomSanitizer } from '@singletons';
|
||||||
import { CoreFilepool } from '@services/filepool';
|
import { CoreFilepool } from '@services/filepool';
|
||||||
|
import { CoreUrl } from '@singletons/url';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directive to open a link in external browser or in the app.
|
* Directive to open a link in external browser or in the app.
|
||||||
|
@ -209,15 +210,8 @@ export class CoreLinkDirective implements OnInit {
|
||||||
|
|
||||||
const currentSite = CoreSites.getRequiredCurrentSite();
|
const currentSite = CoreSites.getRequiredCurrentSite();
|
||||||
|
|
||||||
// Check if URL does not have any protocol, so it's a relative URL.
|
// Make sure it's an absolute URL.
|
||||||
if (!CoreUrlUtils.isAbsoluteURL(href)) {
|
href = CoreUrl.toAbsoluteURL(currentSite.getURL(), href);
|
||||||
// Add the site URL at the begining.
|
|
||||||
if (href.charAt(0) == '/') {
|
|
||||||
href = currentSite.getURL() + href;
|
|
||||||
} else {
|
|
||||||
href = currentSite.getURL() + '/' + href;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentSite.isSitePluginFileUrl(href)) {
|
if (currentSite.isSitePluginFileUrl(href)) {
|
||||||
// It's a site file. Check if it's being downloaded right now.
|
// It's a site file. Check if it's being downloaded right now.
|
||||||
|
|
|
@ -17,7 +17,6 @@ import { ActionSheetButton, IonRefresher } from '@ionic/angular';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import {
|
import {
|
||||||
CoreCourseCustomField,
|
CoreCourseCustomField,
|
||||||
CoreCourseEnrolmentMethod,
|
CoreCourseEnrolmentMethod,
|
||||||
|
@ -38,6 +37,7 @@ import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreCoursesHelper, CoreCourseWithImageAndColor } from '@features/courses/services/courses-helper';
|
import { CoreCoursesHelper, CoreCourseWithImageAndColor } from '@features/courses/services/courses-helper';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { CoreColors } from '@singletons/colors';
|
import { CoreColors } from '@singletons/colors';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that shows the summary of a course including buttons to enrol and other available options.
|
* Page that shows the summary of a course including buttons to enrol and other available options.
|
||||||
|
@ -117,8 +117,8 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentSiteUrl = CoreSites.getRequiredCurrentSite().getURL();
|
const currentSiteUrl = CoreSites.getRequiredCurrentSite().getURL();
|
||||||
this.enrolUrl = CoreTextUtils.concatenatePaths(currentSiteUrl, 'enrol/index.php?id=' + this.courseId);
|
this.enrolUrl = CoreText.concatenatePaths(currentSiteUrl, 'enrol/index.php?id=' + this.courseId);
|
||||||
this.courseUrl = CoreTextUtils.concatenatePaths(currentSiteUrl, 'course/view.php?id=' + this.courseId);
|
this.courseUrl = CoreText.concatenatePaths(currentSiteUrl, 'course/view.php?id=' + this.courseId);
|
||||||
|
|
||||||
await this.getCourse();
|
await this.getCourse();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,13 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreCourse, CoreCourseModuleCompletionStatus, CoreCourseWSSection } from '@features/course/services/course';
|
import { CoreCourse, CoreCourseModuleCompletionStatus, CoreCourseWSSection } from '@features/course/services/course';
|
||||||
import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper';
|
import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
|
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
|
||||||
import { CONTENTS_PAGE_NAME } from '@features/course/course.module';
|
import { CONTENTS_PAGE_NAME } from '@features/course/course.module';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreCourseSummaryPage } from '../course-summary/course-summary';
|
import { CoreCourseSummaryPage } from '../course-summary/course-summary';
|
||||||
import { CoreCoursesHelper, CoreCourseWithImageAndColor } from '@features/courses/services/courses-helper';
|
import { CoreCoursesHelper, CoreCourseWithImageAndColor } from '@features/courses/services/courses-helper';
|
||||||
import { CoreColors } from '@singletons/colors';
|
import { CoreColors } from '@singletons/colors';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the list of courses the user is enrolled in.
|
* Page that displays the list of courses the user is enrolled in.
|
||||||
|
@ -149,7 +149,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentPagePath = CoreNavigator.getCurrentPath();
|
this.currentPagePath = CoreNavigator.getCurrentPath();
|
||||||
this.contentsTab.page = CoreTextUtils.concatenatePaths(this.currentPagePath, this.contentsTab.page);
|
this.contentsTab.page = CoreText.concatenatePaths(this.currentPagePath, this.contentsTab.page);
|
||||||
this.contentsTab.pageParams = {
|
this.contentsTab.pageParams = {
|
||||||
course: this.course,
|
course: this.course,
|
||||||
sectionId: CoreNavigator.getRouteNumberParam('sectionId'),
|
sectionId: CoreNavigator.getRouteNumberParam('sectionId'),
|
||||||
|
@ -207,7 +207,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
// Create the full path.
|
// Create the full path.
|
||||||
handlers.forEach((handler, index) => {
|
handlers.forEach((handler, index) => {
|
||||||
handler.data.page = CoreTextUtils.concatenatePaths(this.currentPagePath, handler.data.page);
|
handler.data.page = CoreText.concatenatePaths(this.currentPagePath, handler.data.page);
|
||||||
handler.data.pageParams = handler.data.pageParams || {};
|
handler.data.pageParams = handler.data.pageParams || {};
|
||||||
|
|
||||||
// Check if this handler should be the first selected tab.
|
// Check if this handler should be the first selected tab.
|
||||||
|
|
|
@ -1266,6 +1266,13 @@ export class CoreCourseProvider {
|
||||||
course: CoreCourseAnyCourseData | { id: number },
|
course: CoreCourseAnyCourseData | { id: number },
|
||||||
navOptions?: CoreNavigationOptions,
|
navOptions?: CoreNavigationOptions,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
if (course.id === CoreSites.getCurrentSite()?.getSiteHomeId()) {
|
||||||
|
// Open site home.
|
||||||
|
await CoreNavigator.navigate('/main/home/site', navOptions);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const loading = await CoreDomUtils.showModalLoading();
|
const loading = await CoreDomUtils.showModalLoading();
|
||||||
|
|
||||||
// Wait for site plugins to be fetched.
|
// Wait for site plugins to be fetched.
|
||||||
|
|
|
@ -12,35 +12,53 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { NgModule } from '@angular/core';
|
import { Injector, NgModule } from '@angular/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, ROUTES, Routes } from '@angular/router';
|
||||||
|
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
|
||||||
|
import { CoreCoursesMyCoursesMainMenuHandlerService } from './services/handlers/my-courses-mainmenu';
|
||||||
|
|
||||||
const routes: Routes = [
|
function buildRoutes(injector: Injector): Routes {
|
||||||
{
|
return [
|
||||||
path: '',
|
{
|
||||||
redirectTo: 'list',
|
path: 'my',
|
||||||
pathMatch: 'full',
|
data: {
|
||||||
},
|
mainMenuTabRoot: CoreCoursesMyCoursesMainMenuHandlerService.PAGE_NAME,
|
||||||
{
|
},
|
||||||
path: 'categories',
|
loadChildren: () => import('./pages/my/my.module').then(m => m.CoreCoursesMyCoursesPageModule),
|
||||||
redirectTo: 'categories/root', // Fake "id".
|
},
|
||||||
pathMatch: 'full',
|
{
|
||||||
},
|
path: 'categories',
|
||||||
{
|
redirectTo: 'categories/root', // Fake "id".
|
||||||
path: 'categories/:id',
|
pathMatch: 'full',
|
||||||
loadChildren: () =>
|
},
|
||||||
import('./pages/categories/categories.module')
|
{
|
||||||
.then(m => m.CoreCoursesCategoriesPageModule),
|
path: 'categories/:id',
|
||||||
},
|
loadChildren: () =>
|
||||||
{
|
import('./pages/categories/categories.module')
|
||||||
path: 'list',
|
.then(m => m.CoreCoursesCategoriesPageModule),
|
||||||
loadChildren: () =>
|
},
|
||||||
import('./pages/list/list.module')
|
{
|
||||||
.then(m => m.CoreCoursesListPageModule),
|
path: 'list',
|
||||||
},
|
loadChildren: () =>
|
||||||
];
|
import('./pages/list/list.module')
|
||||||
|
.then(m => m.CoreCoursesListPageModule),
|
||||||
|
},
|
||||||
|
...buildTabMainRoutes(injector, {
|
||||||
|
redirectTo: 'my',
|
||||||
|
pathMatch: 'full',
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
exports: [RouterModule],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ROUTES,
|
||||||
|
multi: true,
|
||||||
|
deps: [Injector],
|
||||||
|
useFactory: buildRoutes,
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class CoreCoursesLazyModule {}
|
export class CoreCoursesLazyModule {}
|
||||||
|
|
|
@ -50,17 +50,10 @@ const mainMenuHomeChildrenRoutes: Routes = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const mainMenuHomeSiblingRoutes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
|
||||||
path: 'courses',
|
|
||||||
loadChildren: () => import('./courses-lazy.module').then(m => m.CoreCoursesLazyModule),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const mainMenuTabRoutes: Routes = [
|
|
||||||
{
|
{
|
||||||
path: CoreCoursesMyCoursesMainMenuHandlerService.PAGE_NAME,
|
path: CoreCoursesMyCoursesMainMenuHandlerService.PAGE_NAME,
|
||||||
loadChildren: () => import('./pages/my/my.module').then(m => m.CoreCoursesMyCoursesPageModule),
|
loadChildren: () => import('./courses-lazy.module').then(m => m.CoreCoursesLazyModule),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -68,10 +61,9 @@ const mainMenuTabRoutes: Routes = [
|
||||||
imports: [
|
imports: [
|
||||||
CoreMainMenuHomeRoutingModule.forChild({
|
CoreMainMenuHomeRoutingModule.forChild({
|
||||||
children: mainMenuHomeChildrenRoutes,
|
children: mainMenuHomeChildrenRoutes,
|
||||||
siblings: mainMenuHomeSiblingRoutes,
|
|
||||||
}),
|
}),
|
||||||
CoreMainMenuRoutingModule.forChild({ children: mainMenuTabRoutes }),
|
CoreMainMenuRoutingModule.forChild({ children: routes }),
|
||||||
CoreMainMenuTabRoutingModule.forChild(mainMenuTabRoutes),
|
CoreMainMenuTabRoutingModule.forChild(routes),
|
||||||
],
|
],
|
||||||
exports: [CoreMainMenuRoutingModule],
|
exports: [CoreMainMenuRoutingModule],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
@ -12,53 +12,29 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injector, NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { RouterModule, ROUTES, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
import { CoreSharedModule } from '@/core/shared.module';
|
import { CoreSharedModule } from '@/core/shared.module';
|
||||||
import { CoreBlockComponentsModule } from '@features/block/components/components.module';
|
import { CoreBlockComponentsModule } from '@features/block/components/components.module';
|
||||||
|
|
||||||
import { CoreCoursesMyCoursesPage } from './my';
|
import { CoreCoursesMyCoursesPage } from './my';
|
||||||
import { CoreMainMenuComponentsModule } from '@features/mainmenu/components/components.module';
|
import { CoreMainMenuComponentsModule } from '@features/mainmenu/components/components.module';
|
||||||
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
|
|
||||||
import { CoreCoursesMyCoursesMainMenuHandlerService } from '@features/courses/services/handlers/my-courses-mainmenu';
|
|
||||||
|
|
||||||
function buildRoutes(injector: Injector): Routes {
|
const routes: Routes = [
|
||||||
return [
|
{
|
||||||
{
|
path: '',
|
||||||
path: '',
|
component: CoreCoursesMyCoursesPage,
|
||||||
component: CoreCoursesMyCoursesPage,
|
},
|
||||||
data: {
|
];
|
||||||
mainMenuTabRoot: CoreCoursesMyCoursesMainMenuHandlerService.PAGE_NAME,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'list',
|
|
||||||
loadChildren: () =>
|
|
||||||
import('../list/list.module')
|
|
||||||
.then(m => m.CoreCoursesListPageModule),
|
|
||||||
},
|
|
||||||
...buildTabMainRoutes(injector, {
|
|
||||||
redirectTo: '',
|
|
||||||
pathMatch: 'full',
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
RouterModule.forChild(routes),
|
||||||
CoreSharedModule,
|
CoreSharedModule,
|
||||||
CoreBlockComponentsModule,
|
CoreBlockComponentsModule,
|
||||||
CoreMainMenuComponentsModule,
|
CoreMainMenuComponentsModule,
|
||||||
],
|
],
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: ROUTES,
|
|
||||||
multi: true,
|
|
||||||
deps: [Injector],
|
|
||||||
useFactory: buildRoutes,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
declarations: [
|
declarations: [
|
||||||
CoreCoursesMyCoursesPage,
|
CoreCoursesMyCoursesPage,
|
||||||
],
|
],
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { CoreDashboardHomeHandler } from './dashboard-home';
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class CoreCoursesMyCoursesMainMenuHandlerService implements CoreMainMenuHandler {
|
export class CoreCoursesMyCoursesMainMenuHandlerService implements CoreMainMenuHandler {
|
||||||
|
|
||||||
static readonly PAGE_NAME = 'my';
|
static readonly PAGE_NAME = 'courses';
|
||||||
|
|
||||||
name = 'CoreCoursesMyCourses';
|
name = 'CoreCoursesMyCourses';
|
||||||
priority = 900;
|
priority = 900;
|
||||||
|
|
|
@ -20,9 +20,9 @@ import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifi
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { CoreCourses } from '../courses';
|
import { CoreCourses } from '../courses';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,7 +58,7 @@ export class CoreCoursesRequestPushClickHandlerService implements CorePushNotifi
|
||||||
if (notification.name == 'courserequested') {
|
if (notification.name == 'courserequested') {
|
||||||
// Feature not supported in the app, open in browser.
|
// Feature not supported in the app, open in browser.
|
||||||
const site = await CoreSites.getSite(notification.site);
|
const site = await CoreSites.getSite(notification.site);
|
||||||
const url = CoreTextUtils.concatenatePaths(site.getURL(), 'course/pending.php');
|
const url = CoreText.concatenatePaths(site.getURL(), 'course/pending.php');
|
||||||
|
|
||||||
await site.openInBrowserWithAutoLogin(url);
|
await site.openInBrowserWithAutoLogin(url);
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,12 @@ import { CoreApp } from '@services/app';
|
||||||
import { CoreFile, CoreFileProvider } from '@services/file';
|
import { CoreFile, CoreFileProvider } from '@services/file';
|
||||||
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 { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreTimeUtils } from '@services/utils/time';
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
import { Platform, ModalController, Media, Translate } from '@singletons';
|
import { Platform, ModalController, Media, Translate } from '@singletons';
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError } from '@classes/errors/error';
|
||||||
import { CoreCaptureError } from '@classes/errors/captureerror';
|
import { CoreCaptureError } from '@classes/errors/captureerror';
|
||||||
import { CoreCanceledError } from '@classes/errors/cancelederror';
|
import { CoreCanceledError } from '@classes/errors/cancelederror';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page to capture media in browser, or to capture audio in mobile devices.
|
* Page to capture media in browser, or to capture audio in mobile devices.
|
||||||
|
@ -131,7 +131,7 @@ export class CoreEmulatorCaptureMediaComponent implements OnInit, OnDestroy {
|
||||||
*/
|
*/
|
||||||
protected async initCordovaMediaPlugin(): Promise<void> {
|
protected async initCordovaMediaPlugin(): Promise<void> {
|
||||||
this.filePath = this.getFilePath();
|
this.filePath = this.getFilePath();
|
||||||
let absolutePath = CoreTextUtils.concatenatePaths(CoreFile.getBasePathInstant(), this.filePath);
|
let absolutePath = CoreText.concatenatePaths(CoreFile.getBasePathInstant(), this.filePath);
|
||||||
|
|
||||||
if (Platform.is('ios')) {
|
if (Platform.is('ios')) {
|
||||||
// In iOS we need to remove the file:// part.
|
// In iOS we need to remove the file:// part.
|
||||||
|
@ -534,7 +534,7 @@ export class CoreEmulatorCaptureMediaComponent implements OnInit, OnDestroy {
|
||||||
protected getFilePath(): string {
|
protected getFilePath(): string {
|
||||||
const fileName = this.type + '_' + CoreTimeUtils.readableTimestamp() + '.' + this.extension;
|
const fileName = this.type + '_' + CoreTimeUtils.readableTimestamp() + '.' + this.extension;
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(CoreFileProvider.TMPFOLDER, 'media/' + fileName);
|
return CoreText.concatenatePaths(CoreFileProvider.TMPFOLDER, 'media/' + fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -113,7 +113,10 @@ export class FileTransferObjectMock extends FileTransferObject {
|
||||||
xhr.open('GET', source, true);
|
xhr.open('GET', source, true);
|
||||||
xhr.responseType = 'blob';
|
xhr.responseType = 'blob';
|
||||||
for (const name in headers) {
|
for (const name in headers) {
|
||||||
xhr.setRequestHeader(name, headers[name]);
|
// We can't set the User-Agent in browser.
|
||||||
|
if (name !== 'User-Agent') {
|
||||||
|
xhr.setRequestHeader(name, headers[name]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xhr.onprogress = (ev: ProgressEvent): void => {
|
xhr.onprogress = (ev: ProgressEvent): void => {
|
||||||
|
@ -332,7 +335,7 @@ export class FileTransferObjectMock extends FileTransferObject {
|
||||||
xhr.open(httpMethod || 'POST', url);
|
xhr.open(httpMethod || 'POST', url);
|
||||||
for (const name in headers) {
|
for (const name in headers) {
|
||||||
// Filter "unsafe" headers.
|
// Filter "unsafe" headers.
|
||||||
if (name != 'Connection') {
|
if (name !=='Connection' && name !== 'User-Agent') {
|
||||||
xhr.setRequestHeader(name, headers[name]);
|
xhr.setRequestHeader(name, headers[name]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { File, Entry, DirectoryEntry, FileEntry, IWriteOptions, RemoveResult } from '@ionic-native/file/ngx';
|
import { File, Entry, DirectoryEntry, FileEntry, IWriteOptions, RemoveResult } from '@ionic-native/file/ngx';
|
||||||
|
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement the File Error because the ionic-native plugin doesn't implement it.
|
* Implement the File Error because the ionic-native plugin doesn't implement it.
|
||||||
|
@ -58,7 +58,7 @@ export class FileMock extends File {
|
||||||
* @return Returns a Promise that resolves to true if the directory exists or rejects with an error.
|
* @return Returns a Promise that resolves to true if the directory exists or rejects with an error.
|
||||||
*/
|
*/
|
||||||
async checkDir(path: string, dir: string): Promise<boolean> {
|
async checkDir(path: string, dir: string): Promise<boolean> {
|
||||||
const fullPath = CoreTextUtils.concatenatePaths(path, dir);
|
const fullPath = CoreText.concatenatePaths(path, dir);
|
||||||
|
|
||||||
await this.resolveDirectoryUrl(fullPath);
|
await this.resolveDirectoryUrl(fullPath);
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ export class FileMock extends File {
|
||||||
* @return Returns a Promise that resolves with a boolean or rejects with an error.
|
* @return Returns a Promise that resolves with a boolean or rejects with an error.
|
||||||
*/
|
*/
|
||||||
async checkFile(path: string, file: string): Promise<boolean> {
|
async checkFile(path: string, file: string): Promise<boolean> {
|
||||||
const entry = await this.resolveLocalFilesystemUrl(CoreTextUtils.concatenatePaths(path, file));
|
const entry = await this.resolveLocalFilesystemUrl(CoreText.concatenatePaths(path, file));
|
||||||
|
|
||||||
if (entry.isFile) {
|
if (entry.isFile) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -144,7 +144,7 @@ export class FileMock extends File {
|
||||||
async copyFileOrDir(sourcePath: string, sourceName: string, destPath: string, destName: string): Promise<Entry> {
|
async copyFileOrDir(sourcePath: string, sourceName: string, destPath: string, destName: string): Promise<Entry> {
|
||||||
const destFixed = this.fixPathAndName(destPath, destName);
|
const destFixed = this.fixPathAndName(destPath, destName);
|
||||||
|
|
||||||
const source = await this.resolveLocalFilesystemUrl(CoreTextUtils.concatenatePaths(sourcePath, sourceName));
|
const source = await this.resolveLocalFilesystemUrl(CoreText.concatenatePaths(sourcePath, sourceName));
|
||||||
|
|
||||||
const destParentDir = await this.resolveDirectoryUrl(destFixed.path);
|
const destParentDir = await this.resolveDirectoryUrl(destFixed.path);
|
||||||
|
|
||||||
|
@ -424,7 +424,7 @@ export class FileMock extends File {
|
||||||
async moveFileOrDir(sourcePath: string, sourceName: string, destPath: string, destName: string): Promise<Entry> {
|
async moveFileOrDir(sourcePath: string, sourceName: string, destPath: string, destName: string): Promise<Entry> {
|
||||||
const destFixed = this.fixPathAndName(destPath, destName);
|
const destFixed = this.fixPathAndName(destPath, destName);
|
||||||
|
|
||||||
const source = await this.resolveLocalFilesystemUrl(CoreTextUtils.concatenatePaths(sourcePath, sourceName));
|
const source = await this.resolveLocalFilesystemUrl(CoreText.concatenatePaths(sourcePath, sourceName));
|
||||||
|
|
||||||
const destParentDir = await this.resolveDirectoryUrl(destFixed.path);
|
const destParentDir = await this.resolveDirectoryUrl(destFixed.path);
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ export class FileMock extends File {
|
||||||
*/
|
*/
|
||||||
protected fixPathAndName(path: string, name: string): {path: string; name: string} {
|
protected fixPathAndName(path: string, name: string): {path: string; name: string} {
|
||||||
|
|
||||||
const fullPath = CoreTextUtils.concatenatePaths(path, name);
|
const fullPath = CoreText.concatenatePaths(path, name);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
path: fullPath.substring(0, fullPath.lastIndexOf('/')),
|
path: fullPath.substring(0, fullPath.lastIndexOf('/')),
|
||||||
|
|
|
@ -16,8 +16,7 @@ import { Injectable } from '@angular/core';
|
||||||
import { File } from '@ionic-native/file/ngx';
|
import { File } from '@ionic-native/file/ngx';
|
||||||
import { Zip } from '@ionic-native/zip/ngx';
|
import { Zip } from '@ionic-native/zip/ngx';
|
||||||
import * as JSZip from 'jszip';
|
import * as JSZip from 'jszip';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emulates the Cordova Zip plugin in browser.
|
* Emulates the Cordova Zip plugin in browser.
|
||||||
|
@ -46,7 +45,7 @@ export class ZipMock extends Zip {
|
||||||
await this.file.createDir(destination, folder, true);
|
await this.file.createDir(destination, folder, true);
|
||||||
|
|
||||||
// Folder created, add it to the destination path.
|
// Folder created, add it to the destination path.
|
||||||
destination = CoreTextUtils.concatenatePaths(destination, folder);
|
destination = CoreText.concatenatePaths(destination, folder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +105,7 @@ export class ZipMock extends Zip {
|
||||||
const fileData = await file.async('blob');
|
const fileData = await file.async('blob');
|
||||||
|
|
||||||
// File read and parent folder created, now write the file.
|
// File read and parent folder created, now write the file.
|
||||||
const parentFolder = CoreTextUtils.concatenatePaths(destination, fileDir);
|
const parentFolder = CoreText.concatenatePaths(destination, fileDir);
|
||||||
|
|
||||||
await this.file.writeFile(parentFolder, fileName, fileData, { replace: true });
|
await this.file.writeFile(parentFolder, fileName, fileData, { replace: true });
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import { CoreCaptureError } from '@classes/errors/captureerror';
|
||||||
import { CoreIonLoadingElement } from '@classes/ion-loading';
|
import { CoreIonLoadingElement } from '@classes/ion-loading';
|
||||||
import { CoreWSUploadFileResult } from '@services/ws';
|
import { CoreWSUploadFileResult } from '@services/ws';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper service to upload files.
|
* Helper service to upload files.
|
||||||
|
@ -158,7 +159,7 @@ export class CoreFileUploaderHelperProvider {
|
||||||
// Get unique name for the copy.
|
// Get unique name for the copy.
|
||||||
const newName = await CoreFile.getUniqueNameInFolder(CoreFileProvider.TMPFOLDER, name);
|
const newName = await CoreFile.getUniqueNameInFolder(CoreFileProvider.TMPFOLDER, name);
|
||||||
|
|
||||||
const filePath = CoreTextUtils.concatenatePaths(CoreFileProvider.TMPFOLDER, newName);
|
const filePath = CoreText.concatenatePaths(CoreFileProvider.TMPFOLDER, newName);
|
||||||
|
|
||||||
// Write the data into the file.
|
// Write the data into the file.
|
||||||
fileEntry = await CoreFile.writeFileDataInFile(
|
fileEntry = await CoreFile.writeFileDataInFile(
|
||||||
|
@ -218,7 +219,7 @@ export class CoreFileUploaderHelperProvider {
|
||||||
const newName = await CoreFile.getUniqueNameInFolder(CoreFileProvider.TMPFOLDER, fileName, defaultExt);
|
const newName = await CoreFile.getUniqueNameInFolder(CoreFileProvider.TMPFOLDER, fileName, defaultExt);
|
||||||
|
|
||||||
// Now move or copy the file.
|
// Now move or copy the file.
|
||||||
const destPath = CoreTextUtils.concatenatePaths(CoreFileProvider.TMPFOLDER, newName);
|
const destPath = CoreText.concatenatePaths(CoreFileProvider.TMPFOLDER, newName);
|
||||||
if (shouldDelete) {
|
if (shouldDelete) {
|
||||||
return CoreFile.moveExternalFile(path, destPath);
|
return CoreFile.moveExternalFile(path, destPath);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -23,7 +23,6 @@ import { CoreFile, CoreFileProvider } from '@services/file';
|
||||||
import { CoreFilepool } from '@services/filepool';
|
import { CoreFilepool } from '@services/filepool';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreTimeUtils } from '@services/utils/time';
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreWSFile, CoreWSFileUploadOptions, CoreWSUploadFileResult } from '@services/ws';
|
import { CoreWSFile, CoreWSFileUploadOptions, CoreWSUploadFileResult } from '@services/ws';
|
||||||
|
@ -33,6 +32,7 @@ import { CoreEmulatorCaptureMediaComponent } from '@features/emulator/components
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError } from '@classes/errors/error';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
import { CoreFileEntry, CoreFileHelper } from '@services/file-helper';
|
import { CoreFileEntry, CoreFileHelper } from '@services/file-helper';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File upload options.
|
* File upload options.
|
||||||
|
@ -579,7 +579,7 @@ export class CoreFileUploaderProvider {
|
||||||
} else {
|
} else {
|
||||||
// Local file, copy it.
|
// Local file, copy it.
|
||||||
// Use copy instead of move to prevent having a unstable state if some copies succeed and others don't.
|
// Use copy instead of move to prevent having a unstable state if some copies succeed and others don't.
|
||||||
const destFile = CoreTextUtils.concatenatePaths(folderPath, file.name);
|
const destFile = CoreText.concatenatePaths(folderPath, file.name);
|
||||||
result.offline++;
|
result.offline++;
|
||||||
|
|
||||||
await CoreFile.copyFile(file.toURL(), destFile);
|
await CoreFile.copyFile(file.toURL(), destFile);
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { CoreH5PContentValidator, CoreH5PSemantics } from './content-validator';
|
||||||
import { Translate } from '@singletons';
|
import { Translate } from '@singletons';
|
||||||
import { CoreH5PContentBeingSaved } from './storage';
|
import { CoreH5PContentBeingSaved } from './storage';
|
||||||
import { CoreH5PLibraryAddTo } from './validator';
|
import { CoreH5PLibraryAddTo } from './validator';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equivalent to H5P's H5PCore class.
|
* Equivalent to H5P's H5PCore class.
|
||||||
|
@ -148,7 +149,7 @@ export class CoreH5PCore {
|
||||||
urls.push(libUrl + script);
|
urls.push(libUrl + script);
|
||||||
});
|
});
|
||||||
|
|
||||||
urls.push(CoreTextUtils.concatenatePaths(libUrl, 'moodle/js/h5p_overrides.js'));
|
urls.push(CoreText.concatenatePaths(libUrl, 'moodle/js/h5p_overrides.js'));
|
||||||
|
|
||||||
return urls;
|
return urls;
|
||||||
}
|
}
|
||||||
|
@ -456,7 +457,7 @@ export class CoreH5PCore {
|
||||||
|
|
||||||
// Add URL prefix if not external.
|
// Add URL prefix if not external.
|
||||||
if (asset.path.indexOf('://') == -1 && assetsFolderPath) {
|
if (asset.path.indexOf('://') == -1 && assetsFolderPath) {
|
||||||
url = CoreTextUtils.concatenatePaths(assetsFolderPath, url);
|
url = CoreText.concatenatePaths(assetsFolderPath, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add version if set.
|
// Add version if set.
|
||||||
|
|
|
@ -28,6 +28,7 @@ import {
|
||||||
} from './core';
|
} from './core';
|
||||||
import { CONTENTS_LIBRARIES_TABLE_NAME, CONTENT_TABLE_NAME, CoreH5PLibraryCachedAssetsDBRecord } from '../services/database/h5p';
|
import { CONTENTS_LIBRARIES_TABLE_NAME, CONTENT_TABLE_NAME, CoreH5PLibraryCachedAssetsDBRecord } from '../services/database/h5p';
|
||||||
import { CoreH5PLibraryBeingSaved } from './storage';
|
import { CoreH5PLibraryBeingSaved } from './storage';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equivalent to Moodle's implementation of H5PFileStorage.
|
* Equivalent to Moodle's implementation of H5PFileStorage.
|
||||||
|
@ -60,7 +61,7 @@ export class CoreH5PFileStorage {
|
||||||
|
|
||||||
// Create new file for cached assets.
|
// Create new file for cached assets.
|
||||||
const fileName = key + '.' + (type == 'scripts' ? 'js' : 'css');
|
const fileName = key + '.' + (type == 'scripts' ? 'js' : 'css');
|
||||||
const path = CoreTextUtils.concatenatePaths(cachedAssetsPath, fileName);
|
const path = CoreText.concatenatePaths(cachedAssetsPath, fileName);
|
||||||
|
|
||||||
// Store concatenated content.
|
// Store concatenated content.
|
||||||
const content = await this.concatenateFiles(assets, type);
|
const content = await this.concatenateFiles(assets, type);
|
||||||
|
@ -70,7 +71,7 @@ export class CoreH5PFileStorage {
|
||||||
// Now update the files data.
|
// Now update the files data.
|
||||||
files[type] = [
|
files[type] = [
|
||||||
{
|
{
|
||||||
path: CoreTextUtils.concatenatePaths(CoreH5PFileStorage.CACHED_ASSETS_FOLDER_NAME, fileName),
|
path: CoreText.concatenatePaths(CoreH5PFileStorage.CACHED_ASSETS_FOLDER_NAME, fileName),
|
||||||
version: '',
|
version: '',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -142,7 +143,7 @@ export class CoreH5PFileStorage {
|
||||||
|
|
||||||
fileContent = fileContent.replace(
|
fileContent = fileContent.replace(
|
||||||
new RegExp(CoreTextUtils.escapeForRegex(match), 'g'),
|
new RegExp(CoreTextUtils.escapeForRegex(match), 'g'),
|
||||||
'url("' + CoreTextUtils.concatenatePaths(basePath, url) + '")',
|
'url("' + CoreText.concatenatePaths(basePath, url) + '")',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -170,7 +171,7 @@ export class CoreH5PFileStorage {
|
||||||
const cachedAssetsFolder = this.getCachedAssetsFolderPath(entry.foldername, site.getId());
|
const cachedAssetsFolder = this.getCachedAssetsFolderPath(entry.foldername, site.getId());
|
||||||
|
|
||||||
['js', 'css'].forEach((type) => {
|
['js', 'css'].forEach((type) => {
|
||||||
const path = CoreTextUtils.concatenatePaths(cachedAssetsFolder, entry.hash + '.' + type);
|
const path = CoreText.concatenatePaths(cachedAssetsFolder, entry.hash + '.' + type);
|
||||||
|
|
||||||
promises.push(CoreFile.removeFile(path));
|
promises.push(CoreFile.removeFile(path));
|
||||||
});
|
});
|
||||||
|
@ -282,7 +283,7 @@ export class CoreH5PFileStorage {
|
||||||
protected async getCachedAsset(key: string, extension: string): Promise<CoreH5PDependencyAsset[] | undefined> {
|
protected async getCachedAsset(key: string, extension: string): Promise<CoreH5PDependencyAsset[] | undefined> {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const path = CoreTextUtils.concatenatePaths(CoreH5PFileStorage.CACHED_ASSETS_FOLDER_NAME, key + extension);
|
const path = CoreText.concatenatePaths(CoreH5PFileStorage.CACHED_ASSETS_FOLDER_NAME, key + extension);
|
||||||
|
|
||||||
const size = await CoreFile.getFileSize(path);
|
const size = await CoreFile.getFileSize(path);
|
||||||
|
|
||||||
|
@ -307,7 +308,7 @@ export class CoreH5PFileStorage {
|
||||||
* @return Path.
|
* @return Path.
|
||||||
*/
|
*/
|
||||||
getCachedAssetsFolderPath(folderName: string, siteId: string): string {
|
getCachedAssetsFolderPath(folderName: string, siteId: string): string {
|
||||||
return CoreTextUtils.concatenatePaths(
|
return CoreText.concatenatePaths(
|
||||||
this.getContentFolderPath(folderName, siteId),
|
this.getContentFolderPath(folderName, siteId),
|
||||||
CoreH5PFileStorage.CACHED_ASSETS_FOLDER_NAME,
|
CoreH5PFileStorage.CACHED_ASSETS_FOLDER_NAME,
|
||||||
);
|
);
|
||||||
|
@ -336,7 +337,7 @@ export class CoreH5PFileStorage {
|
||||||
* @return Folder path.
|
* @return Folder path.
|
||||||
*/
|
*/
|
||||||
getContentFolderPath(folderName: string, siteId: string): string {
|
getContentFolderPath(folderName: string, siteId: string): string {
|
||||||
return CoreTextUtils.concatenatePaths(
|
return CoreText.concatenatePaths(
|
||||||
this.getExternalH5PFolderPath(siteId),
|
this.getExternalH5PFolderPath(siteId),
|
||||||
'packages/' + folderName + '/content',
|
'packages/' + folderName + '/content',
|
||||||
);
|
);
|
||||||
|
@ -367,7 +368,7 @@ export class CoreH5PFileStorage {
|
||||||
* @return Folder path.
|
* @return Folder path.
|
||||||
*/
|
*/
|
||||||
getContentIndexPath(folderName: string, siteId: string): string {
|
getContentIndexPath(folderName: string, siteId: string): string {
|
||||||
return CoreTextUtils.concatenatePaths(this.getContentFolderPath(folderName, siteId), 'index.html');
|
return CoreText.concatenatePaths(this.getContentFolderPath(folderName, siteId), 'index.html');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -376,7 +377,7 @@ export class CoreH5PFileStorage {
|
||||||
* @return Folder path.
|
* @return Folder path.
|
||||||
*/
|
*/
|
||||||
getCoreH5PPath(): string {
|
getCoreH5PPath(): string {
|
||||||
return CoreTextUtils.concatenatePaths(CoreFile.getWWWPath(), '/assets/lib/h5p/');
|
return CoreText.concatenatePaths(CoreFile.getWWWPath(), '/assets/lib/h5p/');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -396,7 +397,7 @@ export class CoreH5PFileStorage {
|
||||||
* @return Folder path.
|
* @return Folder path.
|
||||||
*/
|
*/
|
||||||
getExternalH5PFolderPath(siteId: string): string {
|
getExternalH5PFolderPath(siteId: string): string {
|
||||||
return CoreTextUtils.concatenatePaths(CoreFile.getSiteFolder(siteId), 'h5p');
|
return CoreText.concatenatePaths(CoreFile.getSiteFolder(siteId), 'h5p');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -406,7 +407,7 @@ export class CoreH5PFileStorage {
|
||||||
* @return Folder path.
|
* @return Folder path.
|
||||||
*/
|
*/
|
||||||
getLibrariesFolderPath(siteId: string): string {
|
getLibrariesFolderPath(siteId: string): string {
|
||||||
return CoreTextUtils.concatenatePaths(this.getExternalH5PFolderPath(siteId), 'libraries');
|
return CoreText.concatenatePaths(this.getExternalH5PFolderPath(siteId), 'libraries');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -426,7 +427,7 @@ export class CoreH5PFileStorage {
|
||||||
folderName = CoreH5PCore.libraryToString(libraryData, true);
|
folderName = CoreH5PCore.libraryToString(libraryData, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(this.getLibrariesFolderPath(siteId), folderName);
|
return CoreText.concatenatePaths(this.getLibrariesFolderPath(siteId), folderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,11 +17,11 @@ import { FileEntry } from '@ionic-native/file/ngx';
|
||||||
import { CoreFile, CoreFileProvider } from '@services/file';
|
import { CoreFile, CoreFileProvider } from '@services/file';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreH5P } from '../services/h5p';
|
import { CoreH5P } from '../services/h5p';
|
||||||
import { CoreH5PCore, CoreH5PDisplayOptions } from './core';
|
import { CoreH5PCore, CoreH5PDisplayOptions } from './core';
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError } from '@classes/errors/error';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equivalent to Moodle's H5P helper class.
|
* Equivalent to Moodle's H5P helper class.
|
||||||
|
@ -131,13 +131,13 @@ export class CoreH5PHelper {
|
||||||
return {
|
return {
|
||||||
baseUrl: CoreFile.getWWWPath(),
|
baseUrl: CoreFile.getWWWPath(),
|
||||||
url: CoreFile.convertFileSrc(
|
url: CoreFile.convertFileSrc(
|
||||||
CoreTextUtils.concatenatePaths(
|
CoreText.concatenatePaths(
|
||||||
basePath,
|
basePath,
|
||||||
CoreH5P.h5pCore.h5pFS.getExternalH5PFolderPath(site.getId()),
|
CoreH5P.h5pCore.h5pFS.getExternalH5PFolderPath(site.getId()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
urlLibraries: CoreFile.convertFileSrc(
|
urlLibraries: CoreFile.convertFileSrc(
|
||||||
CoreTextUtils.concatenatePaths(
|
CoreText.concatenatePaths(
|
||||||
basePath,
|
basePath,
|
||||||
CoreH5P.h5pCore.h5pFS.getLibrariesFolderPath(site.getId()),
|
CoreH5P.h5pCore.h5pFS.getLibrariesFolderPath(site.getId()),
|
||||||
),
|
),
|
||||||
|
@ -155,7 +155,7 @@ export class CoreH5PHelper {
|
||||||
crossorigin: null,
|
crossorigin: null,
|
||||||
libraryConfig: null,
|
libraryConfig: null,
|
||||||
pluginCacheBuster: '',
|
pluginCacheBuster: '',
|
||||||
libraryUrl: CoreTextUtils.concatenatePaths(CoreH5P.h5pCore.h5pFS.getCoreH5PPath(), 'js'),
|
libraryUrl: CoreText.concatenatePaths(CoreH5P.h5pCore.h5pFS.getCoreH5PPath(), 'js'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ export class CoreH5PHelper {
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|
||||||
const folderName = CoreMimetypeUtils.removeExtension(file.name);
|
const folderName = CoreMimetypeUtils.removeExtension(file.name);
|
||||||
const destFolder = CoreTextUtils.concatenatePaths(CoreFileProvider.TMPFOLDER, 'h5p/' + folderName);
|
const destFolder = CoreText.concatenatePaths(CoreFileProvider.TMPFOLDER, 'h5p/' + folderName);
|
||||||
|
|
||||||
// Unzip the file.
|
// Unzip the file.
|
||||||
await CoreFile.unzipFile(file.toURL(), destFolder, onProgress);
|
await CoreFile.unzipFile(file.toURL(), destFolder, onProgress);
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
import { CoreFile } from '@services/file';
|
import { CoreFile } from '@services/file';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUrlUtils } from '@services/utils/url';
|
import { CoreUrlUtils } from '@services/utils/url';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreXAPI } from '@features/xapi/services/xapi';
|
import { CoreXAPI } from '@features/xapi/services/xapi';
|
||||||
|
@ -22,6 +21,7 @@ import { CoreH5P } from '../services/h5p';
|
||||||
import { CoreH5PCore, CoreH5PDisplayOptions, CoreH5PContentData, CoreH5PDependenciesFiles } from './core';
|
import { CoreH5PCore, CoreH5PDisplayOptions, CoreH5PContentData, CoreH5PDependenciesFiles } from './core';
|
||||||
import { CoreH5PCoreSettings, CoreH5PHelper } from './helper';
|
import { CoreH5PCoreSettings, CoreH5PHelper } from './helper';
|
||||||
import { CoreH5PStorage } from './storage';
|
import { CoreH5PStorage } from './storage';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equivalent to Moodle's H5P player class.
|
* Equivalent to Moodle's H5P player class.
|
||||||
|
@ -51,7 +51,7 @@ export class CoreH5PPlayer {
|
||||||
params.component = component;
|
params.component = component;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CoreUrlUtils.addParamsToUrl(CoreTextUtils.concatenatePaths(siteUrl, '/h5p/embed.php'), params);
|
return CoreUrlUtils.addParamsToUrl(CoreText.concatenatePaths(siteUrl, '/h5p/embed.php'), params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +78,7 @@ export class CoreH5PPlayer {
|
||||||
const contentId = this.getContentId(id);
|
const contentId = this.getContentId(id);
|
||||||
const basePath = CoreFile.getBasePathInstant();
|
const basePath = CoreFile.getBasePathInstant();
|
||||||
const contentUrl = CoreFile.convertFileSrc(
|
const contentUrl = CoreFile.convertFileSrc(
|
||||||
CoreTextUtils.concatenatePaths(
|
CoreText.concatenatePaths(
|
||||||
basePath,
|
basePath,
|
||||||
this.h5pCore.h5pFS.getContentFolderPath(content.folderName, site.getId()),
|
this.h5pCore.h5pFS.getContentFolderPath(content.folderName, site.getId()),
|
||||||
),
|
),
|
||||||
|
@ -122,7 +122,7 @@ export class CoreH5PPlayer {
|
||||||
JSON.stringify(result.settings).replace(/\//g, '\\/') + '</script>';
|
JSON.stringify(result.settings).replace(/\//g, '\\/') + '</script>';
|
||||||
|
|
||||||
// Add our own script to handle the params.
|
// Add our own script to handle the params.
|
||||||
html += '<script type="text/javascript" src="' + CoreTextUtils.concatenatePaths(
|
html += '<script type="text/javascript" src="' + CoreText.concatenatePaths(
|
||||||
this.h5pCore.h5pFS.getCoreH5PPath(),
|
this.h5pCore.h5pFS.getCoreH5PPath(),
|
||||||
'moodle/js/params.js',
|
'moodle/js/params.js',
|
||||||
) + '"></script>';
|
) + '"></script>';
|
||||||
|
@ -132,7 +132,7 @@ export class CoreH5PPlayer {
|
||||||
// Include the required JS at the beginning of the body, like Moodle web does.
|
// Include the required JS at the beginning of the body, like Moodle web does.
|
||||||
// Load the embed.js to allow communication with the parent window.
|
// Load the embed.js to allow communication with the parent window.
|
||||||
html += '<script type="text/javascript" src="' +
|
html += '<script type="text/javascript" src="' +
|
||||||
CoreTextUtils.concatenatePaths(this.h5pCore.h5pFS.getCoreH5PPath(), 'moodle/js/embed.js') + '"></script>';
|
CoreText.concatenatePaths(this.h5pCore.h5pFS.getCoreH5PPath(), 'moodle/js/embed.js') + '"></script>';
|
||||||
|
|
||||||
result.jsRequires.forEach((jsUrl) => {
|
result.jsRequires.forEach((jsUrl) => {
|
||||||
html += '<script type="text/javascript" src="' + jsUrl + '"></script>';
|
html += '<script type="text/javascript" src="' + jsUrl + '"></script>';
|
||||||
|
@ -364,7 +364,7 @@ export class CoreH5PPlayer {
|
||||||
* @return The embed URL.
|
* @return The embed URL.
|
||||||
*/
|
*/
|
||||||
protected getEmbedUrl(siteUrl: string, h5pUrl: string): string {
|
protected getEmbedUrl(siteUrl: string, h5pUrl: string): string {
|
||||||
return CoreTextUtils.concatenatePaths(siteUrl, '/h5p/embed.php') + '?url=' + h5pUrl;
|
return CoreText.concatenatePaths(siteUrl, '/h5p/embed.php') + '?url=' + h5pUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -382,7 +382,7 @@ export class CoreH5PPlayer {
|
||||||
* @return URL.
|
* @return URL.
|
||||||
*/
|
*/
|
||||||
getResizerScriptUrl(): string {
|
getResizerScriptUrl(): string {
|
||||||
return CoreTextUtils.concatenatePaths(this.h5pCore.h5pFS.getCoreH5PPath(), 'js/h5p-resizer.js');
|
return CoreText.concatenatePaths(this.h5pCore.h5pFS.getCoreH5PPath(), 'js/h5p-resizer.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
import { CoreFile, CoreFileProvider } from '@services/file';
|
import { CoreFile, CoreFileProvider } from '@services/file';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { CoreH5PCore, CoreH5PLibraryBasicData } from './core';
|
import { CoreH5PCore, CoreH5PLibraryBasicData } from './core';
|
||||||
import { CoreH5PFramework } from './framework';
|
import { CoreH5PFramework } from './framework';
|
||||||
import { CoreH5PMetadata } from './metadata';
|
import { CoreH5PMetadata } from './metadata';
|
||||||
|
@ -199,8 +199,8 @@ export class CoreH5PStorage {
|
||||||
await this.h5pCore.saveContent(content, folderName, fileUrl, siteId);
|
await this.h5pCore.saveContent(content, folderName, fileUrl, siteId);
|
||||||
|
|
||||||
// Save the content files in their right place in FS.
|
// Save the content files in their right place in FS.
|
||||||
const destFolder = CoreTextUtils.concatenatePaths(CoreFileProvider.TMPFOLDER, 'h5p/' + folderName);
|
const destFolder = CoreText.concatenatePaths(CoreFileProvider.TMPFOLDER, 'h5p/' + folderName);
|
||||||
const contentPath = CoreTextUtils.concatenatePaths(destFolder, 'content');
|
const contentPath = CoreText.concatenatePaths(destFolder, 'content');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.h5pCore.h5pFS.saveContent(contentPath, folderName, siteId);
|
await this.h5pCore.h5pFS.saveContent(contentPath, folderName, siteId);
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError } from '@classes/errors/error';
|
||||||
import { FileEntry, DirectoryEntry } from '@ionic-native/file/ngx';
|
import { FileEntry, DirectoryEntry } from '@ionic-native/file/ngx';
|
||||||
import { CoreFile, CoreFileFormat } from '@services/file';
|
import { CoreFile, CoreFileFormat } from '@services/file';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { Translate } from '@singletons';
|
import { Translate } from '@singletons';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { CoreH5PSemantics } from './content-validator';
|
import { CoreH5PSemantics } from './content-validator';
|
||||||
import { CoreH5PCore, CoreH5PLibraryBasicData, CoreH5PMissingLibrary } from './core';
|
import { CoreH5PCore, CoreH5PLibraryBasicData, CoreH5PMissingLibrary } from './core';
|
||||||
import { CoreH5PFramework } from './framework';
|
import { CoreH5PFramework } from './framework';
|
||||||
|
@ -126,7 +126,7 @@ export class CoreH5PValidator {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const libDirPath = CoreTextUtils.concatenatePaths(packagePath, entry.name);
|
const libDirPath = CoreText.concatenatePaths(packagePath, entry.name);
|
||||||
|
|
||||||
const libraryData = await this.getLibraryData(<DirectoryEntry> entry, libDirPath);
|
const libraryData = await this.getLibraryData(<DirectoryEntry> entry, libDirPath);
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ export class CoreH5PValidator {
|
||||||
* @return Promise resolved with boolean: whether the library has an icon file.
|
* @return Promise resolved with boolean: whether the library has an icon file.
|
||||||
*/
|
*/
|
||||||
protected async libraryHasIcon(libPath: string): Promise<boolean> {
|
protected async libraryHasIcon(libPath: string): Promise<boolean> {
|
||||||
const path = CoreTextUtils.concatenatePaths(libPath, 'icon.svg');
|
const path = CoreText.concatenatePaths(libPath, 'icon.svg');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if the file exists.
|
// Check if the file exists.
|
||||||
|
@ -219,7 +219,7 @@ export class CoreH5PValidator {
|
||||||
* @return Promise resolved with the parsed file contents.
|
* @return Promise resolved with the parsed file contents.
|
||||||
*/
|
*/
|
||||||
protected readH5PContentJsonFile(packagePath: string): Promise<unknown> {
|
protected readH5PContentJsonFile(packagePath: string): Promise<unknown> {
|
||||||
const path = CoreTextUtils.concatenatePaths(packagePath, 'content/content.json');
|
const path = CoreText.concatenatePaths(packagePath, 'content/content.json');
|
||||||
|
|
||||||
return CoreFile.readFile(path, CoreFileFormat.FORMATJSON);
|
return CoreFile.readFile(path, CoreFileFormat.FORMATJSON);
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,7 @@ export class CoreH5PValidator {
|
||||||
* @return Promise resolved with the parsed file contents.
|
* @return Promise resolved with the parsed file contents.
|
||||||
*/
|
*/
|
||||||
protected readH5PJsonFile(packagePath: string): Promise<CoreH5PMainJSONData> {
|
protected readH5PJsonFile(packagePath: string): Promise<CoreH5PMainJSONData> {
|
||||||
const path = CoreTextUtils.concatenatePaths(packagePath, 'h5p.json');
|
const path = CoreText.concatenatePaths(packagePath, 'h5p.json');
|
||||||
|
|
||||||
return CoreFile.readFile(path, CoreFileFormat.FORMATJSON);
|
return CoreFile.readFile(path, CoreFileFormat.FORMATJSON);
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ export class CoreH5PValidator {
|
||||||
* @return Promise resolved with the parsed file contents.
|
* @return Promise resolved with the parsed file contents.
|
||||||
*/
|
*/
|
||||||
protected readLibraryJsonFile(libPath: string): Promise<CoreH5PLibraryMainJsonData> {
|
protected readLibraryJsonFile(libPath: string): Promise<CoreH5PLibraryMainJsonData> {
|
||||||
const path = CoreTextUtils.concatenatePaths(libPath, 'library.json');
|
const path = CoreText.concatenatePaths(libPath, 'library.json');
|
||||||
|
|
||||||
return CoreFile.readFile<CoreH5PLibraryMainJsonData>(path, CoreFileFormat.FORMATJSON);
|
return CoreFile.readFile<CoreH5PLibraryMainJsonData>(path, CoreFileFormat.FORMATJSON);
|
||||||
}
|
}
|
||||||
|
@ -256,14 +256,14 @@ export class CoreH5PValidator {
|
||||||
*/
|
*/
|
||||||
protected async readLibraryLanguageFiles(libPath: string): Promise<CoreH5PLibraryLangsJsonData | undefined> {
|
protected async readLibraryLanguageFiles(libPath: string): Promise<CoreH5PLibraryLangsJsonData | undefined> {
|
||||||
try {
|
try {
|
||||||
const path = CoreTextUtils.concatenatePaths(libPath, 'language');
|
const path = CoreText.concatenatePaths(libPath, 'language');
|
||||||
const langIndex: CoreH5PLibraryLangsJsonData = {};
|
const langIndex: CoreH5PLibraryLangsJsonData = {};
|
||||||
|
|
||||||
// Read all the files in the language directory.
|
// Read all the files in the language directory.
|
||||||
const entries = await CoreFile.getDirectoryContents(path);
|
const entries = await CoreFile.getDirectoryContents(path);
|
||||||
|
|
||||||
await Promise.all(entries.map(async (entry) => {
|
await Promise.all(entries.map(async (entry) => {
|
||||||
const langFilePath = CoreTextUtils.concatenatePaths(path, entry.name);
|
const langFilePath = CoreText.concatenatePaths(path, entry.name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const langFileData = await CoreFile.readFile<CoreH5PLibraryLangJsonData>(
|
const langFileData = await CoreFile.readFile<CoreH5PLibraryLangJsonData>(
|
||||||
|
@ -293,7 +293,7 @@ export class CoreH5PValidator {
|
||||||
*/
|
*/
|
||||||
protected async readLibrarySemanticsFile(libPath: string): Promise<CoreH5PSemantics[] | undefined> {
|
protected async readLibrarySemanticsFile(libPath: string): Promise<CoreH5PSemantics[] | undefined> {
|
||||||
try {
|
try {
|
||||||
const path = CoreTextUtils.concatenatePaths(libPath, 'semantics.json');
|
const path = CoreText.concatenatePaths(libPath, 'semantics.json');
|
||||||
|
|
||||||
return await CoreFile.readFile<CoreH5PSemantics[]>(path, CoreFileFormat.FORMATJSON);
|
return await CoreFile.readFile<CoreH5PSemantics[]>(path, CoreFileFormat.FORMATJSON);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreWSExternalWarning, CoreWSExternalFile, CoreWSFile } from '@services/ws';
|
import { CoreWSExternalWarning, CoreWSExternalFile, CoreWSFile } from '@services/ws';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUrlUtils } from '@services/utils/url';
|
import { CoreUrlUtils } from '@services/utils/url';
|
||||||
import { CoreQueueRunner } from '@classes/queue-runner';
|
import { CoreQueueRunner } from '@classes/queue-runner';
|
||||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||||
|
@ -29,6 +28,7 @@ import { CoreH5PValidator } from '../classes/validator';
|
||||||
|
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError } from '@classes/errors/error';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to provide H5P functionalities.
|
* Service to provide H5P functionalities.
|
||||||
|
@ -207,7 +207,7 @@ export class CoreH5PProvider {
|
||||||
* @return Treated url.
|
* @return Treated url.
|
||||||
*/
|
*/
|
||||||
treatH5PUrl(url: string, siteUrl: string): string {
|
treatH5PUrl(url: string, siteUrl: string): string {
|
||||||
if (url.indexOf(CoreTextUtils.concatenatePaths(siteUrl, '/webservice/pluginfile.php')) === 0) {
|
if (url.indexOf(CoreText.concatenatePaths(siteUrl, '/webservice/pluginfile.php')) === 0) {
|
||||||
url = url.replace('/webservice/pluginfile', '/pluginfile');
|
url = url.replace('/webservice/pluginfile', '/pluginfile');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import {
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreForms } from '@singletons/form';
|
import { CoreForms } from '@singletons/form';
|
||||||
import { CoreRecaptchaComponent } from '@components/recaptcha/recaptcha';
|
import { CoreRecaptchaComponent } from '@components/recaptcha/recaptcha';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page to signup using email.
|
* Page to signup using email.
|
||||||
|
@ -161,7 +162,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
|
||||||
try {
|
try {
|
||||||
// Get site config.
|
// Get site config.
|
||||||
this.siteConfig = await CoreSites.getSitePublicConfig(this.siteUrl);
|
this.siteConfig = await CoreSites.getSitePublicConfig(this.siteUrl);
|
||||||
this.signupUrl = CoreTextUtils.concatenatePaths(this.siteConfig.httpswwwroot, 'login/signup.php');
|
this.signupUrl = CoreText.concatenatePaths(this.siteConfig.httpswwwroot, 'login/signup.php');
|
||||||
|
|
||||||
if (this.treatSiteConfig()) {
|
if (this.treatSiteConfig()) {
|
||||||
// Check content verification.
|
// Check content verification.
|
||||||
|
@ -385,7 +386,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
|
||||||
*/
|
*/
|
||||||
showContactOnSite(): void {
|
showContactOnSite(): void {
|
||||||
CoreUtils.openInBrowser(
|
CoreUtils.openInBrowser(
|
||||||
CoreTextUtils.concatenatePaths(this.siteUrl, '/login/verify_age_location.php'),
|
CoreText.concatenatePaths(this.siteUrl, '/login/verify_age_location.php'),
|
||||||
{ showBrowserWarning: false },
|
{ showBrowserWarning: false },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import { CoreNavigator, CoreRedirectPayload } from '@services/navigator';
|
||||||
import { CoreCanceledError } from '@classes/errors/cancelederror';
|
import { CoreCanceledError } from '@classes/errors/cancelederror';
|
||||||
import { CoreCustomURLSchemes } from '@services/urlschemes';
|
import { CoreCustomURLSchemes } from '@services/urlschemes';
|
||||||
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
|
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper provider that provides some common features regarding authentication.
|
* Helper provider that provides some common features regarding authentication.
|
||||||
|
@ -385,8 +386,8 @@ export class CoreLoginHelperProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
const validProviders: CoreSiteIdentityProvider[] = [];
|
const validProviders: CoreSiteIdentityProvider[] = [];
|
||||||
const httpUrl = CoreTextUtils.concatenatePaths(siteConfig.wwwroot, 'auth/oauth2/');
|
const httpUrl = CoreText.concatenatePaths(siteConfig.wwwroot, 'auth/oauth2/');
|
||||||
const httpsUrl = CoreTextUtils.concatenatePaths(siteConfig.httpswwwroot, 'auth/oauth2/');
|
const httpsUrl = CoreText.concatenatePaths(siteConfig.httpswwwroot, 'auth/oauth2/');
|
||||||
|
|
||||||
if (siteConfig.identityproviders && siteConfig.identityproviders.length) {
|
if (siteConfig.identityproviders && siteConfig.identityproviders.length) {
|
||||||
siteConfig.identityproviders.forEach((provider) => {
|
siteConfig.identityproviders.forEach((provider) => {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { CoreTimeUtils } from '@services/utils/time';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreWSExternalFile } from '@services/ws';
|
import { CoreWSExternalFile } from '@services/ws';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import {
|
import {
|
||||||
CoreQuestionAnswerDBRecord,
|
CoreQuestionAnswerDBRecord,
|
||||||
CoreQuestionDBRecord,
|
CoreQuestionDBRecord,
|
||||||
|
@ -331,7 +332,7 @@ export class CoreQuestionProvider {
|
||||||
const siteFolderPath = CoreFile.getSiteFolder(siteId);
|
const siteFolderPath = CoreFile.getSiteFolder(siteId);
|
||||||
const questionFolderPath = 'offlinequestion/' + type + '/' + component + '/' + componentId;
|
const questionFolderPath = 'offlinequestion/' + type + '/' + component + '/' + componentId;
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(siteFolderPath, questionFolderPath);
|
return CoreText.concatenatePaths(siteFolderPath, questionFolderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,8 +20,8 @@ import { Md5 } from 'ts-md5';
|
||||||
import { CoreSharedFiles } from '@features/sharedfiles/services/sharedfiles';
|
import { CoreSharedFiles } from '@features/sharedfiles/services/sharedfiles';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to display the list of shared files, either as a modal or inside a page.
|
* Component to display the list of shared files, either as a modal or inside a page.
|
||||||
|
@ -113,7 +113,7 @@ export class CoreSharedFilesListComponent implements OnInit, OnDestroy {
|
||||||
* @param folder The folder to open.
|
* @param folder The folder to open.
|
||||||
*/
|
*/
|
||||||
openFolder(folder: DirectoryEntry): void {
|
openFolder(folder: DirectoryEntry): void {
|
||||||
const path = CoreTextUtils.concatenatePaths(this.path || '', folder.name);
|
const path = CoreText.concatenatePaths(this.path || '', folder.name);
|
||||||
|
|
||||||
if (this.isModal) {
|
if (this.isModal) {
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
|
|
@ -21,12 +21,12 @@ import { CoreLogger } from '@singletons/logger';
|
||||||
import { CoreApp } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { CoreFile } from '@services/file';
|
import { CoreFile } from '@services/file';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
import { APP_SCHEMA, CoreSharedFilesDBRecord, SHARED_FILES_TABLE_NAME } from './database/sharedfiles';
|
import { APP_SCHEMA, CoreSharedFilesDBRecord, SHARED_FILES_TABLE_NAME } from './database/sharedfiles';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to share files with the app.
|
* Service to share files with the app.
|
||||||
|
@ -157,7 +157,7 @@ export class CoreSharedFilesProvider {
|
||||||
async getSiteSharedFiles(siteId?: string, path?: string, mimetypes?: string[]): Promise<(FileEntry | DirectoryEntry)[]> {
|
async getSiteSharedFiles(siteId?: string, path?: string, mimetypes?: string[]): Promise<(FileEntry | DirectoryEntry)[]> {
|
||||||
let pathToGet = this.getSiteSharedFilesDirPath(siteId);
|
let pathToGet = this.getSiteSharedFilesDirPath(siteId);
|
||||||
if (path) {
|
if (path) {
|
||||||
pathToGet = CoreTextUtils.concatenatePaths(pathToGet, path);
|
pathToGet = CoreText.concatenatePaths(pathToGet, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -240,7 +240,7 @@ export class CoreSharedFilesProvider {
|
||||||
newName = newName || entry.name;
|
newName = newName || entry.name;
|
||||||
|
|
||||||
const sharedFilesFolder = this.getSiteSharedFilesDirPath(siteId);
|
const sharedFilesFolder = this.getSiteSharedFilesDirPath(siteId);
|
||||||
const newPath = CoreTextUtils.concatenatePaths(sharedFilesFolder, newName);
|
const newPath = CoreText.concatenatePaths(sharedFilesFolder, newName);
|
||||||
|
|
||||||
// Create dir if it doesn't exist already.
|
// Create dir if it doesn't exist already.
|
||||||
await CoreFile.createDir(sharedFilesFolder);
|
await CoreFile.createDir(sharedFilesFolder);
|
||||||
|
|
|
@ -32,32 +32,21 @@ export class CoreSiteHomeIndexLinkHandlerService extends CoreContentLinksHandler
|
||||||
pattern = /\/course\/view\.php.*([?&]id=\d+)/;
|
pattern = /\/course\/view\.php.*([?&]id=\d+)/;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of actions for a link (url).
|
* @inheritdoc
|
||||||
*
|
|
||||||
* @param siteIds List of sites the URL belongs to.
|
|
||||||
* @param url The URL to treat.
|
|
||||||
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
|
||||||
* @param courseId Course ID related to the URL. Optional but recommended.
|
|
||||||
* @return List of (or promise resolved with list of) actions.
|
|
||||||
*/
|
*/
|
||||||
getActions(): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
|
getActions(): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
|
||||||
return [{
|
return [{
|
||||||
action: (siteId: string): void => {
|
action: (siteId: string): void => {
|
||||||
// @todo This should open the 'sitehome' setting as well.
|
CoreNavigator.navigateToSitePath('/home/site', {
|
||||||
CoreNavigator.navigateToSiteHome({ siteId });
|
preferCurrentTab: false,
|
||||||
|
siteId,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the handler is enabled for a certain site (site + user) and a URL.
|
* @inheritdoc
|
||||||
* If not defined, defaults to true.
|
|
||||||
*
|
|
||||||
* @param siteId The site ID.
|
|
||||||
* @param url The URL to treat.
|
|
||||||
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
|
||||||
* @param courseId Course ID related to the URL. Optional but recommended.
|
|
||||||
* @return Whether the handler is enabled for the URL and site.
|
|
||||||
*/
|
*/
|
||||||
async isEnabled(siteId: string, url: string, params: Record<string, string>, courseId?: number): Promise<boolean> {
|
async isEnabled(siteId: string, url: string, params: Record<string, string>, courseId?: number): Promise<boolean> {
|
||||||
courseId = parseInt(params.id, 10);
|
courseId = parseInt(params.id, 10);
|
||||||
|
|
|
@ -38,7 +38,6 @@ import { CoreFilepool } from '@services/filepool';
|
||||||
import { CoreLang } from '@services/lang';
|
import { CoreLang } from '@services/lang';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreUrlUtils } from '@services/utils/url';
|
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreWS } from '@services/ws';
|
import { CoreWS } from '@services/ws';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
|
@ -85,6 +84,7 @@ import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/class
|
||||||
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
|
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
|
||||||
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
|
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
|
||||||
import { CoreObject } from '@singletons/object';
|
import { CoreObject } from '@singletons/object';
|
||||||
|
import { CoreUrl } from '@singletons/url';
|
||||||
|
|
||||||
const HANDLER_DISABLED = 'core_site_plugins_helper_handler_disabled';
|
const HANDLER_DISABLED = 'core_site_plugins_helper_handler_disabled';
|
||||||
|
|
||||||
|
@ -164,11 +164,8 @@ export class CoreSitePluginsHelperProvider {
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const site = await CoreSites.getSite(siteId);
|
const site = await CoreSites.getSite(siteId);
|
||||||
|
|
||||||
// Get the absolute URL. If it's a relative URL, add the site URL to it.
|
// Make sure it's an absolute URL.
|
||||||
let url = handlerSchema.styles?.url;
|
let url = handlerSchema.styles?.url ? CoreUrl.toAbsoluteURL(site.getURL(), handlerSchema.styles.url) : undefined;
|
||||||
if (url && !CoreUrlUtils.isAbsoluteURL(url)) {
|
|
||||||
url = CoreTextUtils.concatenatePaths(site.getURL(), url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url && handlerSchema.styles?.version) {
|
if (url && handlerSchema.styles?.version) {
|
||||||
// Add the version to the URL to prevent getting a cached file.
|
// Add the version to the URL to prevent getting a cached file.
|
||||||
|
|
|
@ -16,11 +16,11 @@ import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { CoreApp } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
import { CoreXAPIOffline, CoreXAPIOfflineSaveStatementsOptions } from './offline';
|
import { CoreXAPIOffline, CoreXAPIOfflineSaveStatementsOptions } from './offline';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to provide XAPI functionalities.
|
* Service to provide XAPI functionalities.
|
||||||
|
@ -65,7 +65,7 @@ export class CoreXAPIProvider {
|
||||||
async getUrl(contextId: number, type: string, siteId?: string): Promise<string> {
|
async getUrl(contextId: number, type: string, siteId?: string): Promise<string> {
|
||||||
const site = await CoreSites.getSite(siteId);
|
const site = await CoreSites.getSite(siteId);
|
||||||
|
|
||||||
return CoreTextUtils.concatenatePaths(site.getURL(), `xapi/${type}/${contextId}`);
|
return CoreText.concatenatePaths(site.getURL(), `xapi/${type}/${contextId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -55,11 +55,15 @@ export class CoreRedirectGuard implements CanLoad, CanActivate {
|
||||||
// Redirect to site path.
|
// Redirect to site path.
|
||||||
if (redirect.siteId && redirect.siteId !== CoreConstants.NO_SITE_ID) {
|
if (redirect.siteId && redirect.siteId !== CoreConstants.NO_SITE_ID) {
|
||||||
const redirectData: CoreRedirectPayload = {
|
const redirectData: CoreRedirectPayload = {
|
||||||
redirectPath: redirect.redirectPath,
|
|
||||||
redirectOptions: redirect.redirectOptions,
|
|
||||||
urlToOpen: redirect.urlToOpen,
|
urlToOpen: redirect.urlToOpen,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (redirect.redirectPath !== 'main') {
|
||||||
|
// Only pass redirect path if the page to load isn't the main menu.
|
||||||
|
redirectData.redirectPath = redirect.redirectPath;
|
||||||
|
redirectData.redirectOptions = redirect.redirectOptions;
|
||||||
|
}
|
||||||
|
|
||||||
const loggedIn = await CoreSites.loadSite(
|
const loggedIn = await CoreSites.loadSite(
|
||||||
redirect.siteId,
|
redirect.siteId,
|
||||||
redirectData,
|
redirectData,
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { CoreFormatDatePipe } from './format-date';
|
||||||
import { CoreNoTagsPipe } from './no-tags';
|
import { CoreNoTagsPipe } from './no-tags';
|
||||||
import { CoreSecondsToHMSPipe } from './seconds-to-hms';
|
import { CoreSecondsToHMSPipe } from './seconds-to-hms';
|
||||||
import { CoreTimeAgoPipe } from './time-ago';
|
import { CoreTimeAgoPipe } from './time-ago';
|
||||||
|
import { CoreToLocaleStringPipe } from './to-locale-string';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -33,6 +34,7 @@ import { CoreTimeAgoPipe } from './time-ago';
|
||||||
CoreNoTagsPipe,
|
CoreNoTagsPipe,
|
||||||
CoreSecondsToHMSPipe,
|
CoreSecondsToHMSPipe,
|
||||||
CoreTimeAgoPipe,
|
CoreTimeAgoPipe,
|
||||||
|
CoreToLocaleStringPipe,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
CoreBytesToSizePipe,
|
CoreBytesToSizePipe,
|
||||||
|
@ -43,6 +45,7 @@ import { CoreTimeAgoPipe } from './time-ago';
|
||||||
CoreNoTagsPipe,
|
CoreNoTagsPipe,
|
||||||
CoreSecondsToHMSPipe,
|
CoreSecondsToHMSPipe,
|
||||||
CoreTimeAgoPipe,
|
CoreTimeAgoPipe,
|
||||||
|
CoreToLocaleStringPipe,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class CorePipesModule {}
|
export class CorePipesModule {}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
// (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 { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
|
|
||||||
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter to format a timestamp to a locale string. Timestamp can be in seconds or milliseconds.
|
||||||
|
*
|
||||||
|
* @deprecated since 3.6. Use coreFormatDate instead.
|
||||||
|
* This pipe wasn't removed in app 4.0 because some site plugins still used it. It will be removed in future versions.
|
||||||
|
*/
|
||||||
|
@Pipe({
|
||||||
|
name: 'coreToLocaleString',
|
||||||
|
})
|
||||||
|
export class CoreToLocaleStringPipe implements PipeTransform {
|
||||||
|
|
||||||
|
protected logger: CoreLogger;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.logger = CoreLogger.getInstance('CoreToLocaleStringPipe');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a timestamp to a locale string.
|
||||||
|
*
|
||||||
|
* @param timestamp The timestamp (can be in seconds or milliseconds).
|
||||||
|
* @return Formatted time.
|
||||||
|
*/
|
||||||
|
transform(timestamp: number | string): string {
|
||||||
|
if (typeof timestamp == 'string') {
|
||||||
|
// Convert the value to a number.
|
||||||
|
const numberTimestamp = parseInt(timestamp, 10);
|
||||||
|
if (isNaN(numberTimestamp)) {
|
||||||
|
this.logger.error('Invalid value received', timestamp);
|
||||||
|
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
timestamp = numberTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timestamp < 0) {
|
||||||
|
// Date not valid.
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (timestamp < 100000000000) {
|
||||||
|
// Timestamp is in seconds, convert it to milliseconds.
|
||||||
|
timestamp = timestamp * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CoreTimeUtils.userDate(timestamp, 'core.strftimedatetimeshort');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import { CoreError } from '@classes/errors/error';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
import { makeSingleton, File, Zip, Platform, WebView } from '@singletons';
|
import { makeSingleton, File, Zip, Platform, WebView } from '@singletons';
|
||||||
import { CoreFileEntry } from '@services/file-helper';
|
import { CoreFileEntry } from '@services/file-helper';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Progress event used when writing a file data into a file.
|
* Progress event used when writing a file data into a file.
|
||||||
|
@ -916,7 +917,7 @@ export class CoreFileProvider {
|
||||||
if (path.indexOf(this.basePath) > -1) {
|
if (path.indexOf(this.basePath) > -1) {
|
||||||
return path;
|
return path;
|
||||||
} else {
|
} else {
|
||||||
return CoreTextUtils.concatenatePaths(this.basePath, path);
|
return CoreText.concatenatePaths(this.basePath, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1245,7 +1246,7 @@ export class CoreFileProvider {
|
||||||
*/
|
*/
|
||||||
getWWWAbsolutePath(): string {
|
getWWWAbsolutePath(): string {
|
||||||
if (window.cordova && cordova.file && cordova.file.applicationDirectory) {
|
if (window.cordova && cordova.file && cordova.file.applicationDirectory) {
|
||||||
return CoreTextUtils.concatenatePaths(cordova.file.applicationDirectory, 'www');
|
return CoreText.concatenatePaths(cordova.file.applicationDirectory, 'www');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cannot use Cordova to get it, use the WebView URL.
|
// Cannot use Cordova to get it, use the WebView URL.
|
||||||
|
|
|
@ -52,6 +52,7 @@ import { CoreDatabaseTable } from '@classes/database/database-table';
|
||||||
import { CoreDatabaseCachingStrategy, CoreDatabaseTableProxy } from '@classes/database/database-table-proxy';
|
import { CoreDatabaseCachingStrategy, CoreDatabaseTableProxy } from '@classes/database/database-table-proxy';
|
||||||
import { lazyMap, LazyMap } from '../utils/lazy-map';
|
import { lazyMap, LazyMap } from '../utils/lazy-map';
|
||||||
import { asyncInstance, AsyncInstance } from '../utils/async-instance';
|
import { asyncInstance, AsyncInstance } from '../utils/async-instance';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Factory for handling downloading files and retrieve downloaded files.
|
* Factory for handling downloading files and retrieve downloaded files.
|
||||||
|
@ -811,7 +812,7 @@ export class CoreFilepoolProvider {
|
||||||
if (file.filepath && file.filepath !== '/') {
|
if (file.filepath && file.filepath !== '/') {
|
||||||
path = file.filepath.substring(1) + path;
|
path = file.filepath.substring(1) + path;
|
||||||
}
|
}
|
||||||
path = CoreTextUtils.concatenatePaths(dirPath, path);
|
path = CoreText.concatenatePaths(dirPath, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefetch) {
|
if (prefetch) {
|
||||||
|
@ -905,7 +906,7 @@ export class CoreFilepoolProvider {
|
||||||
if (file.filepath && file.filepath !== '/') {
|
if (file.filepath && file.filepath !== '/') {
|
||||||
path = file.filepath.substring(1) + path;
|
path = file.filepath.substring(1) + path;
|
||||||
}
|
}
|
||||||
path = CoreTextUtils.concatenatePaths(dirPath, path);
|
path = CoreText.concatenatePaths(dirPath, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefetch) {
|
if (prefetch) {
|
||||||
|
@ -2948,7 +2949,7 @@ export class CoreFilepoolProvider {
|
||||||
* and store the result in the CSS file.
|
* and store the result in the CSS file.
|
||||||
*
|
*
|
||||||
* @param siteId Site ID.
|
* @param siteId Site ID.
|
||||||
* @param fileUrl CSS file URL. If a local path is supplied the app will assume it's the path where to write the file.
|
* @param fileUrl CSS file URL. It must be the online URL, not a local path.
|
||||||
* @param cssCode CSS code.
|
* @param cssCode CSS code.
|
||||||
* @param component The component to link the file to.
|
* @param component The component to link the file to.
|
||||||
* @param componentId An ID to use in conjunction with the component.
|
* @param componentId An ID to use in conjunction with the component.
|
||||||
|
@ -2967,19 +2968,24 @@ export class CoreFilepoolProvider {
|
||||||
let updated = false;
|
let updated = false;
|
||||||
|
|
||||||
// Get the path of the CSS file. If it's a local file, assume it's the path where to write the file.
|
// Get the path of the CSS file. If it's a local file, assume it's the path where to write the file.
|
||||||
const filePath = CoreUrlUtils.isLocalFileUrl(fileUrl) ?
|
const filePath = await this.getFilePathByUrl(siteId, fileUrl);
|
||||||
fileUrl :
|
|
||||||
await this.getFilePathByUrl(siteId, fileUrl);
|
|
||||||
|
|
||||||
// Download all files in the CSS.
|
// Download all files in the CSS.
|
||||||
await Promise.all(urls.map(async (url) => {
|
await Promise.all(urls.map(async (url) => {
|
||||||
|
if (!url.trim()) {
|
||||||
|
return; // Ignore empty URLs.
|
||||||
|
}
|
||||||
|
|
||||||
|
const absoluteUrl = CoreUrl.toAbsoluteURL(fileUrl, url);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let fileUrl = url;
|
let fileUrl = absoluteUrl;
|
||||||
if (!CoreUrlUtils.isLocalFileUrl(url)) {
|
|
||||||
|
if (!CoreUrlUtils.isLocalFileUrl(absoluteUrl)) {
|
||||||
// Not a local file, download it.
|
// Not a local file, download it.
|
||||||
fileUrl = await this.downloadUrl(
|
fileUrl = await this.downloadUrl(
|
||||||
siteId,
|
siteId,
|
||||||
url,
|
absoluteUrl,
|
||||||
false,
|
false,
|
||||||
component,
|
component,
|
||||||
componentId,
|
componentId,
|
||||||
|
@ -2994,12 +3000,18 @@ export class CoreFilepoolProvider {
|
||||||
// Convert the URL so it works in mobile devices.
|
// Convert the URL so it works in mobile devices.
|
||||||
fileUrl = CoreFile.convertFileSrc(fileUrl);
|
fileUrl = CoreFile.convertFileSrc(fileUrl);
|
||||||
|
|
||||||
if (fileUrl != url) {
|
if (fileUrl !== url) {
|
||||||
cssCode = cssCode.replace(new RegExp(CoreTextUtils.escapeForRegex(url), 'g'), fileUrl);
|
cssCode = cssCode.replace(new RegExp(CoreTextUtils.escapeForRegex(url), 'g'), fileUrl);
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.warn('Error treating file ', url, error);
|
this.logger.warn('Error treating file ', url, error);
|
||||||
|
|
||||||
|
// If the URL is relative, store the absolute URL.
|
||||||
|
if (absoluteUrl !== url) {
|
||||||
|
cssCode = cssCode.replace(new RegExp(CoreTextUtils.escapeForRegex(url), 'g'), absoluteUrl);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,9 @@ export class CoreNavigatorService {
|
||||||
* @return Whether navigation suceeded.
|
* @return Whether navigation suceeded.
|
||||||
*/
|
*/
|
||||||
async navigateToSiteHome(options: Omit<CoreNavigationOptions, 'reset'> & { siteId?: string } = {}): Promise<boolean> {
|
async navigateToSiteHome(options: Omit<CoreNavigationOptions, 'reset'> & { siteId?: string } = {}): Promise<boolean> {
|
||||||
const landingPagePath = this.getLandingTabPage();
|
const siteId = options.siteId ?? CoreSites.getCurrentSiteId();
|
||||||
|
const landingPagePath = CoreSites.isLoggedIn() && CoreSites.getCurrentSiteId() === siteId ?
|
||||||
|
this.getLandingTabPage() : 'main';
|
||||||
|
|
||||||
return this.navigateToSitePath(landingPagePath, {
|
return this.navigateToSitePath(landingPagePath, {
|
||||||
...options,
|
...options,
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { CoreContentLinksHelper } from '@features/contentlinks/services/contentl
|
||||||
import { CoreLoginHelper, CoreLoginSSOData } from '@features/login/services/login-helper';
|
import { CoreLoginHelper, CoreLoginSSOData } from '@features/login/services/login-helper';
|
||||||
import { ApplicationInit, makeSingleton, Translate } from '@singletons';
|
import { ApplicationInit, makeSingleton, Translate } from '@singletons';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
import { CoreConstants } from '../constants';
|
import { CoreConstants } from '../constants';
|
||||||
import { CoreApp } from './app';
|
import { CoreApp } from './app';
|
||||||
import { CoreNavigator, CoreRedirectPayload } from './navigator';
|
import { CoreNavigator, CoreRedirectPayload } from './navigator';
|
||||||
|
@ -163,7 +164,7 @@ export class CoreCustomURLSchemesProvider {
|
||||||
|
|
||||||
if (data.redirect && !data.redirect.match(/^https?:\/\//)) {
|
if (data.redirect && !data.redirect.match(/^https?:\/\//)) {
|
||||||
// Redirect is a relative URL. Append the site URL.
|
// Redirect is a relative URL. Append the site URL.
|
||||||
data.redirect = CoreTextUtils.concatenatePaths(data.siteUrl, data.redirect);
|
data.redirect = CoreText.concatenatePaths(data.siteUrl, data.redirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
let siteIds = [siteId];
|
let siteIds = [siteId];
|
||||||
|
|
|
@ -21,7 +21,6 @@ import { CoreFile } from '@services/file';
|
||||||
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 { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
|
||||||
import { CoreUrlUtils } from '@services/utils/url';
|
import { CoreUrlUtils } from '@services/utils/url';
|
||||||
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
|
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
|
||||||
|
|
||||||
|
@ -30,6 +29,7 @@ import { CoreLogger } from '@singletons/logger';
|
||||||
import { CoreUrl } from '@singletons/url';
|
import { CoreUrl } from '@singletons/url';
|
||||||
import { CoreWindow } from '@singletons/window';
|
import { CoreWindow } from '@singletons/window';
|
||||||
import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper';
|
import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Possible types of frame elements.
|
* Possible types of frame elements.
|
||||||
|
@ -420,7 +420,7 @@ export class CoreIframeUtilsProvider {
|
||||||
if (src) {
|
if (src) {
|
||||||
const dirAndFile = CoreFile.getFileAndDirectoryFromPath(src);
|
const dirAndFile = CoreFile.getFileAndDirectoryFromPath(src);
|
||||||
if (dirAndFile.directory) {
|
if (dirAndFile.directory) {
|
||||||
url = CoreTextUtils.concatenatePaths(dirAndFile.directory, url);
|
url = CoreText.concatenatePaths(dirAndFile.directory, url);
|
||||||
} else {
|
} else {
|
||||||
this.logger.warn('Cannot get iframe dir path to open relative url', url, element);
|
this.logger.warn('Cannot get iframe dir path to open relative url', url, element);
|
||||||
|
|
||||||
|
@ -560,7 +560,7 @@ export class CoreIframeUtilsProvider {
|
||||||
*/
|
*/
|
||||||
injectiOSScripts(userScriptWindow: WKUserScriptWindow): void {
|
injectiOSScripts(userScriptWindow: WKUserScriptWindow): void {
|
||||||
const wwwPath = CoreFile.getWWWAbsolutePath();
|
const wwwPath = CoreFile.getWWWAbsolutePath();
|
||||||
const linksPath = CoreTextUtils.concatenatePaths(wwwPath, 'assets/js/iframe-treat-links.js');
|
const linksPath = CoreText.concatenatePaths(wwwPath, 'assets/js/iframe-treat-links.js');
|
||||||
|
|
||||||
userScriptWindow.WKUserScript?.addScript({ id: 'CoreIframeUtilsLinksScript', file: linksPath });
|
userScriptWindow.WKUserScript?.addScript({ id: 'CoreIframeUtilsLinksScript', file: linksPath });
|
||||||
|
|
||||||
|
|
|
@ -269,24 +269,10 @@ export class CoreTextUtilsProvider {
|
||||||
* @param leftPath Left path.
|
* @param leftPath Left path.
|
||||||
* @param rightPath Right path.
|
* @param rightPath Right path.
|
||||||
* @return Concatenated path.
|
* @return Concatenated path.
|
||||||
|
* @deprecated since 4.0. Use CoreText instead.
|
||||||
*/
|
*/
|
||||||
concatenatePaths(leftPath: string, rightPath: string): string {
|
concatenatePaths(leftPath: string, rightPath: string): string {
|
||||||
if (!leftPath) {
|
return CoreText.concatenatePaths(leftPath, rightPath);
|
||||||
return rightPath;
|
|
||||||
} else if (!rightPath) {
|
|
||||||
return leftPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastCharLeft = leftPath.slice(-1);
|
|
||||||
const firstCharRight = rightPath.charAt(0);
|
|
||||||
|
|
||||||
if (lastCharLeft === '/' && firstCharRight === '/') {
|
|
||||||
return leftPath + rightPath.substring(1);
|
|
||||||
} else if (lastCharLeft !== '/' && firstCharRight !== '/') {
|
|
||||||
return leftPath + '/' + rightPath;
|
|
||||||
} else {
|
|
||||||
return leftPath + rightPath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -770,7 +756,7 @@ export class CoreTextUtilsProvider {
|
||||||
return { text };
|
return { text };
|
||||||
}
|
}
|
||||||
|
|
||||||
const draftfileUrl = this.concatenatePaths(siteUrl, 'draftfile.php');
|
const draftfileUrl = CoreText.concatenatePaths(siteUrl, 'draftfile.php');
|
||||||
const matches = text.match(new RegExp(this.escapeForRegex(draftfileUrl) + '[^\'" ]+', 'ig'));
|
const matches = text.match(new RegExp(this.escapeForRegex(draftfileUrl) + '[^\'" ]+', 'ig'));
|
||||||
|
|
||||||
if (!matches || !matches.length) {
|
if (!matches || !matches.length) {
|
||||||
|
@ -839,7 +825,7 @@ export class CoreTextUtilsProvider {
|
||||||
return treatedText;
|
return treatedText;
|
||||||
}
|
}
|
||||||
|
|
||||||
const draftfileUrl = this.concatenatePaths(siteUrl, 'draftfile.php');
|
const draftfileUrl = CoreText.concatenatePaths(siteUrl, 'draftfile.php');
|
||||||
const draftfileUrlRegexPrefix = this.escapeForRegex(draftfileUrl) + '/[^/]+/[^/]+/[^/]+/[^/]+/';
|
const draftfileUrlRegexPrefix = this.escapeForRegex(draftfileUrl) + '/[^/]+/[^/]+/[^/]+/[^/]+/';
|
||||||
|
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { makeSingleton } from '@singletons';
|
||||||
import { CoreUrl } from '@singletons/url';
|
import { CoreUrl } from '@singletons/url';
|
||||||
import { CoreApp } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
|
import { CoreText } from '@singletons/text';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "Utils" service with helper functions for URLs.
|
* "Utils" service with helper functions for URLs.
|
||||||
|
@ -118,8 +119,8 @@ export class CoreUrlUtilsProvider {
|
||||||
// Do not use tokenpluginfile if site doesn't use slash params, the URL doesn't work.
|
// Do not use tokenpluginfile if site doesn't use slash params, the URL doesn't work.
|
||||||
// Also, only use it for "core" pluginfile endpoints. Some plugins can implement their own endpoint (like customcert).
|
// Also, only use it for "core" pluginfile endpoints. Some plugins can implement their own endpoint (like customcert).
|
||||||
return !!accessKey && !url.match(/[&?]file=/) && (
|
return !!accessKey && !url.match(/[&?]file=/) && (
|
||||||
url.indexOf(CoreTextUtils.concatenatePaths(siteUrl, 'pluginfile.php')) === 0 ||
|
url.indexOf(CoreText.concatenatePaths(siteUrl, 'pluginfile.php')) === 0 ||
|
||||||
url.indexOf(CoreTextUtils.concatenatePaths(siteUrl, 'webservice/pluginfile.php')) === 0);
|
url.indexOf(CoreText.concatenatePaths(siteUrl, 'webservice/pluginfile.php')) === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -201,7 +202,7 @@ export class CoreUrlUtilsProvider {
|
||||||
url = url.replace(/(\/webservice)?\/pluginfile\.php/, '/tokenpluginfile.php/' + accessKey);
|
url = url.replace(/(\/webservice)?\/pluginfile\.php/, '/tokenpluginfile.php/' + accessKey);
|
||||||
} else {
|
} else {
|
||||||
// Use pluginfile.php. Some webservices returns directly the correct download url, others not.
|
// Use pluginfile.php. Some webservices returns directly the correct download url, others not.
|
||||||
if (url.indexOf(CoreTextUtils.concatenatePaths(siteUrl, 'pluginfile.php')) === 0) {
|
if (url.indexOf(CoreText.concatenatePaths(siteUrl, 'pluginfile.php')) === 0) {
|
||||||
url = url.replace('/pluginfile', '/webservice/pluginfile');
|
url = url.replace('/pluginfile', '/webservice/pluginfile');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -270,7 +270,11 @@ export class CoreWSProvider {
|
||||||
onProgress && transfer.onProgress(onProgress);
|
onProgress && transfer.onProgress(onProgress);
|
||||||
|
|
||||||
// Download the file in the tmp file.
|
// Download the file in the tmp file.
|
||||||
await transfer.download(url, fileEntry.toURL(), true);
|
await transfer.download(url, fileEntry.toURL(), true, {
|
||||||
|
headers: {
|
||||||
|
'User-Agent': navigator.userAgent, // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
let extension = '';
|
let extension = '';
|
||||||
|
|
||||||
|
@ -885,7 +889,9 @@ export class CoreWSProvider {
|
||||||
itemid: options.itemId || 0,
|
itemid: options.itemId || 0,
|
||||||
};
|
};
|
||||||
options.chunkedMode = false;
|
options.chunkedMode = false;
|
||||||
options.headers = {};
|
options.headers = {
|
||||||
|
'User-Agent': navigator.userAgent, // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
|
};
|
||||||
options['Connection'] = 'close';
|
options['Connection'] = 'close';
|
||||||
|
|
||||||
let success: FileUploadResult;
|
let success: FileUploadResult;
|
||||||
|
|
|
@ -56,4 +56,12 @@ describe('CoreUrl singleton', () => {
|
||||||
expect(CoreUrl.sameDomainAndPath('https://school.edu/moodle', 'https://school.edu/moodle/about')).toBe(false);
|
expect(CoreUrl.sameDomainAndPath('https://school.edu/moodle', 'https://school.edu/moodle/about')).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('converts to absolute URLs', () => {
|
||||||
|
expect(CoreUrl.toAbsoluteURL('https://school.edu/foo/bar', 'https://mysite.edu')).toBe('https://mysite.edu');
|
||||||
|
expect(CoreUrl.toAbsoluteURL('https://school.edu/foo/bar', '//mysite.edu')).toBe('https://mysite.edu');
|
||||||
|
expect(CoreUrl.toAbsoluteURL('https://school.edu/foo/bar', '/image.png')).toBe('https://school.edu/image.png');
|
||||||
|
expect(CoreUrl.toAbsoluteURL('https://school.edu/foo/bar', 'image.png')).toBe('https://school.edu/foo/bar/image.png');
|
||||||
|
expect(CoreUrl.toAbsoluteURL('https://school.edu/foo.php', 'image.png')).toBe('https://school.edu/foo.php/image.png');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -40,4 +40,30 @@ export class CoreText {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenate two paths, adding a slash between them if needed.
|
||||||
|
*
|
||||||
|
* @param leftPath Left path.
|
||||||
|
* @param rightPath Right path.
|
||||||
|
* @return Concatenated path.
|
||||||
|
*/
|
||||||
|
static concatenatePaths(leftPath: string, rightPath: string): string {
|
||||||
|
if (!leftPath) {
|
||||||
|
return rightPath;
|
||||||
|
} else if (!rightPath) {
|
||||||
|
return leftPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastCharLeft = leftPath.slice(-1);
|
||||||
|
const firstCharRight = rightPath.charAt(0);
|
||||||
|
|
||||||
|
if (lastCharLeft === '/' && firstCharRight === '/') {
|
||||||
|
return leftPath + rightPath.substring(1);
|
||||||
|
} else if (lastCharLeft !== '/' && firstCharRight !== '/') {
|
||||||
|
return leftPath + '/' + rightPath;
|
||||||
|
} else {
|
||||||
|
return leftPath + rightPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,22 @@ export class CoreUrl {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given some parts of a URL, returns the URL as a string.
|
||||||
|
*
|
||||||
|
* @param parts Parts.
|
||||||
|
* @return Assembled URL.
|
||||||
|
*/
|
||||||
|
static assemble(parts: UrlParts): string {
|
||||||
|
return (parts.protocol ? `${parts.protocol}://` : '') +
|
||||||
|
(parts.credentials ? `${parts.credentials}@` : '') +
|
||||||
|
(parts.domain ?? '') +
|
||||||
|
(parts.port ? `:${parts.port}` : '') +
|
||||||
|
(parts.path ?? '') +
|
||||||
|
(parts.query ? `?${parts.query}` : '') +
|
||||||
|
(parts.fragment ? `#${parts.fragment}` : '');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Guess the Moodle domain from a site url.
|
* Guess the Moodle domain from a site url.
|
||||||
*
|
*
|
||||||
|
@ -231,4 +247,37 @@ export class CoreUrl {
|
||||||
return urlAndAnchor[0];
|
return urlAndAnchor[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a URL to an absolute URL (if it isn't already).
|
||||||
|
*
|
||||||
|
* @param parentUrl The parent URL.
|
||||||
|
* @param url The url to convert.
|
||||||
|
* @return Absolute URL.
|
||||||
|
*/
|
||||||
|
static toAbsoluteURL(parentUrl: string, url: string): string {
|
||||||
|
const parsedUrl = CoreUrl.parse(url);
|
||||||
|
|
||||||
|
if (parsedUrl?.protocol) {
|
||||||
|
return url; // Already absolute URL.
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedParentUrl = CoreUrl.parse(parentUrl);
|
||||||
|
|
||||||
|
if (url.startsWith('//')) {
|
||||||
|
// It only lacks the protocol, add it.
|
||||||
|
return (parsedParentUrl?.protocol || 'https') + ':' + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The URL should be added after the domain (if starts with /) or after the parent path.
|
||||||
|
const treatedParentUrl = CoreUrl.assemble({
|
||||||
|
protocol: parsedParentUrl?.protocol || 'https',
|
||||||
|
domain: parsedParentUrl?.domain,
|
||||||
|
port: parsedParentUrl?.port,
|
||||||
|
credentials: parsedParentUrl?.credentials,
|
||||||
|
path: url.startsWith('/') ? undefined : parsedParentUrl?.path,
|
||||||
|
});
|
||||||
|
|
||||||
|
return CoreText.concatenatePaths(treatedParentUrl, url);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue