MOBILE-4616 url: Migrate all CoreUrlUtils to CoreUrl static singleton
parent
5bd549477e
commit
1186694c5f
|
@ -69,8 +69,7 @@ jobs:
|
|||
cat circular-dependencies
|
||||
lines=$(cat circular-dependencies | wc -l)
|
||||
echo "Total circular dependencies: $lines"
|
||||
test $lines -ge 138
|
||||
test $lines -le 148
|
||||
test $lines -eq 135
|
||||
- name: JavaScript code compatibility
|
||||
run: |
|
||||
npx check-es-compat www/*.js --polyfills="\{Array,String,TypedArray\}.prototype.at,Object.hasOwn"
|
||||
|
|
|
@ -454,7 +454,7 @@ class behat_app_helper extends behat_base {
|
|||
$result = $this->zone_js("customUrlSchemes.handleCustomURL('$customurl')");
|
||||
|
||||
if ($result !== 'OK') {
|
||||
throw new DriverException('Error handling url - ' . $result);
|
||||
throw new DriverException('Error handling url - ' . $customurl . ' - '.$result);
|
||||
}
|
||||
if (!empty($successXPath)) {
|
||||
// Wait until the page appears.
|
||||
|
|
|
@ -22,7 +22,7 @@ import { Translate } from '@singletons';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreCourseHelper } from '@features/course/services/course-helper';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
|
||||
/**
|
||||
|
@ -103,7 +103,7 @@ export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent i
|
|||
brandedIcons[mod.modname] = mod.branded;
|
||||
|
||||
// If this is not a theme image, leave it undefined to avoid having specific activity icons.
|
||||
if (CoreUrlUtils.isThemeImageUrl(mod.modicon)) {
|
||||
if (CoreUrl.isThemeImageUrl(mod.modicon)) {
|
||||
modIcons[mod.modname] = mod.modicon;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -26,7 +26,7 @@ import { CoreNavigator } from '@services/navigator';
|
|||
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
|
@ -79,7 +79,7 @@ export class AddonBlogIndexPage implements OnInit, OnDestroy {
|
|||
...this.filter,
|
||||
category: 'blog',
|
||||
},
|
||||
url: CoreUrlUtils.addParamsToUrl('/blog/index.php', {
|
||||
url: CoreUrl.addParamsToUrl('/blog/index.php', {
|
||||
...this.filter,
|
||||
modid: this.filter.cmid,
|
||||
cmid: undefined,
|
||||
|
|
|
@ -50,7 +50,7 @@ import {
|
|||
import { CoreSwipeSlidesDynamicItemsManager } from '@classes/items-management/swipe-slides-dynamic-items-manager';
|
||||
import moment from 'moment-timezone';
|
||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreTime } from '@singletons/time';
|
||||
import { Translate } from '@singletons';
|
||||
|
||||
|
@ -132,7 +132,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
|
|||
...params,
|
||||
category: 'calendar',
|
||||
},
|
||||
url: CoreUrlUtils.addParamsToUrl('/calendar/view.php?view=month', params),
|
||||
url: CoreUrl.addParamsToUrl('/calendar/view.php?view=month', params),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import { AddonCalendarOffline } from '../../services/calendar-offline';
|
|||
import { CoreCategoryData, CoreCourses } from '@features/courses/services/courses';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreTime } from '@singletons/time';
|
||||
import { Translate } from '@singletons';
|
||||
|
||||
|
@ -103,7 +103,7 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, DoCheck, On
|
|||
...params,
|
||||
category: 'calendar',
|
||||
},
|
||||
url: CoreUrlUtils.addParamsToUrl('/calendar/view.php?view=upcoming', params),
|
||||
url: CoreUrl.addParamsToUrl('/calendar/view.php?view=upcoming', params),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ import {
|
|||
import { CoreRoutedItemsManagerSourcesTracker } from '@classes/items-management/routed-items-manager-sources-tracker';
|
||||
import { AddonCalendarEventsSource } from '@addons/calendar/classes/events-source';
|
||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreTime } from '@singletons/time';
|
||||
|
||||
/**
|
||||
|
@ -201,7 +201,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
|||
...params,
|
||||
category: 'calendar',
|
||||
},
|
||||
url: CoreUrlUtils.addParamsToUrl('/calendar/view.php?view=day', params),
|
||||
url: CoreUrl.addParamsToUrl('/calendar/view.php?view=day', params),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import { CoreSite } from '@classes/sites/site';
|
|||
import { CoreNetwork } from '@services/network';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreGroups } from '@services/groups';
|
||||
import { CoreLocalNotifications } from '@services/local-notifications';
|
||||
|
@ -362,14 +362,14 @@ export class AddonCalendarProvider {
|
|||
// Add links to the days if needed.
|
||||
if (dayStart && (!seenDay || !moment(seenDay).isSame(start, 'day'))) {
|
||||
promises.push(this.getViewUrl('day', event.timestart, undefined, siteId).then((url) => {
|
||||
dayStart = CoreUrlUtils.buildLink(url, dayStart);
|
||||
dayStart = CoreUrl.buildLink(url, dayStart);
|
||||
|
||||
return;
|
||||
}));
|
||||
}
|
||||
if (dayEnd && (!seenDay || !moment(seenDay).isSame(end, 'day'))) {
|
||||
promises.push(this.getViewUrl('day', end / 1000, undefined, siteId).then((url) => {
|
||||
dayEnd = CoreUrlUtils.buildLink(url, dayEnd);
|
||||
dayEnd = CoreUrl.buildLink(url, dayEnd);
|
||||
|
||||
return;
|
||||
}));
|
||||
|
@ -398,7 +398,7 @@ export class AddonCalendarProvider {
|
|||
// Add link to view the day.
|
||||
const url = await this.getViewUrl('day', event.timestart, undefined, siteId);
|
||||
|
||||
return CoreUrlUtils.buildLink(url, this.getDayRepresentation(start, useCommonWords)) + ', ' + time;
|
||||
return CoreUrl.buildLink(url, this.getDayRepresentation(start, useCommonWords)) + ', ' + time;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,7 +40,7 @@ import { ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router';
|
|||
import { AddonCompetencyCourseCompetenciesSource } from '@addons/competency/classes/competency-course-competencies-source';
|
||||
import { CoreTime } from '@singletons/time';
|
||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
|
||||
/**
|
||||
* Page that displays the competency information.
|
||||
|
@ -306,7 +306,7 @@ export class AddonCompetencyCompetencyPage implements OnInit, OnDestroy {
|
|||
planstatus: this.planStatus,
|
||||
userid: userId,
|
||||
},
|
||||
url: CoreUrlUtils.addParamsToUrl('/admin/tool/lp/user_competency_in_plan.php', {
|
||||
url: CoreUrl.addParamsToUrl('/admin/tool/lp/user_competency_in_plan.php', {
|
||||
planid: source.PLAN_ID,
|
||||
userid: userId,
|
||||
competencyid: compId,
|
||||
|
@ -328,7 +328,7 @@ export class AddonCompetencyCompetencyPage implements OnInit, OnDestroy {
|
|||
courseid: source.COURSE_ID,
|
||||
userid: userId,
|
||||
},
|
||||
url: CoreUrlUtils.addParamsToUrl('/admin/tool/lp/user_competency_in_course.php', {
|
||||
url: CoreUrl.addParamsToUrl('/admin/tool/lp/user_competency_in_course.php', {
|
||||
courseid: source.COURSE_ID,
|
||||
competencyid: compId,
|
||||
userid: userId,
|
||||
|
|
|
@ -18,7 +18,7 @@ import { COURSE_PAGE_NAME } from '@features/course/constants';
|
|||
import { CorePushNotificationsClickHandler } from '@features/pushnotifications/services/push-delegate';
|
||||
import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifications/services/pushnotifications';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonCompetency } from '../competency';
|
||||
|
@ -49,7 +49,7 @@ export class AddonCompetencyPushClickHandlerService implements CorePushNotificat
|
|||
* @inheritdoc
|
||||
*/
|
||||
async handleClick(notification: AddonCompetencyPushNotificationData): Promise<void> {
|
||||
const contextUrlParams = CoreUrlUtils.extractUrlParams(notification.contexturl);
|
||||
const contextUrlParams = CoreUrl.extractUrlParams(notification.contexturl);
|
||||
|
||||
if (notification.name == 'competencyplancomment') {
|
||||
// Open the learning plan.
|
||||
|
|
|
@ -18,7 +18,7 @@ import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/def
|
|||
import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreH5PPlayerComponent } from '@features/h5p/components/h5p-player/h5p-player';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreH5PHelper } from '@features/h5p/classes/helper';
|
||||
|
||||
/**
|
||||
|
@ -57,7 +57,7 @@ export class AddonFilterDisplayH5PHandlerService extends CoreFilterDefaultHandle
|
|||
|
||||
embeddedH5PIframes.forEach((iframe) => {
|
||||
// Add the preventredirect param to allow authenticating if auto-login fails.
|
||||
iframe.src = CoreUrlUtils.addParamsToUrl(iframe.src, { preventredirect: false });
|
||||
iframe.src = CoreUrl.addParamsToUrl(iframe.src, { preventredirect: false });
|
||||
|
||||
// Add resizer script so the H5P has the right height.
|
||||
CoreH5PHelper.addResizerScript();
|
||||
|
|
|
@ -17,7 +17,7 @@ import { CorePromisedValue } from '@classes/promised-value';
|
|||
import { CoreExternalContentDirective } from '@directives/external-content';
|
||||
import { CoreLang } from '@services/lang';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreEvents } from '@singletons/events';
|
||||
|
@ -107,7 +107,7 @@ export class AddonFilterMediaPluginVideoJSService {
|
|||
|
||||
const dataSetupString = video.getAttribute('data-setup') || video.getAttribute('data-setup-lazy') || '{}';
|
||||
const data = CoreTextUtils.parseJSON<VideoJSOptions>(dataSetupString, {});
|
||||
const youtubeUrl = data.techOrder?.[0] == 'youtube' && CoreUrlUtils.getYoutubeEmbedUrl(data.sources?.[0]?.src);
|
||||
const youtubeUrl = data.techOrder?.[0] == 'youtube' && CoreUrl.getYoutubeEmbedUrl(data.sources?.[0]?.src);
|
||||
|
||||
if (!youtubeUrl) {
|
||||
return;
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreCourseHelper } from '@features/course/services/course-helper';
|
||||
import { CorePushNotificationsClickHandler } from '@features/pushnotifications/services/push-delegate';
|
||||
import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifications/services/pushnotifications';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModAssign } from '../assign';
|
||||
|
@ -50,7 +50,7 @@ export class AddonModAssignPushClickHandlerService implements CorePushNotificati
|
|||
* @returns Promise resolved when done.
|
||||
*/
|
||||
async handleClick(notification: NotificationData): Promise<void> {
|
||||
const contextUrlParams = CoreUrlUtils.extractUrlParams(notification.contexturl);
|
||||
const contextUrlParams = CoreUrl.extractUrlParams(notification.contexturl);
|
||||
const courseId = Number(notification.courseid);
|
||||
const moduleId = Number(contextUrlParams.id);
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ import {
|
|||
AddonModBookTocChapter,
|
||||
} from '../../services/book';
|
||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { ADDON_MOD_BOOK_COMPONENT, AddonModBookNavStyle } from '../../constants';
|
||||
|
||||
/**
|
||||
|
@ -293,7 +293,7 @@ export class AddonModBookContentsPage implements OnInit, OnDestroy {
|
|||
ws: 'mod_book_view_book',
|
||||
name: this.module.name,
|
||||
data: { id: this.module.instance, category: 'book', chapterid: chapterId },
|
||||
url: CoreUrlUtils.addParamsToUrl(`/mod/book/view.php?id=${this.module.id}`, { chapterid: chapterId }),
|
||||
url: CoreUrl.addParamsToUrl(`/mod/book/view.php?id=${this.module.id}`, { chapterid: chapterId }),
|
||||
});
|
||||
|
||||
const currentChapterIndex = this.chapters.findIndex((chapter) => chapter.id == chapterId);
|
||||
|
|
|
@ -18,7 +18,7 @@ import { CoreTagFeedComponent } from '@features/tag/components/feed/feed';
|
|||
import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate';
|
||||
import { CoreTagFeedElement, CoreTagHelper } from '@features/tag/services/tag-helper';
|
||||
import { CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModBook } from '../book';
|
||||
|
||||
|
@ -51,7 +51,7 @@ export class AddonModBookTagAreaHandlerService implements CoreTagAreaHandler {
|
|||
|
||||
// Find module ids of the returned books, they are needed by the link delegate.
|
||||
await Promise.all(items.map(async (item) => {
|
||||
const params = item.url ? CoreUrlUtils.extractUrlParams(item.url) : {};
|
||||
const params = item.url ? CoreUrl.extractUrlParams(item.url) : {};
|
||||
if (params.b && !params.id) {
|
||||
const bookId = parseInt(params.b, 10);
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ import { AddonModDataHelper, AddonModDatDisplayFieldsOptions } from '../../servi
|
|||
import { AddonModDataAutoSyncData, AddonModDataSyncResult } from '../../services/data-sync';
|
||||
import { AddonModDataPrefetchHandler } from '../../services/handlers/prefetch-lazy';
|
||||
import { AddonModDataComponentsCompileModule } from '../components-compile.module';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreTime } from '@singletons/time';
|
||||
import {
|
||||
ADDON_MOD_DATA_AUTO_SYNCED,
|
||||
|
@ -568,7 +568,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
|
||||
this.analyticsLogEvent('mod_data_search_entries', {
|
||||
data: params,
|
||||
url: CoreUrlUtils.addParamsToUrl(`/mod/data/view.php?d=${this.database.id}`, params),
|
||||
url: CoreUrl.addParamsToUrl(`/mod/data/view.php?d=${this.database.id}`, params),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreCourseHelper } from '@features/course/services/course-helper';
|
||||
import { CorePushNotificationsClickHandler } from '@features/pushnotifications/services/push-delegate';
|
||||
import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifications/services/pushnotifications';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFeedbackHelper } from '../feedback-helper';
|
||||
|
@ -48,7 +48,7 @@ export class AddonModFeedbackPushClickHandlerService implements CorePushNotifica
|
|||
* @inheritdoc
|
||||
*/
|
||||
handleClick(notification: AddonModFeedbackPushNotificationData): Promise<void> {
|
||||
const contextUrlParams = CoreUrlUtils.extractUrlParams(notification.contexturl!);
|
||||
const contextUrlParams = CoreUrl.extractUrlParams(notification.contexturl!);
|
||||
const courseId = Number(notification.courseid);
|
||||
const moduleId = Number(contextUrlParams.id);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { Translate } from '@singletons';
|
||||
|
||||
|
@ -116,7 +116,7 @@ export class AddonModForumSearchPage implements OnInit {
|
|||
query,
|
||||
filters: JSON.stringify(this.resultsSource.getFilters()),
|
||||
},
|
||||
url: CoreUrlUtils.addParamsToUrl('/search/index.php', {
|
||||
url: CoreUrl.addParamsToUrl('/search/index.php', {
|
||||
q: query,
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -24,7 +24,7 @@ import { CoreNetwork } from '@services/network';
|
|||
import { CoreFileEntry } from '@services/file-helper';
|
||||
import { CoreGroups } from '@services/groups';
|
||||
import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning, CoreWSStoredFile } from '@services/ws';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
|
@ -1312,7 +1312,7 @@ export class AddonModForumProvider {
|
|||
protected translateWSPost(post: AddonModForumWSPost): AddonModForumPost {
|
||||
(post as unknown as AddonModForumPost).tags = (post.tags || []).map((tag) => {
|
||||
const viewUrl = (tag.urls && tag.urls.view) || '';
|
||||
const params = CoreUrlUtils.extractUrlParams(viewUrl);
|
||||
const params = CoreUrl.extractUrlParams(viewUrl);
|
||||
|
||||
return {
|
||||
id: tag.tagid,
|
||||
|
|
|
@ -19,7 +19,7 @@ import { AddonModForum } from '@addons/mod/forum/services/forum';
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CorePushNotificationsClickHandler } from '@features/pushnotifications/services/push-delegate';
|
||||
import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifications/services/pushnotifications';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
|
@ -56,7 +56,7 @@ export class AddonModForumPushClickHandlerService implements CorePushNotificatio
|
|||
* @returns Promise resolved when done.
|
||||
*/
|
||||
async handleClick(notification: NotificationData): Promise<void> {
|
||||
const contextUrlParams = CoreUrlUtils.extractUrlParams(notification.contexturl);
|
||||
const contextUrlParams = CoreUrl.extractUrlParams(notification.contexturl);
|
||||
const data = notification.customdata || {};
|
||||
const courseId = Number(notification.courseid);
|
||||
const discussionId = Number(contextUrlParams.d || data.discussionid);
|
||||
|
|
|
@ -23,7 +23,7 @@ import { CoreNavigator } from '@services/navigator';
|
|||
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreSync } from '@services/sync';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreWSExternalFile } from '@services/ws';
|
||||
import { ModalController, Translate } from '@singletons';
|
||||
|
@ -439,7 +439,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave {
|
|||
|
||||
// Format review lesson if present.
|
||||
if (this.eolData.reviewlesson) {
|
||||
const params = CoreUrlUtils.extractUrlParams(<string> this.eolData.reviewlesson.value);
|
||||
const params = CoreUrl.extractUrlParams(<string> this.eolData.reviewlesson.value);
|
||||
|
||||
if (!params || !params.pageid) {
|
||||
// No pageid in the URL, the user cannot review (probably didn't answer any question).
|
||||
|
|
|
@ -23,7 +23,7 @@ import { CoreNetwork } from '@services/network';
|
|||
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreSync, CoreSyncResult } from '@services/sync';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { CoreEvents } from '@singletons/events';
|
||||
|
@ -463,7 +463,7 @@ export class AddonModLessonSyncProvider extends CoreCourseActivitySyncBaseProvid
|
|||
|
||||
// Mark the retake as finished in a sync if it can be reviewed.
|
||||
if (!ignoreBlock && response.data?.reviewlesson) {
|
||||
const params = CoreUrlUtils.extractUrlParams(<string> response.data.reviewlesson.value);
|
||||
const params = CoreUrl.extractUrlParams(<string> response.data.reviewlesson.value);
|
||||
if (params.pageid) {
|
||||
// The retake can be reviewed, mark it as finished. Don't block the user for this.
|
||||
this.setRetakeFinishedInSync(lessonId, retake.retake, Number(params.pageid), siteId);
|
||||
|
|
|
@ -22,7 +22,7 @@ import { CoreFile } from '@services/file';
|
|||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
|
@ -244,7 +244,7 @@ export class AddonModLtiProvider {
|
|||
* @returns Promise resolved when the WS call is successful.
|
||||
*/
|
||||
async launch(url: string, params: AddonModLtiParam[]): Promise<void> {
|
||||
if (!CoreUrlUtils.isHttpURL(url)) {
|
||||
if (!CoreUrl.isHttpURL(url)) {
|
||||
throw Translate.instant('addon.mod_lti.errorinvalidlaunchurl');
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreCourseHelper } from '@features/course/services/course-helper';
|
||||
import { CorePushNotificationsClickHandler } from '@features/pushnotifications/services/push-delegate';
|
||||
import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifications/services/pushnotifications';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModQuiz } from '../quiz';
|
||||
|
@ -56,7 +56,7 @@ export class AddonModQuizPushClickHandlerService implements CorePushNotification
|
|||
* @returns Promise resolved when done.
|
||||
*/
|
||||
async handleClick(notification: AddonModQuizPushNotificationData): Promise<void> {
|
||||
const contextUrlParams = CoreUrlUtils.extractUrlParams(notification.contexturl || '');
|
||||
const contextUrlParams = CoreUrl.extractUrlParams(notification.contexturl || '');
|
||||
const data = notification.customdata || {};
|
||||
const courseId = Number(notification.courseid);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@
|
|||
import { CoreSync } from '@services/sync';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreWS, CoreWSExternalFile, CoreWSExternalWarning, CoreWSFile, CoreWSPreSets } from '@services/ws';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
|
@ -1328,7 +1328,7 @@ export class AddonModScormProvider {
|
|||
protected isExternalLink(link: string): boolean {
|
||||
link = link.toLowerCase();
|
||||
|
||||
if (link.match(/^https?:\/\//i) && !CoreUrlUtils.isLocalFileUrl(link)) {
|
||||
if (link.match(/^https?:\/\//i) && !CoreUrl.isLocalFileUrl(link)) {
|
||||
return true;
|
||||
} else if (link.substring(0, 4) == 'www.') {
|
||||
return true;
|
||||
|
|
|
@ -26,7 +26,7 @@ import { makeSingleton } from '@singletons';
|
|||
import { AddonModUrl } from '../url';
|
||||
import { AddonModUrlHelper } from '../url-helper';
|
||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||
import { ADDON_MOD_URL_ADDON_NAME, ADDON_MOD_URL_MODNAME, ADDON_MOD_URL_PAGE_NAME } from '../../constants';
|
||||
|
||||
|
@ -122,14 +122,14 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
|
|||
return modIcon;
|
||||
}
|
||||
|
||||
const component = CoreUrlUtils.getThemeImageUrlParam(module.modicon, 'component');
|
||||
const component = CoreUrl.getThemeImageUrlParam(module.modicon, 'component');
|
||||
if (component === this.modName) {
|
||||
return modIcon;
|
||||
}
|
||||
|
||||
let icon: string | undefined;
|
||||
|
||||
let image = CoreUrlUtils.getThemeImageUrlParam(module.modicon, 'image');
|
||||
let image = CoreUrl.getThemeImageUrlParam(module.modicon, 'image');
|
||||
if (image.startsWith('f/')) {
|
||||
// Remove prefix, and hyphen + numbered suffix.
|
||||
image = image.substring(2).replace(/-[0-9]+$/, '');
|
||||
|
|
|
@ -26,7 +26,7 @@ import { CoreNavigator } from '@services/navigator';
|
|||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils, ToastDuration } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
|
@ -313,7 +313,7 @@ export class AddonNotesListPage implements OnInit, OnDestroy {
|
|||
ws: 'core_notes_view_notes',
|
||||
name: Translate.instant('addon.notes.notes'),
|
||||
data: { courseid: this.courseId, userid: this.userId || 0, category: 'notes' },
|
||||
url: CoreUrlUtils.addParamsToUrl('/notes/index.php', {
|
||||
url: CoreUrl.addParamsToUrl('/notes/index.php', {
|
||||
user: this.userId,
|
||||
course: this.courseId !== CoreSites.getCurrentSiteHomeId() ? this.courseId : undefined,
|
||||
}),
|
||||
|
@ -329,7 +329,7 @@ export class AddonNotesListPage implements OnInit, OnDestroy {
|
|||
ws: 'core_notes_create_notes',
|
||||
name: Translate.instant('addon.notes.notes'),
|
||||
data: { courseid: this.courseId, userid: this.userId || 0, category: 'notes' },
|
||||
url: CoreUrlUtils.addParamsToUrl('/notes/edit.php', {
|
||||
url: CoreUrl.addParamsToUrl('/notes/edit.php', {
|
||||
courseid: this.courseId,
|
||||
userid: this.userId,
|
||||
publishstate: this.type === 'personal' ? 'draft' : (this.type === 'course' ? 'public' : 'site'),
|
||||
|
|
|
@ -39,7 +39,6 @@ import { CoreSiteError } from '@classes/errors/siteerror';
|
|||
import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config';
|
||||
import { CoreSiteInfo, CoreSiteInfoResponse, CoreSitePublicConfigResponse, CoreUnauthenticatedSite } from './unauthenticated-site';
|
||||
import { Md5 } from 'ts-md5';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreSiteWSCacheRecord } from '@services/database/sites';
|
||||
import { CoreErrorLogs } from '@singletons/error-logs';
|
||||
import { CoreWait } from '@singletons/wait';
|
||||
|
@ -1268,11 +1267,33 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite {
|
|||
*
|
||||
* @param page Docs page to go to.
|
||||
* @returns Promise resolved with the Moodle docs URL.
|
||||
*
|
||||
* @deprecated since 4.5. Not needed anymore.
|
||||
*/
|
||||
getDocsUrl(page?: string): Promise<string> {
|
||||
async getDocsUrl(page?: string): Promise<string> {
|
||||
const release = this.infos?.release ? this.infos.release : undefined;
|
||||
let docsUrl = 'https://docs.moodle.org/en/' + page;
|
||||
|
||||
return CoreUrlUtils.getDocsUrl(release, page);
|
||||
if (release !== undefined) {
|
||||
// Remove this part of the function if this file only uses CoreSites here.
|
||||
const version = CoreSites.getMajorReleaseNumber(release).replace('.', '');
|
||||
|
||||
// Check is a valid number.
|
||||
if (Number(version) >= 24) {
|
||||
// Append release number.
|
||||
docsUrl = docsUrl.replace('https://docs.moodle.org/', 'https://docs.moodle.org/' + version + '/');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Remove this part of the function if this file only uses CoreLang here.
|
||||
let lang = CoreLang.getCurrentLanguageSync(CoreLangFormat.LMS);
|
||||
lang = CoreLang.getParentLanguage() || lang;
|
||||
|
||||
return docsUrl.replace('/en/', '/' + lang + '/');
|
||||
} catch {
|
||||
return docsUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,7 +27,7 @@ import {
|
|||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils, CoreUtilsOpenInBrowserOptions } from '@services/utils/utils';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { SQLiteDB } from '@classes/sqlitedb';
|
||||
|
@ -380,7 +380,7 @@ export class CoreSite extends CoreAuthenticatedSite {
|
|||
const accessKey = this.tokenPluginFileWorks || this.tokenPluginFileWorks === undefined ?
|
||||
this.infos && this.infos.userprivateaccesskey : undefined;
|
||||
|
||||
return CoreUrlUtils.fixPluginfileURL(url, this.token || '', this.siteUrl, accessKey);
|
||||
return CoreUrl.fixPluginfileURL(url, this.token || '', this.siteUrl, accessKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -775,7 +775,7 @@ export class CoreSite extends CoreAuthenticatedSite {
|
|||
* @returns Promise resolved with boolean: whether it works or not.
|
||||
*/
|
||||
checkTokenPluginFile(url: string): Promise<boolean> {
|
||||
if (!CoreUrlUtils.canUseTokenPluginFile(url, this.siteUrl, this.infos && this.infos.userprivateaccesskey)) {
|
||||
if (!CoreUrl.canUseTokenPluginFile(url, this.siteUrl, this.infos && this.infos.userprivateaccesskey)) {
|
||||
// Cannot use tokenpluginfile.
|
||||
return Promise.resolve(false);
|
||||
} else if (this.tokenPluginFileWorks !== undefined) {
|
||||
|
|
|
@ -17,7 +17,7 @@ import { CoreError } from '@classes/errors/error';
|
|||
import { CoreLoginHelper } from '@features/login/services/login-helper';
|
||||
import { CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
|
||||
import { CoreWS, CoreWSAjaxPreSets, CoreWSExternalWarning } from '@services/ws';
|
||||
import { CorePath } from '@singletons/path';
|
||||
|
||||
|
@ -37,7 +37,10 @@ export class CoreUnauthenticatedSite {
|
|||
* @param publicConfig Site public config.
|
||||
*/
|
||||
constructor(siteUrl: string, publicConfig?: CoreSitePublicConfigResponse) {
|
||||
this.siteUrl = CoreUrlUtils.removeUrlParams(siteUrl); // Make sure the URL doesn't have params.
|
||||
this.siteUrl = CoreUrl.removeUrlParts(
|
||||
siteUrl,
|
||||
[CoreUrlPartNames.Query, CoreUrlPartNames.Fragment],
|
||||
); // Make sure the URL doesn't have params.
|
||||
if (publicConfig) {
|
||||
this.setPublicConfig(publicConfig);
|
||||
}
|
||||
|
@ -143,7 +146,7 @@ export class CoreUnauthenticatedSite {
|
|||
* @returns URL with params.
|
||||
*/
|
||||
createSiteUrl(path: string, params?: Record<string, unknown>, anchor?: string): string {
|
||||
return CoreUrlUtils.addParamsToUrl(CorePath.concatenatePaths(this.siteUrl, path), params, anchor);
|
||||
return CoreUrl.addParamsToUrl(CorePath.concatenatePaths(this.siteUrl, path), params, anchor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,8 +160,10 @@ export class CoreUnauthenticatedSite {
|
|||
return false;
|
||||
}
|
||||
|
||||
const siteUrl = CoreTextUtils.addEndingSlash(CoreUrlUtils.removeProtocolAndWWW(this.siteUrl));
|
||||
url = CoreTextUtils.addEndingSlash(CoreUrlUtils.removeProtocolAndWWW(url));
|
||||
const siteUrl = CoreTextUtils.addEndingSlash(
|
||||
CoreUrl.removeUrlParts(this.siteUrl, [CoreUrlPartNames.Protocol, CoreUrlPartNames.WWWInDomain]),
|
||||
);
|
||||
url = CoreTextUtils.addEndingSlash(CoreUrl.removeUrlParts(url, [CoreUrlPartNames.Protocol, CoreUrlPartNames.WWWInDomain]));
|
||||
|
||||
return url.indexOf(siteUrl) == 0;
|
||||
}
|
||||
|
@ -244,7 +249,10 @@ export class CoreUnauthenticatedSite {
|
|||
|
||||
// Use the wwwroot returned by the server.
|
||||
if (config.httpswwwroot) {
|
||||
this.siteUrl = CoreUrlUtils.removeUrlParams(config.httpswwwroot); // Make sure the URL doesn't have params.
|
||||
this.siteUrl = CoreUrl.removeUrlParts(
|
||||
config.httpswwwroot,
|
||||
[CoreUrlPartNames.Query, CoreUrlPartNames.Fragment],
|
||||
); // Make sure the URL doesn't have params.
|
||||
}
|
||||
|
||||
return config;
|
||||
|
@ -268,7 +276,7 @@ export class CoreUnauthenticatedSite {
|
|||
* @returns Whether it's a site file URL.
|
||||
*/
|
||||
isSitePluginFileUrl(url: string): boolean {
|
||||
const isPluginFileUrl = CoreUrlUtils.isPluginFileUrl(url) || CoreUrlUtils.isTokenPluginFileUrl(url);
|
||||
const isPluginFileUrl = CoreUrl.isPluginFileUrl(url) || CoreUrl.isTokenPluginFileUrl(url);
|
||||
if (!isPluginFileUrl) {
|
||||
return false;
|
||||
}
|
||||
|
@ -283,7 +291,7 @@ export class CoreUnauthenticatedSite {
|
|||
* @returns Whether it's a site theme image URL.
|
||||
*/
|
||||
isSiteThemeImageUrl(url: string): boolean {
|
||||
if (!CoreUrlUtils.isThemeImageUrl(url)) {
|
||||
if (!CoreUrl.isThemeImageUrl(url)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import { CorePluginFileDelegate } from '@services/plugin-file-delegate';
|
|||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils, CoreUtilsOpenFileOptions, OpenFileAction } from '@services/utils/utils';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { DownloadStatus } from '@/core/constants';
|
||||
|
@ -195,10 +195,10 @@ export class CoreFileComponent implements OnInit, OnDestroy {
|
|||
|
||||
if (!this.canDownload || !this.state || this.state === DownloadStatus.NOT_DOWNLOADABLE) {
|
||||
// File cannot be downloaded, just open it.
|
||||
if (CoreUrlUtils.isLocalFileUrl(this.fileUrl)) {
|
||||
if (CoreUrl.isLocalFileUrl(this.fileUrl)) {
|
||||
CoreUtils.openFile(this.fileUrl);
|
||||
} else {
|
||||
CoreUtils.openOnlineFile(CoreUrlUtils.unfixPluginfileURL(this.fileUrl));
|
||||
CoreUtils.openOnlineFile(CoreUrl.unfixPluginfileURL(this.fileUrl));
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
@ -19,7 +19,7 @@ import { SafeResourceUrl } from '@angular/platform-browser';
|
|||
|
||||
import { CoreFile } from '@services/file';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreIframeUtils } from '@services/utils/iframe';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { DomSanitizer, Router, StatusBar } from '@singletons';
|
||||
|
@ -29,7 +29,6 @@ import { Subscription } from 'rxjs';
|
|||
import { filter } from 'rxjs/operators';
|
||||
import { NavigationStart } from '@angular/router';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
|
||||
@Component({
|
||||
selector: 'core-iframe',
|
||||
|
@ -118,7 +117,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
// Show loading only with external URLs.
|
||||
this.loading = !this.src || !CoreUrlUtils.isLocalFileUrl(this.src);
|
||||
this.loading = !this.src || !CoreUrl.isLocalFileUrl(this.src);
|
||||
|
||||
if (this.loading) {
|
||||
setTimeout(() => {
|
||||
|
@ -197,8 +196,8 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
|
|||
|
||||
this.launchExternalLabel = undefined;
|
||||
|
||||
if (url && !CoreUrlUtils.isLocalFileUrl(url)) {
|
||||
url = CoreUrlUtils.getYoutubeEmbedUrl(url) || url;
|
||||
if (url && !CoreUrl.isLocalFileUrl(url)) {
|
||||
url = CoreUrl.getYoutubeEmbedUrl(url) || url;
|
||||
this.displayHelp = CoreIframeUtils.shouldDisplayHelpForUrl(url);
|
||||
|
||||
const currentSite = CoreSites.getCurrentSite();
|
||||
|
|
|
@ -28,7 +28,7 @@ import { CoreCourse } from '@features/course/services/course';
|
|||
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
|
||||
const assetsPath = 'assets/img/';
|
||||
const fallbackModName = 'external-tool';
|
||||
|
@ -155,8 +155,8 @@ export class CoreModIconComponent implements OnInit, OnChanges {
|
|||
}
|
||||
|
||||
// If it's an Moodle Theme icon, check if filtericon is set and use it.
|
||||
if (CoreUrlUtils.isThemeImageUrl(this.iconUrl())) {
|
||||
const filter = CoreUrlUtils.getThemeImageUrlParam(this.iconUrl(), 'filtericon');
|
||||
if (CoreUrl.isThemeImageUrl(this.iconUrl())) {
|
||||
const filter = CoreUrl.getThemeImageUrlParam(this.iconUrl(), 'filtericon');
|
||||
if (filter === '1') {
|
||||
this.brandedClass = false;
|
||||
|
||||
|
@ -233,7 +233,7 @@ export class CoreModIconComponent implements OnInit, OnChanges {
|
|||
* @returns Guessed modname.
|
||||
*/
|
||||
protected getComponentNameFromIconUrl(iconUrl: string): string {
|
||||
const component = CoreUrlUtils.getThemeImageUrlParam(iconUrl, 'component');
|
||||
const component = CoreUrl.getThemeImageUrlParam(iconUrl, 'component');
|
||||
|
||||
// Some invalid components (others may be added later on).
|
||||
if (component === 'core' || component === 'theme') {
|
||||
|
|
|
@ -21,7 +21,7 @@ import { USER_PROFILE_PICTURE_UPDATED, CoreUserBasicData } from '@features/user/
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreNetwork } from '@services/network';
|
||||
import { CoreUserHelper } from '@features/user/services/user-helper';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreSiteInfo } from '@classes/sites/unauthenticated-site';
|
||||
|
||||
/**
|
||||
|
@ -124,7 +124,7 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
this.fullname = this.fullname || (this.user && (this.user.fullname || this.user.userfullname));
|
||||
|
||||
if (this.avatarUrl && CoreUrlUtils.isThemeImageUrl(this.avatarUrl)) {
|
||||
if (this.avatarUrl && CoreUrl.isThemeImageUrl(this.avatarUrl)) {
|
||||
this.avatarUrl = undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import {
|
|||
import { CoreFile, CoreFileProvider } from '@services/file';
|
||||
import { CoreFilepool, CoreFilepoolFileActions, CoreFilepoolFileEventData } from '@services/filepool';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
|
@ -206,8 +206,8 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges, O
|
|||
const site = await CoreUtils.ignoreErrors(CoreSites.getSite(this.siteId));
|
||||
const isSiteFile = site?.isSitePluginFileUrl(url);
|
||||
|
||||
if (!url || !url.match(/^https?:\/\//i) || CoreUrlUtils.isLocalFileUrl(url) ||
|
||||
(tagName === 'A' && !(isSiteFile || site?.isSiteThemeImageUrl(url) || CoreUrlUtils.isGravatarUrl(url)))) {
|
||||
if (!url || !url.match(/^https?:\/\//i) || CoreUrl.isLocalFileUrl(url) ||
|
||||
(tagName === 'A' && !(isSiteFile || site?.isSiteThemeImageUrl(url) || CoreUrl.isGravatarUrl(url)))) {
|
||||
|
||||
this.logger.debug('Ignoring non-downloadable URL: ' + url);
|
||||
|
||||
|
@ -393,7 +393,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges, O
|
|||
finalUrl = CoreFile.convertFileSrc(finalUrl);
|
||||
}
|
||||
|
||||
if (!CoreUrlUtils.isLocalFileUrl(finalUrl) && !finalUrl.includes('#') && tagName !== 'A') {
|
||||
if (!CoreUrl.isLocalFileUrl(finalUrl) && !finalUrl.includes('#') && tagName !== 'A') {
|
||||
/* In iOS, if we use the same URL in embedded file and background download then the download only
|
||||
downloads a few bytes (cached ones). Add an anchor to the URL so both URLs are different.
|
||||
Don't add this anchor if the URL already has an anchor, otherwise other anchors might not work.
|
||||
|
|
|
@ -19,7 +19,7 @@ import { IonContent } from '@ionic/angular';
|
|||
import { CoreFileHelper } from '@services/file-helper';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
|
@ -27,7 +27,6 @@ import { CoreContentLinksHelper } from '@features/contentlinks/services/contentl
|
|||
import { CoreCustomURLSchemes } from '@services/urlschemes';
|
||||
import { DomSanitizer } from '@singletons';
|
||||
import { CoreFilepool } from '@services/filepool';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
|
||||
/**
|
||||
|
@ -87,7 +86,7 @@ export class CoreLinkDirective implements OnInit {
|
|||
|
||||
href = href || this.element.getAttribute('href') || this.element.getAttribute('xlink:href');
|
||||
|
||||
if (!href || CoreUrlUtils.getUrlScheme(href) === 'javascript') {
|
||||
if (!href || CoreUrl.getUrlProtocol(href) === 'javascript') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -116,7 +115,7 @@ export class CoreLinkDirective implements OnInit {
|
|||
*/
|
||||
protected async navigate(href: string, openIn?: string | null): Promise<void> {
|
||||
|
||||
if (CoreUrlUtils.isLocalFileUrl(href)) {
|
||||
if (CoreUrl.isLocalFileUrl(href)) {
|
||||
return this.openLocalFile(href);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,10 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreText } from '@singletons/text';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
|
||||
/**
|
||||
* Interface that all handlers must implement.
|
||||
|
@ -174,7 +173,7 @@ export class CoreContentLinksDelegateService {
|
|||
|
||||
const linkActions: CoreContentLinksHandlerActions[] = [];
|
||||
const promises: Promise<void>[] = [];
|
||||
const params = CoreUrlUtils.extractUrlParams(url);
|
||||
const params = CoreUrl.extractUrlParams(url);
|
||||
const relativeUrl = CoreText.addStartingSlash(CoreUrl.toRelativeURL(site.getURL(), url));
|
||||
|
||||
for (const name in this.handlers) {
|
||||
|
|
|
@ -31,7 +31,7 @@ import { CoreCourseHelper, CoreCourseModuleData } from '../services/course-helpe
|
|||
import { CoreCourseModuleDelegate, CoreCourseModuleMainComponent } from '../services/module-delegate';
|
||||
import { CoreCourseModulePrefetchDelegate } from '../services/module-prefetch-delegate';
|
||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreTime } from '@singletons/time';
|
||||
|
||||
/**
|
||||
|
@ -506,7 +506,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
|||
url = options.url;
|
||||
} else if (this.pluginName) {
|
||||
// Use default value.
|
||||
url = CoreUrlUtils.addParamsToUrl(`/mod/${this.pluginName}/view.php?id=${this.module.id}`, options.data);
|
||||
url = CoreUrl.addParamsToUrl(`/mod/${this.pluginName}/view.php?id=${this.module.id}`, options.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ import { CoreFileHelper } from '@services/file-helper';
|
|||
import { CoreNetwork } from '@services/network';
|
||||
import { CoreSite } from '@classes/sites/site';
|
||||
import { CoreFile } from '@services/file';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreFilterHelper } from '@features/filter/services/filter-helper';
|
||||
|
@ -710,7 +710,7 @@ export class CoreCourseHelperProvider {
|
|||
options,
|
||||
);
|
||||
|
||||
if (CoreUrlUtils.isLocalFileUrl(result.path)) {
|
||||
if (CoreUrl.isLocalFileUrl(result.path)) {
|
||||
return CoreUtils.openFile(result.path, options);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ import { Subscription } from 'rxjs';
|
|||
import { CoreSites } from '@services/sites';
|
||||
import { CoreFilepool } from '@services/filepool';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreEventFormActionData, CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreEditorOffline } from '../../services/editor-offline';
|
||||
|
@ -514,7 +514,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
|
|||
|
||||
const url = el.src;
|
||||
|
||||
if (!url || !CoreUrlUtils.isDownloadableUrl(url) || (!canDownloadFiles && site?.isSitePluginFileUrl(url))) {
|
||||
if (!url || !CoreUrl.isDownloadableUrl(url) || (!canDownloadFiles && site?.isSitePluginFileUrl(url))) {
|
||||
// Nothing to treat.
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ import {
|
|||
CoreGradesTableRow,
|
||||
} from '@features/grades/services/grades';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreMenuItem, CoreUtils } from '@services/utils/utils';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
|
@ -416,7 +416,7 @@ export class CoreGradesHelperProvider {
|
|||
const matches = row.itemname.content.match(regex);
|
||||
|
||||
if (matches && matches.length) {
|
||||
const hrefParams = CoreUrlUtils.extractUrlParams(matches[1]);
|
||||
const hrefParams = CoreUrl.extractUrlParams(matches[1]);
|
||||
|
||||
return hrefParams && parseInt(hrefParams.id) === moduleId;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { CoreFile } from '@services/file';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreH5P } from '../services/h5p';
|
||||
import { CoreH5PCore, CoreH5PDisplayOptions, CoreH5PContentData, CoreH5PDependenciesFiles } from './core';
|
||||
|
@ -51,7 +51,7 @@ export class CoreH5PPlayer {
|
|||
params.component = component;
|
||||
}
|
||||
|
||||
return CoreUrlUtils.addParamsToUrl(CorePath.concatenatePaths(siteUrl, '/h5p/embed.php'), params);
|
||||
return CoreUrl.addParamsToUrl(CorePath.concatenatePaths(siteUrl, '/h5p/embed.php'), params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -303,7 +303,7 @@ export class CoreH5PPlayer {
|
|||
params.customCssUrl = customCssUrl;
|
||||
}
|
||||
|
||||
return CoreUrlUtils.addParamsToUrl(path, params);
|
||||
return CoreUrl.addParamsToUrl(path, params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,7 +22,7 @@ import { CoreFilepool } from '@services/filepool';
|
|||
import { CoreFileHelper } from '@services/file-helper';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreH5P } from '@features/h5p/services/h5p';
|
||||
import { DownloadStatus } from '@/core/constants';
|
||||
import { CoreSite } from '@classes/sites/site';
|
||||
|
@ -140,7 +140,7 @@ export class CoreH5PIframeComponent implements OnChanges, OnDestroy {
|
|||
);
|
||||
|
||||
// Add the preventredirect param so the user can authenticate.
|
||||
this.iframeSrc = CoreUrlUtils.addParamsToUrl(src, { preventredirect: false });
|
||||
this.iframeSrc = CoreUrl.addParamsToUrl(src, { preventredirect: false });
|
||||
}
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'Error loading H5P package.', true);
|
||||
|
|
|
@ -18,7 +18,7 @@ import { CoreNetwork } from '@services/network';
|
|||
import { CoreFilepool } from '@services/filepool';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CorePluginFileDelegate } from '@services/plugin-file-delegate';
|
||||
import { DownloadStatus } from '@/core/constants';
|
||||
import { CoreSite } from '@classes/sites/site';
|
||||
|
@ -168,7 +168,7 @@ export class CoreH5PPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
*/
|
||||
protected async checkCanDownload(): Promise<void> {
|
||||
this.observer && this.observer.off();
|
||||
this.urlParams = CoreUrlUtils.extractUrlParams(this.src || '');
|
||||
this.urlParams = CoreUrl.extractUrlParams(this.src || '');
|
||||
|
||||
if (this.src && this.siteCanDownload && CoreH5P.canGetTrustedH5PFileInSite() && this.site.containsUrl(this.src)) {
|
||||
this.calculateState();
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreWSExternalWarning, CoreWSExternalFile, CoreWSFile } from '@services/ws';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
|
||||
import { CoreQueueRunner } from '@classes/queue-runner';
|
||||
import { CoreSite } from '@classes/sites/site';
|
||||
|
||||
|
@ -246,7 +246,7 @@ export class CoreH5PProvider {
|
|||
url = url.replace('/webservice/pluginfile', '/pluginfile');
|
||||
}
|
||||
|
||||
return CoreUrlUtils.removeUrlParams(url);
|
||||
return CoreUrl.removeUrlParts(url, [CoreUrlPartNames.Query, CoreUrlPartNames.Fragment]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import { CoreFilepoolOnProgressCallback } from '@services/filepool';
|
|||
import { CorePluginFileDownloadableResult, CorePluginFileHandler } from '@services/plugin-file-delegate';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreWSFile } from '@services/ws';
|
||||
import { CoreH5P } from '../h5p';
|
||||
|
@ -80,7 +80,7 @@ export class CoreH5PPluginFileHandlerService implements CorePluginFileHandler {
|
|||
const urls: string[] = [];
|
||||
|
||||
for (let i = 0; i < iframes.length; i++) {
|
||||
const params = CoreUrlUtils.extractUrlParams(iframes[i].src);
|
||||
const params = CoreUrl.extractUrlParams(iframes[i].src);
|
||||
|
||||
if (params.url) {
|
||||
urls.push(params.url);
|
||||
|
|
|
@ -28,8 +28,7 @@ import {
|
|||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreCustomURLSchemes, CoreCustomURLSchemesHandleError } from '@services/urlschemes';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
|
@ -206,7 +205,9 @@ export class CoreLoginSitePage implements OnInit {
|
|||
*/
|
||||
protected extendCoreLoginSiteInfo(sites: CoreLoginSiteInfoExtended[]): CoreLoginSiteInfoExtended[] {
|
||||
return sites.map((site) => {
|
||||
site.noProtocolUrl = this.siteFinderSettings.displayurl && site.url ? CoreUrl.removeProtocol(site.url) : '';
|
||||
site.noProtocolUrl = this.siteFinderSettings.displayurl && site.url
|
||||
? CoreUrl.removeUrlParts(site.url, CoreUrlPartNames.Protocol)
|
||||
: '';
|
||||
|
||||
const name = this.siteFinderSettings.displaysitename ? site.name : '';
|
||||
const alias = this.siteFinderSettings.displayalias && site.alias ? site.alias : '';
|
||||
|
@ -510,7 +511,7 @@ export class CoreLoginSitePage implements OnInit {
|
|||
name: 'connect',
|
||||
title: '',
|
||||
location: '',
|
||||
noProtocolUrl: CoreUrl.removeProtocol(search),
|
||||
noProtocolUrl: CoreUrl.removeUrlParts(search, CoreUrlPartNames.Protocol),
|
||||
};
|
||||
} else {
|
||||
this.enteredSiteUrl = undefined;
|
||||
|
@ -563,7 +564,7 @@ export class CoreLoginSitePage implements OnInit {
|
|||
}
|
||||
|
||||
// Not a custom URL scheme, check if it's a URL scheme to another app.
|
||||
const scheme = CoreUrlUtils.getUrlProtocol(text);
|
||||
const scheme = CoreUrl.getUrlProtocol(text);
|
||||
|
||||
if (scheme && scheme != 'http' && scheme != 'https') {
|
||||
CoreDomUtils.showErrorModal(Translate.instant('core.errorurlschemeinvalidscheme', { $a: text }));
|
||||
|
|
|
@ -23,7 +23,6 @@ import { CoreSites, CoreLoginSiteInfo, CoreSiteBasicInfo } from '@services/sites
|
|||
import { CoreWS, CoreWSExternalWarning } from '@services/ws';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlParams, CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { CoreSite } from '@classes/sites/site';
|
||||
|
@ -31,7 +30,7 @@ import { CoreError } from '@classes/errors/error';
|
|||
import { CoreWSError } from '@classes/errors/wserror';
|
||||
import { DomSanitizer, makeSingleton, Translate } from '@singletons';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUrl, CoreUrlParams } from '@singletons/url';
|
||||
import { CoreNavigator, CoreRedirectPayload } from '@services/navigator';
|
||||
import { CoreCanceledError } from '@classes/errors/cancelederror';
|
||||
import { CoreCustomURLSchemes } from '@services/urlschemes';
|
||||
|
@ -356,7 +355,7 @@ export class CoreLoginHelperProvider {
|
|||
|
||||
if (siteConfig.identityproviders && siteConfig.identityproviders.length) {
|
||||
siteConfig.identityproviders.forEach((provider) => {
|
||||
const urlParams = CoreUrlUtils.extractUrlParams(provider.url);
|
||||
const urlParams = CoreUrl.extractUrlParams(provider.url);
|
||||
|
||||
if (
|
||||
provider.url &&
|
||||
|
@ -397,7 +396,7 @@ export class CoreLoginHelperProvider {
|
|||
|
||||
if (siteConfig.identityproviders && siteConfig.identityproviders.length) {
|
||||
siteConfig.identityproviders.forEach((provider) => {
|
||||
const urlParams = CoreUrlUtils.extractUrlParams(provider.url);
|
||||
const urlParams = CoreUrl.extractUrlParams(provider.url);
|
||||
|
||||
if (provider.url && (provider.url.indexOf(httpsUrl) != -1 || provider.url.indexOf(httpUrl) != -1) &&
|
||||
!site.isFeatureDisabled(IDENTITY_PROVIDER_FEATURE_NAME_PREFIX + urlParams.id)) {
|
||||
|
@ -642,7 +641,7 @@ export class CoreLoginHelperProvider {
|
|||
return false;
|
||||
}
|
||||
|
||||
const params = CoreUrlUtils.extractUrlParams(provider.url);
|
||||
const params = CoreUrl.extractUrlParams(provider.url);
|
||||
|
||||
if (!params.id) {
|
||||
return false;
|
||||
|
@ -830,7 +829,7 @@ export class CoreLoginHelperProvider {
|
|||
loginUrl += '&urlscheme=' + CoreConstants.CONFIG.customurlscheme;
|
||||
|
||||
if (urlParams) {
|
||||
loginUrl = CoreUrlUtils.addParamsToUrl(loginUrl, urlParams);
|
||||
loginUrl = CoreUrl.addParamsToUrl(loginUrl, urlParams);
|
||||
}
|
||||
|
||||
// Store the siteurl and passport in CoreConfigProvider for persistence.
|
||||
|
@ -1334,7 +1333,7 @@ export class CoreLoginHelperProvider {
|
|||
}
|
||||
} else if (text) {
|
||||
// Not a custom URL scheme, check if it's a URL scheme to another app.
|
||||
const scheme = CoreUrlUtils.getUrlProtocol(text);
|
||||
const scheme = CoreUrl.getUrlProtocol(text);
|
||||
|
||||
if (scheme && scheme != 'http' && scheme != 'https') {
|
||||
CoreDomUtils.showErrorModal(Translate.instant('core.errorurlschemeinvalidscheme', { $a: text }));
|
||||
|
|
|
@ -25,7 +25,7 @@ import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
|||
import { Translate } from '@singletons';
|
||||
import { CorePolicy, CorePolicyAgreementStyle, CorePolicySitePolicy } from '@features/policy/services/policy';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { IonContent } from '@ionic/angular';
|
||||
import { CoreScreen } from '@services/screen';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
@ -223,7 +223,7 @@ export class CorePolicySitePolicyPage implements OnInit, OnDestroy {
|
|||
ws: 'tool_policy_get_user_acceptances',
|
||||
name: this.currentPolicy.name,
|
||||
data: analyticsParams,
|
||||
url: CoreUrlUtils.addParamsToUrl('/admin/tool/policy/view.php', analyticsParams),
|
||||
url: CoreUrl.addParamsToUrl('/admin/tool/policy/view.php', analyticsParams),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -236,7 +236,7 @@ export class CorePolicySitePolicyPage implements OnInit, OnDestroy {
|
|||
ws: 'tool_policy_get_user_acceptances',
|
||||
name: Translate.instant('core.policy.consentpagetitle'),
|
||||
data: {},
|
||||
url: CoreUrlUtils.addParamsToUrl('/admin/tool/policy/index.php'),
|
||||
url: CoreUrl.addParamsToUrl('/admin/tool/policy/index.php'),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import { CoreFileHelper } from '@services/file-helper';
|
|||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreWSFile } from '@services/ws';
|
||||
import { CoreIonicColorNames } from '@singletons/colors';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
|
@ -367,7 +367,7 @@ export class CoreQuestionBaseComponent<T extends AddonModQuizQuestion = AddonMod
|
|||
}
|
||||
|
||||
if (fileManagerUrl) {
|
||||
const params = CoreUrlUtils.extractUrlParams(fileManagerUrl);
|
||||
const params = CoreUrl.extractUrlParams(fileManagerUrl);
|
||||
const maxBytes = Number(params.maxbytes);
|
||||
const areaMaxBytes = Number(params.areamaxbytes);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import { makeSingleton, Translate } from '@singletons';
|
|||
import { CoreQuestion, CoreQuestionProvider, CoreQuestionQuestionParsed, CoreQuestionsAnswers } from './question';
|
||||
import { CoreQuestionDelegate } from './question-delegate';
|
||||
import { CoreIcons } from '@singletons/icons';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { ContextLevel } from '@/core/constants';
|
||||
import { CoreIonicColorNames } from '@singletons/colors';
|
||||
|
||||
|
@ -681,7 +681,7 @@ export class CoreQuestionHelperProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
if (CoreUrlUtils.isThemeImageUrl(fileUrl) && fileUrl.indexOf('flagged') > -1) {
|
||||
if (CoreUrl.isThemeImageUrl(fileUrl) && fileUrl.indexOf('flagged') > -1) {
|
||||
// Ignore flag images.
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import { CoreSites } from '@services/sites';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreEvents, CoreEventObserver } from '@singletons/events';
|
||||
import {
|
||||
CoreSearchGlobalSearchResult,
|
||||
|
@ -115,7 +115,7 @@ export class CoreSearchGlobalSearchPage implements OnInit, OnDestroy, AfterViewI
|
|||
query,
|
||||
filters: JSON.stringify(this.resultsSource.getFilters()),
|
||||
},
|
||||
url: CoreUrlUtils.addParamsToUrl('/search/index.php', {
|
||||
url: CoreUrl.addParamsToUrl('/search/index.php', {
|
||||
q: query,
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -84,7 +84,7 @@ import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/class
|
|||
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
|
||||
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
|
||||
import { CoreObject } from '@singletons/object';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CorePath } from '@singletons/path';
|
||||
import { CoreEnrolAction, CoreEnrolDelegate } from '@features/enrol/services/enrol-delegate';
|
||||
import { CoreSitePluginsEnrolHandler } from '../classes/handlers/enrol-handler';
|
||||
|
@ -170,7 +170,7 @@ export class CoreSitePluginsInitService {
|
|||
|
||||
// Make sure it's an absolute URL. Do not use toAbsoluteURL because it can change the behaviour and break plugin styles.
|
||||
let url = handlerSchema.styles?.url;
|
||||
if (url && !CoreUrlUtils.isAbsoluteURL(url)) {
|
||||
if (url && !CoreUrl.isAbsoluteURL(url)) {
|
||||
url = CorePath.concatenatePaths(site.getURL(), url);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import { CoreNavigator } from '@services/navigator';
|
|||
import { CoreTime } from '@singletons/time';
|
||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
|
||||
/**
|
||||
* Page that displays the tag index.
|
||||
|
@ -62,7 +62,7 @@ export class CoreTagIndexPage implements OnInit {
|
|||
ws: 'core_tag_get_tagindex_per_area',
|
||||
name: this.tagName || Translate.instant('core.tag.tag'),
|
||||
data: { id: this.tagId || undefined, ...params, category: 'tag' },
|
||||
url: CoreUrlUtils.addParamsToUrl('/tag/index.php', params),
|
||||
url: CoreUrl.addParamsToUrl('/tag/index.php', params),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import { CoreSite } from '@classes/sites/site';
|
|||
import { CoreFileUploaderHelper } from '@features/fileuploader/services/fileuploader-helper';
|
||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
|
||||
/**
|
||||
* Page that displays info about a user.
|
||||
|
@ -247,7 +247,7 @@ export class CoreUserAboutPage implements OnInit, OnDestroy {
|
|||
return 'undefined';
|
||||
}
|
||||
|
||||
if (CoreUrlUtils.isThemeImageUrl(avatarUrl, this.site?.siteUrl)) {
|
||||
if (CoreUrl.isThemeImageUrl(avatarUrl, this.site?.siteUrl)) {
|
||||
return 'default';
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import { CoreEvents, CoreEventSiteData, CoreEventUserDeletedData, CoreEventUserS
|
|||
import { CoreStatusWithWarningsWSResponse, CoreWSExternalWarning } from '@services/ws';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { USERS_TABLE_NAME, CoreUserDBRecord } from './database/user';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
|
||||
|
@ -668,7 +668,7 @@ export class CoreUserProvider {
|
|||
}
|
||||
|
||||
// Do not prefetch when initials are set and image is default.
|
||||
if (imageUrl && CoreUrlUtils.isThemeImageUrl(imageUrl)) {
|
||||
if (imageUrl && CoreUrl.isThemeImageUrl(imageUrl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import { CorePlatform } from '@services/platform';
|
|||
import { CoreSites } from '@services/sites';
|
||||
import { CoreCustomURLSchemes } from '@services/urlschemes';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreEvents } from '@singletons/events';
|
||||
|
@ -34,9 +34,9 @@ export default function(): void {
|
|||
// Check URLs loaded in any InAppBrowser.
|
||||
CoreEvents.on(CoreEvents.IAB_LOAD_START, async (event) => {
|
||||
// URLs with a custom scheme can be prefixed with "http://" or "https://", we need to remove this.
|
||||
const protocol = CoreUrlUtils.getUrlProtocol(event.url);
|
||||
const protocol = CoreUrl.getUrlProtocol(event.url);
|
||||
const url = event.url.replace(/^https?:\/\//, '');
|
||||
const urlScheme = CoreUrlUtils.getUrlProtocol(url);
|
||||
const urlScheme = CoreUrl.getUrlProtocol(url);
|
||||
const isExternalApp = urlScheme && urlScheme !== 'file' && urlScheme !== 'cdvfile';
|
||||
|
||||
if (CoreCustomURLSchemes.isCustomURL(url)) {
|
||||
|
|
|
@ -20,8 +20,8 @@ import { CoreEvents } from '@singletons/events';
|
|||
import { CoreSites } from './sites';
|
||||
import { CoreConfig, CoreConfigProvider } from './config';
|
||||
import { CoreConstants } from '../constants';
|
||||
import { CoreUrlUtils } from './utils/url';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
|
||||
/**
|
||||
* Helper service to support analytics.
|
||||
|
@ -107,7 +107,7 @@ export class CoreAnalyticsService extends CoreDelegate<CoreAnalyticsHandler> {
|
|||
}
|
||||
|
||||
if ('url' in treatedEvent && treatedEvent.url) {
|
||||
if (!CoreUrlUtils.isAbsoluteURL(treatedEvent.url)) {
|
||||
if (!CoreUrl.isAbsoluteURL(treatedEvent.url)) {
|
||||
treatedEvent.url = site.createSiteUrl(treatedEvent.url);
|
||||
} else if (!site.containsUrl(treatedEvent.url)) {
|
||||
// URL belongs to a different site, ignore the event.
|
||||
|
|
|
@ -21,7 +21,7 @@ import { CoreFilepool } from '@services/filepool';
|
|||
import { CoreSites } from '@services/sites';
|
||||
import { CoreWS, CoreWSFile } from '@services/ws';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils, CoreUtilsOpenFileOptions, OpenFileAction } from '@services/utils/utils';
|
||||
import { CoreConstants, DownloadStatus } from '@/core/constants';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
|
@ -93,7 +93,7 @@ export class CoreFileHelperProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!CoreUrlUtils.isLocalFileUrl(url)) {
|
||||
if (!CoreUrl.isLocalFileUrl(url)) {
|
||||
/* In iOS, if we use the same URL in embedded browser and background download then the download only
|
||||
downloads a few bytes (cached ones). Add a hash to the URL so both URLs are different. */
|
||||
url = url + '#moodlemobile-embedded';
|
||||
|
|
|
@ -26,7 +26,7 @@ import { CoreDomUtils } from '@services/utils/dom';
|
|||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
|
||||
import { CoreUtils, CoreUtilsOpenFileOptions } from '@services/utils/utils';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { DownloadStatus } from '@/core/constants';
|
||||
|
@ -51,7 +51,6 @@ import {
|
|||
QUEUE_TABLE_PRIMARY_KEYS,
|
||||
} from '@services/database/filepool';
|
||||
import { CoreFileHelper } from './file-helper';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreDatabaseTable } from '@classes/database/database-table';
|
||||
import { CoreDatabaseCachingStrategy, CoreDatabaseTableProxy } from '@classes/database/database-table-proxy';
|
||||
import { lazyMap, LazyMap } from '../utils/lazy-map';
|
||||
|
@ -782,7 +781,7 @@ export class CoreFilepoolProvider {
|
|||
|
||||
CoreAnalytics.logEvent({
|
||||
type: CoreAnalyticsEventType.DOWNLOAD_FILE,
|
||||
fileUrl: CoreUrlUtils.unfixPluginfileURL(fileUrl, site.getURL()),
|
||||
fileUrl: CoreUrl.unfixPluginfileURL(fileUrl, site.getURL()),
|
||||
});
|
||||
|
||||
// Add the anchor again to the local URL.
|
||||
|
@ -1126,14 +1125,14 @@ export class CoreFilepoolProvider {
|
|||
const element = elements[i];
|
||||
const url = 'href' in element ? element.href : element.src;
|
||||
|
||||
if (url && CoreUrlUtils.isDownloadableUrl(url) && urls.indexOf(url) == -1) {
|
||||
if (url && CoreUrl.isDownloadableUrl(url) && urls.indexOf(url) == -1) {
|
||||
urls.push(url);
|
||||
}
|
||||
|
||||
// Treat video poster.
|
||||
if (element.tagName == 'VIDEO' && element.getAttribute('poster')) {
|
||||
const poster = element.getAttribute('poster');
|
||||
if (poster && CoreUrlUtils.isDownloadableUrl(poster) && urls.indexOf(poster) == -1) {
|
||||
if (poster && CoreUrl.isDownloadableUrl(poster) && urls.indexOf(poster) == -1) {
|
||||
urls.push(poster);
|
||||
}
|
||||
}
|
||||
|
@ -1363,7 +1362,7 @@ export class CoreFilepoolProvider {
|
|||
}
|
||||
|
||||
// Remove the anchor.
|
||||
url = CoreUrl.removeUrlAnchor(url);
|
||||
url = CoreUrl.removeUrlParts(url, CoreUrlPartNames.Fragment);
|
||||
|
||||
// Try to guess the filename the target file should have.
|
||||
// We want to keep the original file name so people can easily identify the files after the download.
|
||||
|
@ -1535,7 +1534,7 @@ export class CoreFilepoolProvider {
|
|||
return DownloadStatus.NOT_DOWNLOADABLE;
|
||||
}
|
||||
|
||||
fileUrl = CoreUrl.removeUrlAnchor(CoreFileHelper.getFileUrl(file));
|
||||
fileUrl = CoreUrl.removeUrlParts(CoreFileHelper.getFileUrl(file), CoreUrlPartNames.Fragment);
|
||||
timemodified = file.timemodified ?? timemodified;
|
||||
revision = revision ?? this.getRevisionFromUrl(fileUrl);
|
||||
const fileId = this.getFileIdByUrl(fileUrl);
|
||||
|
@ -1914,7 +1913,7 @@ export class CoreFilepoolProvider {
|
|||
* @returns The args found, undefined if not a pluginfile.
|
||||
*/
|
||||
protected getPluginFileArgs(url: string): string[] | undefined {
|
||||
if (!CoreUrlUtils.isPluginFileUrl(url)) {
|
||||
if (!CoreUrl.isPluginFileUrl(url)) {
|
||||
// Not pluginfile, return.
|
||||
return;
|
||||
}
|
||||
|
@ -2160,27 +2159,27 @@ export class CoreFilepoolProvider {
|
|||
|
||||
if (fileUrl.indexOf('/webservice/pluginfile') !== -1) {
|
||||
// It's a pluginfile URL. Search for the 'file' param to extract the name.
|
||||
const params = CoreUrlUtils.extractUrlParams(fileUrl);
|
||||
const params = CoreUrl.extractUrlParams(fileUrl);
|
||||
if (params.file) {
|
||||
filename = params.file.substring(params.file.lastIndexOf('/') + 1);
|
||||
} else {
|
||||
// 'file' param not found. Extract what's after the last '/' without params.
|
||||
filename = CoreUrlUtils.getLastFileWithoutParams(fileUrl);
|
||||
filename = CoreUrl.getLastFileWithoutParams(fileUrl);
|
||||
}
|
||||
} else if (CoreUrlUtils.isGravatarUrl(fileUrl)) {
|
||||
} else if (CoreUrl.isGravatarUrl(fileUrl)) {
|
||||
// Extract gravatar ID.
|
||||
filename = 'gravatar_' + CoreUrlUtils.getLastFileWithoutParams(fileUrl);
|
||||
} else if (CoreUrlUtils.isThemeImageUrl(fileUrl)) {
|
||||
filename = 'gravatar_' + CoreUrl.getLastFileWithoutParams(fileUrl);
|
||||
} else if (CoreUrl.isThemeImageUrl(fileUrl)) {
|
||||
// Extract user ID.
|
||||
const matches = fileUrl.match(/\/core\/([^/]*)\//);
|
||||
if (matches && matches[1]) {
|
||||
filename = matches[1];
|
||||
}
|
||||
// Attach a constant and the image type.
|
||||
filename = 'default_' + filename + '_' + CoreUrlUtils.getLastFileWithoutParams(fileUrl);
|
||||
filename = 'default_' + filename + '_' + CoreUrl.getLastFileWithoutParams(fileUrl);
|
||||
} else {
|
||||
// Another URL. Just get what's after the last /.
|
||||
filename = CoreUrlUtils.getLastFileWithoutParams(fileUrl);
|
||||
filename = CoreUrl.getLastFileWithoutParams(fileUrl);
|
||||
}
|
||||
|
||||
// If there are hashes in the URL, extract them.
|
||||
|
@ -3005,7 +3004,7 @@ export class CoreFilepoolProvider {
|
|||
try {
|
||||
let fileUrl = absoluteUrl;
|
||||
|
||||
if (!CoreUrlUtils.isLocalFileUrl(absoluteUrl)) {
|
||||
if (!CoreUrl.isLocalFileUrl(absoluteUrl)) {
|
||||
// Not a local file, download it.
|
||||
fileUrl = await this.downloadUrl(
|
||||
siteId,
|
||||
|
|
|
@ -23,7 +23,7 @@ import { CoreMainMenu } from '@features/mainmenu/services/mainmenu';
|
|||
import { CoreObject } from '@singletons/object';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { makeSingleton, NavController, Router } from '@singletons';
|
||||
import { CoreScreen } from './screen';
|
||||
|
@ -262,7 +262,7 @@ export class CoreNavigatorService {
|
|||
* @returns Current path.
|
||||
*/
|
||||
getCurrentPath(): string {
|
||||
return CoreUrlUtils.removeUrlParams(Router.url);
|
||||
return CoreUrl.removeUrlParts(Router.url, [CoreUrlPartNames.Query, CoreUrlPartNames.Fragment]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,7 +21,7 @@ import { CoreEvents } from '@singletons/events';
|
|||
import { CoreWS } from '@services/ws';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import {
|
||||
|
@ -286,9 +286,9 @@ export class CoreSitesProvider {
|
|||
*/
|
||||
async checkSite(siteUrl: string, protocol: string = 'https://'): Promise<CoreSiteCheckResponse> {
|
||||
// The formatURL function adds the protocol if is missing.
|
||||
siteUrl = CoreUrlUtils.formatURL(siteUrl);
|
||||
siteUrl = CoreUrl.formatURL(siteUrl);
|
||||
|
||||
if (!CoreUrlUtils.isHttpURL(siteUrl)) {
|
||||
if (!CoreUrl.isHttpURL(siteUrl)) {
|
||||
throw new CoreError(Translate.instant('core.login.invalidsite'));
|
||||
}
|
||||
|
||||
|
@ -350,7 +350,7 @@ export class CoreSitesProvider {
|
|||
}
|
||||
|
||||
// Try to add or remove 'www'.
|
||||
temporarySite.setURL(CoreUrlUtils.addOrRemoveWWW(temporarySite.getURL()));
|
||||
temporarySite.setURL(CoreUrl.addOrRemoveWWW(temporarySite.getURL()));
|
||||
|
||||
try {
|
||||
config = await temporarySite.getPublicConfig();
|
||||
|
@ -546,7 +546,7 @@ export class CoreSitesProvider {
|
|||
|
||||
// We only allow one retry (to avoid loops).
|
||||
if (!retry && data.errorcode == 'requirecorrectaccess') {
|
||||
siteUrl = CoreUrlUtils.addOrRemoveWWW(siteUrl);
|
||||
siteUrl = CoreUrl.addOrRemoveWWW(siteUrl);
|
||||
|
||||
return this.getUserToken(siteUrl, username, password, service, true);
|
||||
}
|
||||
|
@ -1697,7 +1697,7 @@ export class CoreSitesProvider {
|
|||
// Check if URL has http(s) protocol.
|
||||
if (!url.match(/^https?:\/\//i)) {
|
||||
// URL doesn't have http(s) protocol. Check if it has any protocol.
|
||||
if (CoreUrlUtils.isAbsoluteURL(url)) {
|
||||
if (CoreUrl.isAbsoluteURL(url)) {
|
||||
// It has some protocol. Return empty array.
|
||||
return [];
|
||||
}
|
||||
|
@ -1943,11 +1943,13 @@ export class CoreSitesProvider {
|
|||
const site = await this.getSite(siteIds[0]);
|
||||
|
||||
const siteUrl = CoreText.removeEndingSlash(
|
||||
CoreUrlUtils.removeProtocolAndWWW(site.getURL()),
|
||||
CoreUrl.removeUrlParts(site.getURL(), [CoreUrlPartNames.Protocol, CoreUrlPartNames.WWWInDomain]),
|
||||
);
|
||||
const treatedUrl = CoreText.removeEndingSlash(
|
||||
CoreUrl.removeUrlParts(url, [CoreUrlPartNames.Protocol, CoreUrlPartNames.WWWInDomain]),
|
||||
);
|
||||
const treatedUrl = CoreText.removeEndingSlash(CoreUrlUtils.removeProtocolAndWWW(url));
|
||||
|
||||
if (siteUrl == treatedUrl) {
|
||||
if (siteUrl === treatedUrl) {
|
||||
result.site = site;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { CoreUrlUtilsProvider } from '@services/utils/url';
|
||||
|
||||
describe('CoreUrlUtilsProvider', () => {
|
||||
|
||||
let urlUtils: CoreUrlUtilsProvider;
|
||||
|
||||
beforeEach(() => {
|
||||
urlUtils = new CoreUrlUtilsProvider();
|
||||
});
|
||||
|
||||
it('adds www if missing', () => {
|
||||
const originalUrl = 'https://moodle.org';
|
||||
const url = urlUtils.addOrRemoveWWW(originalUrl);
|
||||
|
||||
expect(url).toEqual('https://www.moodle.org');
|
||||
});
|
||||
|
||||
it('removes www if present', () => {
|
||||
const originalUrl = 'https://www.moodle.org';
|
||||
const url = urlUtils.addOrRemoveWWW(originalUrl);
|
||||
|
||||
expect(url).toEqual('https://moodle.org');
|
||||
});
|
||||
|
||||
it('adds params to URL without params', () => {
|
||||
const originalUrl = 'https://moodle.org';
|
||||
const params = {
|
||||
first: '1',
|
||||
second: '2',
|
||||
};
|
||||
const url = urlUtils.addParamsToUrl(originalUrl, params);
|
||||
|
||||
expect(url).toEqual('https://moodle.org?first=1&second=2');
|
||||
});
|
||||
|
||||
it('adds params to URL with existing params', () => {
|
||||
const originalUrl = 'https://moodle.org?existing=1';
|
||||
const params = {
|
||||
first: '1',
|
||||
second: '2',
|
||||
};
|
||||
const url = urlUtils.addParamsToUrl(originalUrl, params);
|
||||
|
||||
expect(url).toEqual('https://moodle.org?existing=1&first=1&second=2');
|
||||
});
|
||||
|
||||
it('doesn\'t change URL if no params supplied', () => {
|
||||
const originalUrl = 'https://moodle.org';
|
||||
const url = urlUtils.addParamsToUrl(originalUrl);
|
||||
|
||||
expect(url).toEqual(originalUrl);
|
||||
});
|
||||
|
||||
it('doesn\'t add undefined or null params', () => {
|
||||
const originalUrl = 'https://moodle.org';
|
||||
const url = urlUtils.addParamsToUrl(originalUrl, {
|
||||
foo: undefined,
|
||||
bar: null,
|
||||
baz: 1,
|
||||
});
|
||||
|
||||
expect(url).toEqual('https://moodle.org?baz=1');
|
||||
});
|
||||
|
||||
it('adds anchor to URL', () => {
|
||||
const originalUrl = 'https://moodle.org';
|
||||
const params = {
|
||||
first: '1',
|
||||
second: '2',
|
||||
};
|
||||
const url = urlUtils.addParamsToUrl(originalUrl, params, 'myanchor');
|
||||
|
||||
expect(url).toEqual('https://moodle.org?first=1&second=2#myanchor');
|
||||
});
|
||||
|
||||
});
|
|
@ -28,7 +28,7 @@ import { CoreNavigator, CoreRedirectPayload } from './navigator';
|
|||
import { CoreSiteCheckResponse, CoreSites } from './sites';
|
||||
import { CoreDomUtils } from './utils/dom';
|
||||
import { CoreTextErrorObject, CoreTextUtils } from './utils/text';
|
||||
import { CoreUrlUtils } from './utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from './utils/utils';
|
||||
|
||||
/*
|
||||
|
@ -240,13 +240,13 @@ export class CoreCustomURLSchemesProvider {
|
|||
url = this.removeCustomURLScheme(url);
|
||||
|
||||
// Detect if there's a user specified.
|
||||
const username = CoreUrlUtils.getUsernameFromUrl(url);
|
||||
const username = CoreUrl.getUsernameFromUrl(url);
|
||||
if (username) {
|
||||
url = url.replace(username + '@', ''); // Remove the username from the URL.
|
||||
}
|
||||
|
||||
// Get the params of the URL.
|
||||
const params = CoreUrlUtils.extractUrlParams(url);
|
||||
const params = CoreUrl.extractUrlParams(url);
|
||||
|
||||
// Remove the params to get the site URL.
|
||||
if (url.indexOf('?') != -1) {
|
||||
|
@ -293,7 +293,7 @@ export class CoreCustomURLSchemesProvider {
|
|||
url = this.removeCustomURLLinkScheme(url);
|
||||
|
||||
// Detect if there's a user specified.
|
||||
const username = CoreUrlUtils.getUsernameFromUrl(url);
|
||||
const username = CoreUrl.getUsernameFromUrl(url);
|
||||
if (username) {
|
||||
url = url.replace(username + '@', ''); // Remove the username from the URL.
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import { CoreConfig } from '@services/config';
|
|||
import { CoreFile } from '@services/file';
|
||||
import { CoreWSExternalWarning } from '@services/ws';
|
||||
import { CoreTextUtils, CoreTextErrorObject } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { CoreIonLoadingElement } from '@classes/ion-loading';
|
||||
|
@ -710,7 +710,10 @@ export class CoreDomUtilsProvider {
|
|||
media.forEach((media: HTMLElement) => {
|
||||
const currentSrc = media.getAttribute('src');
|
||||
const newSrc = currentSrc ?
|
||||
paths[CoreUrlUtils.removeUrlParams(CoreTextUtils.decodeURIComponent(currentSrc))] :
|
||||
paths[CoreUrl.removeUrlParts(
|
||||
CoreTextUtils.decodeURIComponent(currentSrc),
|
||||
[CoreUrlPartNames.Query, CoreUrlPartNames.Fragment],
|
||||
)] :
|
||||
undefined;
|
||||
|
||||
if (newSrc !== undefined) {
|
||||
|
@ -732,7 +735,10 @@ export class CoreDomUtilsProvider {
|
|||
anchors.forEach((anchor: HTMLElement) => {
|
||||
const currentHref = anchor.getAttribute('href');
|
||||
const newHref = currentHref ?
|
||||
paths[CoreUrlUtils.removeUrlParams(CoreTextUtils.decodeURIComponent(currentHref))] :
|
||||
paths[CoreUrl.removeUrlParts(
|
||||
CoreTextUtils.decodeURIComponent(currentHref),
|
||||
[CoreUrlPartNames.Query, CoreUrlPartNames.Fragment],
|
||||
)] :
|
||||
undefined;
|
||||
|
||||
if (newHref !== undefined) {
|
||||
|
|
|
@ -21,12 +21,11 @@ import { CoreFile } from '@services/file';
|
|||
import { CoreFileHelper } from '@services/file-helper';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
|
||||
import { makeSingleton, NgZone, Translate } from '@singletons';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreWindow } from '@singletons/window';
|
||||
import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper';
|
||||
import { CorePath } from '@singletons/path';
|
||||
|
@ -68,7 +67,7 @@ export class CoreIframeUtilsProvider {
|
|||
checkOnlineFrameInOffline(element: CoreFrameElement, isSubframe?: boolean): boolean {
|
||||
const src = 'src' in element ? element.src : element.data;
|
||||
|
||||
if (src && src != 'about:blank' && !CoreUrlUtils.isLocalFileUrl(src) && !CoreNetwork.isOnline()) {
|
||||
if (src && src != 'about:blank' && !CoreUrl.isLocalFileUrl(src) && !CoreNetwork.isOnline()) {
|
||||
if (element.classList.contains('core-iframe-offline-disabled')) {
|
||||
// Iframe already hidden, stop.
|
||||
return true;
|
||||
|
@ -234,7 +233,7 @@ export class CoreIframeUtilsProvider {
|
|||
*/
|
||||
getContentWindowAndDocument(element: CoreFrameElement): { window: Window | null; document: Document | null } {
|
||||
const src = 'src' in element ? element.src : element.data;
|
||||
if (src !== 'about:blank' && !CoreUrlUtils.isLocalFileUrl(src)) {
|
||||
if (src !== 'about:blank' && !CoreUrl.isLocalFileUrl(src)) {
|
||||
// No permissions to access the iframe.
|
||||
return { window: null, document: null };
|
||||
}
|
||||
|
@ -423,7 +422,7 @@ export class CoreIframeUtilsProvider {
|
|||
* @returns Promise resolved when done.
|
||||
*/
|
||||
protected async windowOpen(url: string, name: string, element?: CoreFrameElement): Promise<void> {
|
||||
const scheme = CoreUrlUtils.getUrlScheme(url);
|
||||
const scheme = CoreUrl.getUrlProtocol(url);
|
||||
if (!scheme) {
|
||||
// It's a relative URL, use the frame src to create the full URL.
|
||||
const src = element
|
||||
|
@ -488,12 +487,12 @@ export class CoreIframeUtilsProvider {
|
|||
|
||||
const urlParts = CoreUrl.parse(link.href);
|
||||
const originalHref = 'getAttribute' in link ? link.getAttribute('href') : link.originalHref;
|
||||
if (!link.href || !originalHref || originalHref == '#' || !urlParts || urlParts.protocol == 'javascript') {
|
||||
if (!link.href || !originalHref || originalHref == '#' || !urlParts || urlParts.protocol === 'javascript') {
|
||||
// Links with no URL and Javascript links are ignored.
|
||||
return;
|
||||
}
|
||||
|
||||
if (urlParts.protocol && !CoreUrlUtils.isLocalFileUrlScheme(urlParts.protocol, urlParts.domain || '')) {
|
||||
if (urlParts.protocol && !CoreUrl.isLocalFileUrlScheme(urlParts.protocol, urlParts.domain || '')) {
|
||||
// Scheme suggests it's an external resource.
|
||||
event && event.preventDefault();
|
||||
|
||||
|
@ -503,7 +502,7 @@ export class CoreIframeUtilsProvider {
|
|||
if (
|
||||
element &&
|
||||
frameSrc &&
|
||||
!CoreUrlUtils.isLocalFileUrl(frameSrc) &&
|
||||
!CoreUrl.isLocalFileUrl(frameSrc) &&
|
||||
(!link.target || link.target == '_self')
|
||||
) {
|
||||
// Load the link inside the frame itself.
|
||||
|
@ -574,7 +573,7 @@ export class CoreIframeUtilsProvider {
|
|||
* @returns Promise resolved when done.
|
||||
*/
|
||||
async fixIframeCookies(url: string): Promise<void> {
|
||||
if (!CorePlatform.isIOS() || !url || CoreUrlUtils.isLocalFileUrl(url)) {
|
||||
if (!CorePlatform.isIOS() || !url || CoreUrl.isLocalFileUrl(url)) {
|
||||
// No need to fix cookies.
|
||||
return;
|
||||
}
|
||||
|
@ -613,7 +612,7 @@ export class CoreIframeUtilsProvider {
|
|||
* @returns Boolean.
|
||||
*/
|
||||
shouldDisplayHelpForUrl(url: string): boolean {
|
||||
return this.shouldDisplayHelp() && !CoreUrlUtils.isLocalFileUrl(url);
|
||||
return this.shouldDisplayHelp() && !CoreUrl.isLocalFileUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,18 +14,12 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { CoreLang, CoreLangFormat } from '@services/lang';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CorePath } from '@singletons/path';
|
||||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreMedia } from '@singletons/media';
|
||||
import { CoreUrl, CoreUrlParams as CoreUrlParamsNew, CoreUrlPartNames } from '@singletons/url';
|
||||
|
||||
/*
|
||||
* "Utils" service with helper functions for URLs.
|
||||
* @deprecated since 4.5. Use CoreUrl instead.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CoreUrlUtilsProvider {
|
||||
|
@ -35,19 +29,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url URL to modify.
|
||||
* @returns Modified URL.
|
||||
* @deprecated since 4.5. Use CoreUrl.addOrRemoveWWW instead.
|
||||
*/
|
||||
addOrRemoveWWW(url: string): string {
|
||||
if (url) {
|
||||
if (url.match(/http(s)?:\/\/www\./)) {
|
||||
// Already has www. Remove it.
|
||||
url = url.replace('www.', '');
|
||||
} else {
|
||||
url = url.replace('https://', 'https://www.');
|
||||
url = url.replace('http://', 'http://www.');
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
return CoreUrl.addOrRemoveWWW(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,43 +43,10 @@ export class CoreUrlUtilsProvider {
|
|||
* @param anchor Anchor text if needed.
|
||||
* @param boolToNumber Whether to convert bools to 1 or 0.
|
||||
* @returns URL with params.
|
||||
* @deprecated since 4.5. Use CoreUrl.addParamsToUrl instead.
|
||||
*/
|
||||
addParamsToUrl(url: string, params?: Record<string, unknown>, anchor?: string, boolToNumber?: boolean): string {
|
||||
// Remove any existing anchor to add the params before it.
|
||||
const urlAndAnchor = url.split('#');
|
||||
url = urlAndAnchor[0];
|
||||
|
||||
let separator = url.indexOf('?') !== -1 ? '&' : '?';
|
||||
|
||||
for (const key in params) {
|
||||
let value = params[key];
|
||||
|
||||
if (boolToNumber && typeof value === 'boolean') {
|
||||
// Convert booleans to 1 or 0.
|
||||
value = value ? '1' : '0';
|
||||
}
|
||||
|
||||
// Ignore objects and undefined.
|
||||
if (typeof value !== 'object' && value !== undefined) {
|
||||
url += separator + key + '=' + value;
|
||||
separator = '&';
|
||||
}
|
||||
}
|
||||
|
||||
// Re-add the anchor if any.
|
||||
if (urlAndAnchor.length > 1) {
|
||||
// Remove the URL from the array.
|
||||
urlAndAnchor.shift();
|
||||
|
||||
// Use a join in case there is more than one #.
|
||||
url += '#' + urlAndAnchor.join('#');
|
||||
}
|
||||
|
||||
if (anchor) {
|
||||
url += '#' + anchor;
|
||||
}
|
||||
|
||||
return url;
|
||||
return CoreUrl.addParamsToUrl(url, params, anchor, boolToNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,9 +55,10 @@ export class CoreUrlUtilsProvider {
|
|||
* @param url URL.
|
||||
* @param text Text of the link.
|
||||
* @returns Link.
|
||||
* @deprecated since 4.5. Use CoreUrl.buildLink instead.
|
||||
*/
|
||||
buildLink(url: string, text: string): string {
|
||||
return '<a href="' + url + '">' + text + '</a>';
|
||||
return CoreUrl.buildLink(url, text);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,14 +68,10 @@ export class CoreUrlUtilsProvider {
|
|||
* @param siteUrl The URL of the site the URL belongs to.
|
||||
* @param accessKey User access key for tokenpluginfile.
|
||||
* @returns Whether tokenpluginfile.php can be used.
|
||||
* @deprecated since 4.5. Use CoreUrl.canUseTokenPluginFile instead.
|
||||
*/
|
||||
canUseTokenPluginFile(url: string, siteUrl: string, accessKey?: string): boolean {
|
||||
// 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).
|
||||
return !CoreConstants.CONFIG.disableTokenFile && !!accessKey && !url.match(/[&?]file=/) && (
|
||||
url.indexOf(CorePath.concatenatePaths(siteUrl, 'pluginfile.php')) === 0 ||
|
||||
url.indexOf(CorePath.concatenatePaths(siteUrl, 'webservice/pluginfile.php')) === 0) &&
|
||||
!CoreMedia.sourceUsesJavascriptPlayer({ src: url });
|
||||
return CoreUrl.canUseTokenPluginFile(url, siteUrl, accessKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,43 +79,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url URL to treat.
|
||||
* @returns Object with the params.
|
||||
* @deprecated since 4.5. Use CoreUrl.extractUrlParams instead.
|
||||
*/
|
||||
extractUrlParams(url: string): CoreUrlParams {
|
||||
const regex = /[?&]+([^=&]+)=?([^&]*)?/gi;
|
||||
const subParamsPlaceholder = '@@@SUBPARAMS@@@';
|
||||
const params: CoreUrlParams = {};
|
||||
const urlAndHash = url.split('#');
|
||||
const questionMarkSplit = urlAndHash[0].split('?');
|
||||
let subParams: string;
|
||||
|
||||
if (questionMarkSplit.length > 2) {
|
||||
// There is more than one question mark in the URL. This can happen if any of the params is a URL with params.
|
||||
// We only want to treat the first level of params, so we'll remove this second list of params and restore it later.
|
||||
questionMarkSplit.splice(0, 2);
|
||||
|
||||
subParams = '?' + questionMarkSplit.join('?');
|
||||
urlAndHash[0] = urlAndHash[0].replace(subParams, subParamsPlaceholder);
|
||||
}
|
||||
|
||||
urlAndHash[0].replace(regex, (match: string, key: string, value: string): string => {
|
||||
params[key] = value !== undefined ? CoreTextUtils.decodeURIComponent(value) : '';
|
||||
|
||||
if (subParams) {
|
||||
params[key] = params[key].replace(subParamsPlaceholder, subParams);
|
||||
}
|
||||
|
||||
return match;
|
||||
});
|
||||
|
||||
if (urlAndHash.length > 1) {
|
||||
// Remove the URL from the array.
|
||||
urlAndHash.shift();
|
||||
|
||||
// Add the hash as a param with a special name. Use a join in case there is more than one #.
|
||||
params.urlHash = urlAndHash.join('#');
|
||||
}
|
||||
|
||||
return params;
|
||||
extractUrlParams(url: string): CoreUrlParamsNew {
|
||||
return CoreUrl.extractUrlParams(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,40 +95,10 @@ export class CoreUrlUtilsProvider {
|
|||
* @param siteUrl The URL of the site the URL belongs to.
|
||||
* @param accessKey User access key for tokenpluginfile.
|
||||
* @returns Fixed URL.
|
||||
* @deprecated since 4.5. Use CoreUrl.fixPluginfileURL instead.
|
||||
*/
|
||||
fixPluginfileURL(url: string, token: string, siteUrl: string, accessKey?: string): string {
|
||||
if (!url) {
|
||||
return '';
|
||||
}
|
||||
|
||||
url = url.replace(/&/g, '&');
|
||||
|
||||
const canUseTokenPluginFile = accessKey && this.canUseTokenPluginFile(url, siteUrl, accessKey);
|
||||
|
||||
// First check if we need to fix this url or is already fixed.
|
||||
if (!canUseTokenPluginFile && url.indexOf('token=') != -1) {
|
||||
return url;
|
||||
}
|
||||
|
||||
// Check if is a valid URL (contains the pluginfile endpoint) and belongs to the site.
|
||||
if (!this.isPluginFileUrl(url) || url.indexOf(CoreTextUtils.addEndingSlash(siteUrl)) !== 0) {
|
||||
return url;
|
||||
}
|
||||
|
||||
if (canUseTokenPluginFile) {
|
||||
// Use tokenpluginfile.php.
|
||||
url = url.replace(/(\/webservice)?\/pluginfile\.php/, '/tokenpluginfile.php/' + accessKey);
|
||||
} else {
|
||||
// Use pluginfile.php. Some webservices returns directly the correct download url, others not.
|
||||
if (url.indexOf(CorePath.concatenatePaths(siteUrl, 'pluginfile.php')) === 0) {
|
||||
url = url.replace('/pluginfile', '/webservice/pluginfile');
|
||||
}
|
||||
|
||||
url = this.addParamsToUrl(url, { token });
|
||||
}
|
||||
|
||||
// Always send offline=1 (it's for external repositories).
|
||||
return this.addParamsToUrl(url, { offline: '1', lang: CoreLang.getCurrentLanguageSync(CoreLangFormat.LMS) });
|
||||
return CoreUrl.fixPluginfileURL(url, token, siteUrl, accessKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -220,54 +106,26 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url The url to be formatted.
|
||||
* @returns Fromatted url.
|
||||
* @deprecated since 4.5. Use CoreUrl.formatURL instead.
|
||||
*/
|
||||
formatURL(url: string): string {
|
||||
url = url.trim();
|
||||
|
||||
// Check if the URL starts by http or https.
|
||||
if (! /^http(s)?:\/\/.*/i.test(url)) {
|
||||
// Test first allways https.
|
||||
url = 'https://' + url;
|
||||
}
|
||||
|
||||
// http always in lowercase.
|
||||
url = url.replace(/^http/i, 'http');
|
||||
url = url.replace(/^https/i, 'https');
|
||||
|
||||
// Replace last slash.
|
||||
url = url.replace(/\/$/, '');
|
||||
|
||||
return url;
|
||||
return CoreUrl.formatURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL to the documentation of the app, based on Moodle version and current language.
|
||||
*
|
||||
* @param release Moodle release.
|
||||
* The URL has been simplified and always returns the English version of the latest version of Moodle
|
||||
* to simplify the circular dependencies.
|
||||
*
|
||||
* @param release Moodle release. Unused.
|
||||
* @param page Docs page to go to.
|
||||
* @returns Promise resolved with the Moodle docs URL.
|
||||
*
|
||||
* @deprecated since 4.5. You can use CoreAuthenticatedSite.getDocsUrl but is also deprecated.
|
||||
*/
|
||||
async getDocsUrl(release?: string, page: string = 'Mobile_app'): Promise<string> {
|
||||
let docsUrl = 'https://docs.moodle.org/en/' + page;
|
||||
|
||||
if (release !== undefined) {
|
||||
const version = CoreSites.getMajorReleaseNumber(release).replace('.', '');
|
||||
|
||||
// Check is a valid number.
|
||||
if (Number(version) >= 24) {
|
||||
// Append release number.
|
||||
docsUrl = docsUrl.replace('https://docs.moodle.org/', 'https://docs.moodle.org/' + version + '/');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
let lang = await CoreLang.getCurrentLanguage(CoreLangFormat.LMS);
|
||||
lang = CoreLang.getParentLanguage() || lang;
|
||||
|
||||
return docsUrl.replace('/en/', '/' + lang + '/');
|
||||
} catch (error) {
|
||||
return docsUrl;
|
||||
}
|
||||
return 'https://docs.moodle.org/en/' + page;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -275,53 +133,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url URL
|
||||
* @returns Youtube Embed Video URL or undefined if not found.
|
||||
* @deprecated since 4.5. Use CoreUrl.getYoutubeEmbedUrl instead.
|
||||
*/
|
||||
getYoutubeEmbedUrl(url?: string): string | void {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
let videoId = '';
|
||||
const params: CoreUrlParams = {};
|
||||
|
||||
url = CoreTextUtils.decodeHTML(url);
|
||||
|
||||
// Get the video ID.
|
||||
let match = url.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/);
|
||||
|
||||
if (match && match[2].length === 11) {
|
||||
videoId = match[2];
|
||||
}
|
||||
|
||||
// No videoId, do not continue.
|
||||
if (!videoId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now get the playlist (if any).
|
||||
match = url.match(/[?&]list=([^#&?]+)/);
|
||||
|
||||
if (match && match[1]) {
|
||||
params.list = match[1];
|
||||
}
|
||||
|
||||
// Now get the start time (if any).
|
||||
match = url.match(/[?&]start=(\d+)/);
|
||||
|
||||
if (match && match[1]) {
|
||||
params.start = parseInt(match[1], 10).toString();
|
||||
} else {
|
||||
// No start param, but it could have a time param.
|
||||
match = url.match(/[?&]t=(\d+h)?(\d+m)?(\d+s)?/);
|
||||
if (match) {
|
||||
const start = (match[1] ? parseInt(match[1], 10) * 3600 : 0) +
|
||||
(match[2] ? parseInt(match[2], 10) * 60 : 0) +
|
||||
(match[3] ? parseInt(match[3], 10) : 0);
|
||||
params.start = start.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return this.addParamsToUrl('https://www.youtube.com/embed/' + videoId, params);
|
||||
return CoreUrl.getYoutubeEmbedUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,15 +146,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url URL to treat.
|
||||
* @returns Last file without params.
|
||||
* @deprecated since 4.5. Use CoreUrl.getLastFileWithoutParams instead.
|
||||
*/
|
||||
getLastFileWithoutParams(url: string): string {
|
||||
const parsedUrl = CoreUrl.parse(url);
|
||||
if (!parsedUrl) {
|
||||
return '';
|
||||
}
|
||||
const path = parsedUrl.path ?? '';
|
||||
|
||||
return path.split('/').pop() ?? '';
|
||||
return CoreUrl.getLastFileWithoutParams(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -348,17 +158,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url URL to treat.
|
||||
* @returns Protocol, undefined if no protocol found.
|
||||
* @todo Use CoreUrl.parse
|
||||
* @deprecated since 4.5. Use CoreUrl.getUrlProtocol instead.
|
||||
*/
|
||||
getUrlProtocol(url: string): string | void {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matches = url.match(/^([^/:.?]*):\/\//);
|
||||
if (matches && matches[1]) {
|
||||
return matches[1];
|
||||
}
|
||||
return CoreUrl.getUrlProtocol(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -367,36 +170,21 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url URL to treat.
|
||||
* @returns Scheme, undefined if no scheme found.
|
||||
* @deprecated since 4.5. Use CoreUrl.getUrlProtocol instead.
|
||||
*/
|
||||
getUrlScheme(url: string): string | void {
|
||||
if (!url) {
|
||||
return;
|
||||
return CoreUrl.getUrlProtocol(url);
|
||||
}
|
||||
|
||||
const matches = url.match(/^([a-z][a-z0-9+\-.]*):/);
|
||||
if (matches && matches[1]) {
|
||||
return matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Gets a username from a URL like: user@mysite.com.
|
||||
*
|
||||
* @param url URL to treat.
|
||||
* @returns Username. Undefined if no username found.
|
||||
* @todo Use CoreUrl.parse
|
||||
* @deprecated since 4.5. Use CoreUrl.getUsernameFromUrl instead.
|
||||
*/
|
||||
getUsernameFromUrl(url: string): string | undefined {
|
||||
if (url.indexOf('@') > -1) {
|
||||
// Get URL without protocol.
|
||||
const withoutProtocol = url.replace(/^[^?@/]*:\/\//, '');
|
||||
const matches = withoutProtocol.match(/[^@]*/);
|
||||
|
||||
// Make sure that @ is at the start of the URL, not in a param at the end.
|
||||
if (matches && matches.length && !matches[0].match(/[/|?]/)) {
|
||||
return matches[0];
|
||||
}
|
||||
}
|
||||
return CoreUrl.getUsernameFromUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -404,9 +192,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url The url to test against the pattern.
|
||||
* @returns Whether the url is absolute.
|
||||
* @deprecated since 4.5. Use CoreUrl.isAbsoluteURL instead.
|
||||
*/
|
||||
isAbsoluteURL(url: string): boolean {
|
||||
return /^[^:]{2,}:\/\//i.test(url) || /^(tel:|mailto:|geo:)/.test(url);
|
||||
return CoreUrl.isAbsoluteURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -414,9 +203,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url The URL to test.
|
||||
* @returns Whether the URL is downloadable.
|
||||
* @deprecated since 4.5. Use CoreUrl.isDownloadableUrl instead.
|
||||
*/
|
||||
isDownloadableUrl(url: string): boolean {
|
||||
return this.isPluginFileUrl(url) || this.isTokenPluginFileUrl(url) || this.isThemeImageUrl(url) || this.isGravatarUrl(url);
|
||||
return CoreUrl.isDownloadableUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -424,9 +214,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url The URL to test.
|
||||
* @returns Whether the URL is a gravatar URL.
|
||||
* @deprecated since 4.5. Use CoreUrl.isGravatarUrl instead.
|
||||
*/
|
||||
isGravatarUrl(url: string): boolean {
|
||||
return url?.indexOf('gravatar.com/avatar') !== -1;
|
||||
return CoreUrl.isGravatarUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -434,10 +225,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url The url to test.
|
||||
* @returns Whether the url uses http or https protocol.
|
||||
* @todo Use CoreUrl.parse
|
||||
* @deprecated since 4.5. Use CoreUrl.isHttpURL instead.
|
||||
*/
|
||||
isHttpURL(url: string): boolean {
|
||||
return /^https?:\/\/.+/i.test(url);
|
||||
return CoreUrl.isHttpURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -445,11 +236,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url URL to check.
|
||||
* @returns Whether the URL belongs to a local file.
|
||||
* @deprecated since 4.5. Use CoreUrl.isLocalFileUrl instead.
|
||||
*/
|
||||
isLocalFileUrl(url: string): boolean {
|
||||
const urlParts = CoreUrl.parse(url);
|
||||
|
||||
return this.isLocalFileUrlScheme(urlParts?.protocol || '', urlParts?.domain || '');
|
||||
return CoreUrl.isLocalFileUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -457,18 +247,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param scheme Scheme to check.
|
||||
* @returns Whether the scheme belongs to a local file.
|
||||
* @deprecated since 4.5. Use CoreUrl.isLocalFileUrlScheme instead.
|
||||
*/
|
||||
isLocalFileUrlScheme(scheme: string, domain: string): boolean {
|
||||
if (!scheme) {
|
||||
return false;
|
||||
}
|
||||
scheme = scheme.toLowerCase();
|
||||
|
||||
return scheme == 'cdvfile' ||
|
||||
scheme == 'file' ||
|
||||
scheme == 'filesystem' ||
|
||||
scheme == CoreConstants.CONFIG.ioswebviewscheme ||
|
||||
(CorePlatform.isMobile() && scheme === 'http' && domain === 'localhost'); // @todo Get served domain from ENV.
|
||||
return CoreUrl.isLocalFileUrlScheme(scheme, domain);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -476,9 +258,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url The URL to test.
|
||||
* @returns Whether the URL is a pluginfile URL.
|
||||
* @deprecated since 4.5. Use CoreUrl.isPluginFileUrl instead.
|
||||
*/
|
||||
isPluginFileUrl(url: string): boolean {
|
||||
return url.indexOf('/pluginfile.php') !== -1;
|
||||
return CoreUrl.isPluginFileUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -486,9 +269,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url The URL to test.
|
||||
* @returns Whether the URL is a tokenpluginfile URL.
|
||||
* @deprecated since 4.5. Use CoreUrl.isTokenPluginFileUrl instead.
|
||||
*/
|
||||
isTokenPluginFileUrl(url: string): boolean {
|
||||
return url.indexOf('/tokenpluginfile.php') !== -1;
|
||||
return CoreUrl.isTokenPluginFileUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -497,13 +281,10 @@ export class CoreUrlUtilsProvider {
|
|||
* @param imageUrl The URL to test.
|
||||
* @param siteUrl The Site Url.
|
||||
* @returns Whether the URL is a theme image URL.
|
||||
* @deprecated since 4.5. Use CoreUrl.isThemeImageUrl instead.
|
||||
*/
|
||||
isThemeImageUrl(imageUrl: string, siteUrl?: string): boolean {
|
||||
if (siteUrl) {
|
||||
return imageUrl.startsWith(`${siteUrl}/theme/image.php`);
|
||||
}
|
||||
|
||||
return imageUrl?.indexOf('/theme/image.php') !== -1;
|
||||
return CoreUrl.isThemeImageUrl(imageUrl, siteUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -513,57 +294,10 @@ export class CoreUrlUtilsProvider {
|
|||
* @param param Param to get from the URL.
|
||||
* @param siteUrl Site URL.
|
||||
* @returns Param from the URL.
|
||||
* @deprecated since 4.5. Use CoreUrl.getThemeImageUrlParam instead.
|
||||
*/
|
||||
getThemeImageUrlParam(imageUrl: string, param: string, siteUrl?: string): string {
|
||||
if (!this.isThemeImageUrl(imageUrl, siteUrl)) {
|
||||
// Cannot be guessed.
|
||||
return '';
|
||||
}
|
||||
|
||||
const matches = imageUrl.match('/theme/image.php/(.*)');
|
||||
if (matches?.[1]) {
|
||||
// Slash arguments found.
|
||||
const slasharguments = matches[1].split('/');
|
||||
|
||||
if (slasharguments.length < 4) {
|
||||
// Image not found, malformed URL.
|
||||
return '';
|
||||
}
|
||||
|
||||
// Join from the third element to the end.
|
||||
const image = slasharguments.slice(3).join('/');
|
||||
switch (param) {
|
||||
case 'theme':
|
||||
return slasharguments[0];
|
||||
case 'component':
|
||||
return slasharguments[1];
|
||||
case 'rev':
|
||||
return slasharguments[2];
|
||||
case 'image':
|
||||
// Remove possible url params.
|
||||
return CoreUrlUtils.removeUrlParams(image);
|
||||
default:
|
||||
return CoreUrlUtils.extractUrlParams(image)[param] || '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// URL arguments found.
|
||||
const iconParams = CoreUrlUtils.extractUrlParams(imageUrl);
|
||||
|
||||
switch (param) {
|
||||
case 'theme':
|
||||
return iconParams[param] || 'standard';
|
||||
case 'component':
|
||||
return iconParams[param] || 'core';
|
||||
case 'rev':
|
||||
return iconParams[param] || '-1';
|
||||
case 'svg':
|
||||
return iconParams[param] || '1';
|
||||
case 'image':
|
||||
default:
|
||||
return iconParams[param] || '';
|
||||
}
|
||||
return CoreUrl.getThemeImageUrlParam(imageUrl, param, siteUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -571,14 +305,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url URL to treat.
|
||||
* @returns Treated URL.
|
||||
* @deprecated since 4.5. Use CoreUrl.removeUrlParts(url, [CoreUrlPartNames.Protocol, CoreUrlPartNames.WWWInDomain]) instead.
|
||||
*/
|
||||
removeProtocolAndWWW(url: string): string {
|
||||
// Remove protocol.
|
||||
url = url.replace(/^.*?:\/\//, '');
|
||||
// Remove www.
|
||||
url = url.replace(/^www./, '');
|
||||
|
||||
return url;
|
||||
return CoreUrl.removeUrlParts(url, [CoreUrlPartNames.Protocol, CoreUrlPartNames.WWWInDomain]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -586,11 +316,10 @@ export class CoreUrlUtilsProvider {
|
|||
*
|
||||
* @param url URL to treat.
|
||||
* @returns URL without params.
|
||||
* @deprecated since 4.5. Use CoreUrl.removeUrlParts(url, [CoreUrlPartNames.Query, CoreUrlPartNames.Fragment]) instead.
|
||||
*/
|
||||
removeUrlParams(url: string): string {
|
||||
const matches = url.match(/^[^?]+/);
|
||||
|
||||
return matches ? matches[0] : '';
|
||||
return CoreUrl.removeUrlParts(url, [CoreUrlPartNames.Query, CoreUrlPartNames.Fragment]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -599,33 +328,16 @@ export class CoreUrlUtilsProvider {
|
|||
* @param url The url to be fixed.
|
||||
* @param siteUrl The URL of the site the URL belongs to.
|
||||
* @returns Modified URL.
|
||||
* @deprecated since 4.5. Use CoreUrl.unfixPluginfileURL instead.
|
||||
*/
|
||||
unfixPluginfileURL(url: string, siteUrl?: string): string {
|
||||
if (!url) {
|
||||
return '';
|
||||
}
|
||||
|
||||
url = url.replace(/&/g, '&');
|
||||
|
||||
// It site URL is supplied, check if the URL belongs to the site.
|
||||
if (siteUrl && url.indexOf(CoreTextUtils.addEndingSlash(siteUrl)) !== 0) {
|
||||
return url;
|
||||
}
|
||||
|
||||
// Check tokenpluginfile first.
|
||||
url = url.replace(/\/tokenpluginfile\.php\/[^/]+\//, '/pluginfile.php/');
|
||||
|
||||
// Treat webservice/pluginfile case.
|
||||
url = url.replace(/\/webservice\/pluginfile\.php\//, '/pluginfile.php/');
|
||||
|
||||
// Make sure the URL doesn't contain the token.
|
||||
url = url.replace(/([?&])token=[^&]*&?/, '$1');
|
||||
|
||||
return url;
|
||||
return CoreUrl.unfixPluginfileURL(url, siteUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const CoreUrlUtils = makeSingleton(CoreUrlUtilsProvider);
|
||||
|
||||
export type CoreUrlParams = {[key: string]: string};
|
||||
/**
|
||||
* @deprecated since 4.5. Use CoreUrlParams on CoreUrl instead.
|
||||
*/
|
||||
export type CoreUrlParams = CoreUrlParamsNew;
|
||||
|
|
|
@ -37,7 +37,7 @@ import { CoreFilepool } from '@services/filepool';
|
|||
import { CoreSites } from '@services/sites';
|
||||
import { CoreCancellablePromise } from '@classes/cancellable-promise';
|
||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { CoreUrlUtils } from './url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { QRScanner } from '@features/native/plugins';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
import { CoreText } from '@singletons/text';
|
||||
|
@ -1114,7 +1114,7 @@ export class CoreUtilsProvider {
|
|||
|
||||
CoreAnalytics.logEvent({
|
||||
type: CoreAnalyticsEventType.OPEN_LINK,
|
||||
link: CoreUrlUtils.unfixPluginfileURL(options.originalUrl ?? url),
|
||||
link: CoreUrl.unfixPluginfileURL(options.originalUrl ?? url),
|
||||
});
|
||||
|
||||
return this.iabInstance;
|
||||
|
@ -1172,7 +1172,7 @@ export class CoreUtilsProvider {
|
|||
*/
|
||||
async openInBrowser(url: string, options: CoreUtilsOpenInBrowserOptions = {}): Promise<void> {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const originaUrl = CoreUrlUtils.unfixPluginfileURL(options.originalUrl ?? options.browserWarningUrl ?? url);
|
||||
const originaUrl = CoreUrl.unfixPluginfileURL(options.originalUrl ?? options.browserWarningUrl ?? url);
|
||||
if (options.showBrowserWarning || options.showBrowserWarning === undefined) {
|
||||
try {
|
||||
await CoreWindow.confirmOpenBrowserIfNeeded(originaUrl);
|
||||
|
@ -1217,7 +1217,7 @@ export class CoreUtilsProvider {
|
|||
|
||||
CoreAnalytics.logEvent({
|
||||
type: CoreAnalyticsEventType.OPEN_LINK,
|
||||
link: CoreUrlUtils.unfixPluginfileURL(url),
|
||||
link: CoreUrl.unfixPluginfileURL(url),
|
||||
});
|
||||
|
||||
return;
|
||||
|
|
|
@ -14,10 +14,75 @@
|
|||
|
||||
import { mock } from '@/testing/utils';
|
||||
import { CoreSite } from '@classes/sites/site';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
|
||||
|
||||
describe('CoreUrl singleton', () => {
|
||||
|
||||
it('adds www if missing', () => {
|
||||
const originalUrl = 'https://moodle.org';
|
||||
const url = CoreUrl.addOrRemoveWWW(originalUrl);
|
||||
|
||||
expect(url).toEqual('https://www.moodle.org');
|
||||
});
|
||||
|
||||
it('removes www if present', () => {
|
||||
const originalUrl = 'https://www.moodle.org';
|
||||
const url = CoreUrl.addOrRemoveWWW(originalUrl);
|
||||
|
||||
expect(url).toEqual('https://moodle.org');
|
||||
});
|
||||
|
||||
it('adds params to URL without params', () => {
|
||||
const originalUrl = 'https://moodle.org';
|
||||
const params = {
|
||||
first: '1',
|
||||
second: '2',
|
||||
};
|
||||
const url = CoreUrl.addParamsToUrl(originalUrl, params);
|
||||
|
||||
expect(url).toEqual('https://moodle.org?first=1&second=2');
|
||||
});
|
||||
|
||||
it('adds params to URL with existing params', () => {
|
||||
const originalUrl = 'https://moodle.org?existing=1';
|
||||
const params = {
|
||||
first: '1',
|
||||
second: '2',
|
||||
};
|
||||
const url = CoreUrl.addParamsToUrl(originalUrl, params);
|
||||
|
||||
expect(url).toEqual('https://moodle.org?existing=1&first=1&second=2');
|
||||
});
|
||||
|
||||
it('doesn\'t change URL if no params supplied', () => {
|
||||
const originalUrl = 'https://moodle.org';
|
||||
const url = CoreUrl.addParamsToUrl(originalUrl);
|
||||
|
||||
expect(url).toEqual(originalUrl);
|
||||
});
|
||||
|
||||
it('doesn\'t add undefined or null params', () => {
|
||||
const originalUrl = 'https://moodle.org';
|
||||
const url = CoreUrl.addParamsToUrl(originalUrl, {
|
||||
foo: undefined,
|
||||
bar: null,
|
||||
baz: 1,
|
||||
});
|
||||
|
||||
expect(url).toEqual('https://moodle.org?baz=1');
|
||||
});
|
||||
|
||||
it('adds anchor to URL', () => {
|
||||
const originalUrl = 'https://moodle.org';
|
||||
const params = {
|
||||
first: '1',
|
||||
second: '2',
|
||||
};
|
||||
const url = CoreUrl.addParamsToUrl(originalUrl, params, 'myanchor');
|
||||
|
||||
expect(url).toEqual('https://moodle.org?first=1&second=2#myanchor');
|
||||
});
|
||||
|
||||
it('parses standard urls', () => {
|
||||
expect(CoreUrl.parse('https://u1:pw1@my.subdomain.com/path/?query=search#hash')).toEqual({
|
||||
protocol: 'https',
|
||||
|
@ -83,9 +148,34 @@ describe('CoreUrl singleton', () => {
|
|||
});
|
||||
|
||||
it('removes protocol', () => {
|
||||
expect(CoreUrl.removeProtocol('https://school.edu')).toEqual('school.edu');
|
||||
expect(CoreUrl.removeProtocol('ftp://school.edu')).toEqual('school.edu');
|
||||
expect(CoreUrl.removeProtocol('school.edu')).toEqual('school.edu');
|
||||
expect(CoreUrl.removeUrlParts('https://school.edu', CoreUrlPartNames.Protocol)).toEqual('school.edu');
|
||||
expect(CoreUrl.removeUrlParts('ftp://school.edu', CoreUrlPartNames.Protocol)).toEqual('school.edu');
|
||||
expect(CoreUrl.removeUrlParts('school.edu', CoreUrlPartNames.Protocol)).toEqual('school.edu');
|
||||
});
|
||||
|
||||
it('removes protocol and www', () => {
|
||||
expect(CoreUrl.removeUrlParts('https://www.school.edu', [CoreUrlPartNames.Protocol, CoreUrlPartNames.WWWInDomain]))
|
||||
.toEqual('school.edu');
|
||||
expect(CoreUrl.removeUrlParts('ftp://school.edu', [CoreUrlPartNames.Protocol, CoreUrlPartNames.WWWInDomain]))
|
||||
.toEqual('school.edu');
|
||||
expect(CoreUrl.removeUrlParts('www.school.edu', [CoreUrlPartNames.Protocol, CoreUrlPartNames.WWWInDomain]))
|
||||
.toEqual('school.edu');
|
||||
// Test that it works in a different order.
|
||||
expect(CoreUrl.removeUrlParts('https://www.school.edu', [CoreUrlPartNames.WWWInDomain, CoreUrlPartNames.Protocol]))
|
||||
.toEqual('school.edu');
|
||||
expect(CoreUrl.removeUrlParts('ftp://school.edu', [CoreUrlPartNames.WWWInDomain, CoreUrlPartNames.Protocol]))
|
||||
.toEqual('school.edu');
|
||||
expect(CoreUrl.removeUrlParts('www.school.edu', [CoreUrlPartNames.WWWInDomain, CoreUrlPartNames.Protocol]))
|
||||
.toEqual('school.edu');
|
||||
});
|
||||
|
||||
it('removes params', () => {
|
||||
expect(CoreUrl.removeUrlParts('https://www.school.edu?blabla#a', [CoreUrlPartNames.Query, CoreUrlPartNames.Fragment]))
|
||||
.toEqual('https://www.school.edu');
|
||||
expect(CoreUrl.removeUrlParts('ftp://school.edu?blabla=r#a', [CoreUrlPartNames.Query, CoreUrlPartNames.Fragment]))
|
||||
.toEqual('ftp://school.edu');
|
||||
expect(CoreUrl.removeUrlParts('www.school.edu?blabla=5&gg=3', [CoreUrlPartNames.Query, CoreUrlPartNames.Fragment]))
|
||||
.toEqual('www.school.edu');
|
||||
});
|
||||
|
||||
it('compares domains and paths', () => {
|
||||
|
@ -108,9 +198,21 @@ describe('CoreUrl singleton', () => {
|
|||
});
|
||||
|
||||
it('removes the anchor of a URL', () => {
|
||||
expect(CoreUrl.removeUrlAnchor('https://school.edu#foo')).toEqual('https://school.edu');
|
||||
expect(CoreUrl.removeUrlAnchor('https://school.edu#foo#bar')).toEqual('https://school.edu');
|
||||
expect(CoreUrl.removeUrlAnchor('https://school.edu')).toEqual('https://school.edu');
|
||||
expect(CoreUrl.removeUrlParts('https://school.edu#foo', CoreUrlPartNames.Fragment)).toEqual('https://school.edu');
|
||||
expect(CoreUrl.removeUrlParts('https://school.edu#foo#bar', CoreUrlPartNames.Fragment)).toEqual('https://school.edu');
|
||||
expect(CoreUrl.removeUrlParts('https://school.edu', CoreUrlPartNames.Fragment)).toEqual('https://school.edu');
|
||||
});
|
||||
|
||||
it('gets the username from a URL', () => {
|
||||
expect(CoreUrl.getUsernameFromUrl(
|
||||
'https://username@domain.com?token=TOKEN&privatetoken=PRIVATETOKEN&redirect=http://domain.com/course/view.php?id=2',
|
||||
)).toEqual('username');
|
||||
expect(CoreUrl.getUsernameFromUrl(
|
||||
'https://username:password@domain.com?token=TOKEN&privatetoken=PRIVATETOKEN&redirect=http://domain.com/course/',
|
||||
)).toEqual('username');
|
||||
expect(CoreUrl.getUsernameFromUrl(
|
||||
'https://domain.com?token=TOKEN&privatetoken=PRIVATETOKEN&redirect=http://domain.com/course/view.php?id=2',
|
||||
)).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('converts to absolute URLs', () => {
|
||||
|
|
|
@ -16,6 +16,12 @@ import { CoreSite } from '@classes/sites/site';
|
|||
import { CorePath } from './path';
|
||||
import { CoreText } from './text';
|
||||
|
||||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreConstants } from '../constants';
|
||||
import { CoreMedia } from './media';
|
||||
import { CoreLang, CoreLangFormat } from '@services/lang';
|
||||
|
||||
/**
|
||||
* Parts contained within a url.
|
||||
*/
|
||||
|
@ -68,6 +74,13 @@ interface UrlParts {
|
|||
|
||||
}
|
||||
|
||||
export const enum CoreUrlPartNames {
|
||||
Protocol = 'protocol',
|
||||
WWWInDomain = 'www', // Will remove starting www from domain.
|
||||
Query = 'query',
|
||||
Fragment = 'fragment',
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton with helper functions for urls.
|
||||
*/
|
||||
|
@ -85,8 +98,9 @@ export class CoreUrl {
|
|||
* @returns Url parts.
|
||||
*/
|
||||
static parse(url: string): UrlParts | null {
|
||||
url = url.trim();
|
||||
// Parse url with regular expression taken from RFC 3986: https://tools.ietf.org/html/rfc3986#appendix-B.
|
||||
const match = url.trim().match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/);
|
||||
const match = url.match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/);
|
||||
|
||||
if (!match) {
|
||||
return null;
|
||||
|
@ -120,8 +134,12 @@ export class CoreUrl {
|
|||
* @returns Assembled URL.
|
||||
*/
|
||||
static assemble(parts: UrlParts): string {
|
||||
return (parts.protocol ? `${parts.protocol}://` : '') +
|
||||
(parts.credentials ? `${parts.credentials}@` : '') +
|
||||
const protocol = parts.protocol;
|
||||
const credentials = parts.credentials ||
|
||||
(parts.password ? `${parts.username}:${parts.password}` : parts.username);
|
||||
|
||||
return (protocol ? `${protocol}://` : '') +
|
||||
(credentials ? `${credentials}@` : '') +
|
||||
(parts.domain ?? '') +
|
||||
(parts.port ? `:${parts.port}` : '') +
|
||||
(parts.path ?? '') +
|
||||
|
@ -190,9 +208,10 @@ export class CoreUrl {
|
|||
*
|
||||
* @param url Site url.
|
||||
* @returns Url without protocol.
|
||||
* @deprecated since 4.5. Use CoreUrl.removeUrlParts(url, CoreUrlPartNames.Protocol) instead.
|
||||
*/
|
||||
static removeProtocol(url: string): string {
|
||||
return url.replace(/^[a-zA-Z]+:\/\//i, '');
|
||||
return CoreUrl.removeUrlParts(url, CoreUrlPartNames.Protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,12 +248,9 @@ export class CoreUrl {
|
|||
* @returns Anchor, undefined if no anchor.
|
||||
*/
|
||||
static getUrlAnchor(url: string): string | undefined {
|
||||
const firstAnchorIndex = url.indexOf('#');
|
||||
if (firstAnchorIndex === -1) {
|
||||
return;
|
||||
}
|
||||
const urlParts = CoreUrl.parse(url);
|
||||
|
||||
return url.substring(firstAnchorIndex);
|
||||
return urlParts?.fragment ? `#${urlParts.fragment}` : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -242,11 +258,11 @@ export class CoreUrl {
|
|||
*
|
||||
* @param url URL.
|
||||
* @returns URL without anchor if any.
|
||||
*
|
||||
* @deprecated since 4.5. Use CoreUrl.removeUrlParts(url, CoreUrlPartNames.Fragment) instead.
|
||||
*/
|
||||
static removeUrlAnchor(url: string): string {
|
||||
const urlAndAnchor = url.split('#');
|
||||
|
||||
return urlAndAnchor[0];
|
||||
return CoreUrl.removeUrlParts(url, CoreUrlPartNames.Fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -290,13 +306,13 @@ export class CoreUrl {
|
|||
* @returns Relative URL.
|
||||
*/
|
||||
static toRelativeURL(parentUrl: string, url: string): string {
|
||||
parentUrl = CoreUrl.removeProtocol(parentUrl);
|
||||
parentUrl = CoreUrl.removeUrlParts(parentUrl, CoreUrlPartNames.Protocol);
|
||||
|
||||
if (!url.includes(parentUrl)) {
|
||||
return url; // Already relative URL.
|
||||
}
|
||||
|
||||
return CoreText.removeStartingSlash(CoreUrl.removeProtocol(url).replace(parentUrl, ''));
|
||||
return CoreText.removeStartingSlash(CoreUrl.removeUrlParts(url, CoreUrlPartNames.Protocol).replace(parentUrl, ''));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -344,4 +360,564 @@ export class CoreUrl {
|
|||
return newUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or remove 'www' from a URL. The url needs to have http or https protocol.
|
||||
*
|
||||
* @param url URL to modify.
|
||||
* @returns Modified URL.
|
||||
*/
|
||||
static addOrRemoveWWW(url: string): string {
|
||||
if (url) {
|
||||
if (url.match(/http(s)?:\/\/www\./)) {
|
||||
// Already has www. Remove it.
|
||||
url = url.replace('www.', '');
|
||||
} else {
|
||||
url = url.replace('https://', 'https://www.');
|
||||
url = url.replace('http://', 'http://www.');
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add params to a URL.
|
||||
*
|
||||
* @param url URL to add the params to.
|
||||
* @param params Object with the params to add.
|
||||
* @param anchor Anchor text if needed.
|
||||
* @param boolToNumber Whether to convert bools to 1 or 0.
|
||||
* @returns URL with params.
|
||||
*/
|
||||
static addParamsToUrl(url: string, params?: Record<string, unknown>, anchor?: string, boolToNumber?: boolean): string {
|
||||
// Remove any existing anchor to add the params before it.
|
||||
const urlAndAnchor = url.split('#');
|
||||
url = urlAndAnchor[0];
|
||||
|
||||
let separator = url.indexOf('?') !== -1 ? '&' : '?';
|
||||
|
||||
for (const key in params) {
|
||||
let value = params[key];
|
||||
|
||||
if (boolToNumber && typeof value === 'boolean') {
|
||||
// Convert booleans to 1 or 0.
|
||||
value = value ? '1' : '0';
|
||||
}
|
||||
|
||||
// Ignore objects and undefined.
|
||||
if (typeof value !== 'object' && value !== undefined) {
|
||||
url += separator + key + '=' + value;
|
||||
separator = '&';
|
||||
}
|
||||
}
|
||||
|
||||
// Re-add the anchor if any.
|
||||
if (urlAndAnchor.length > 1) {
|
||||
// Remove the URL from the array.
|
||||
urlAndAnchor.shift();
|
||||
|
||||
// Use a join in case there is more than one #.
|
||||
url += '#' + urlAndAnchor.join('#');
|
||||
}
|
||||
|
||||
if (anchor) {
|
||||
url += '#' + anchor;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a URL and a text, return an HTML link.
|
||||
*
|
||||
* @param url URL.
|
||||
* @param text Text of the link.
|
||||
* @returns Link.
|
||||
*/
|
||||
static buildLink(url: string, text: string): string {
|
||||
return '<a href="' + url + '">' + text + '</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we can use tokenpluginfile.php endpoint for a certain URL.
|
||||
*
|
||||
* @param url URL to check.
|
||||
* @param siteUrl The URL of the site the URL belongs to.
|
||||
* @param accessKey User access key for tokenpluginfile.
|
||||
* @returns Whether tokenpluginfile.php can be used.
|
||||
*/
|
||||
static canUseTokenPluginFile(url: string, siteUrl: string, accessKey?: string): boolean {
|
||||
// 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).
|
||||
return !CoreConstants.CONFIG.disableTokenFile && !!accessKey && !url.match(/[&?]file=/) && (
|
||||
url.indexOf(CorePath.concatenatePaths(siteUrl, 'pluginfile.php')) === 0 ||
|
||||
url.indexOf(CorePath.concatenatePaths(siteUrl, 'webservice/pluginfile.php')) === 0) &&
|
||||
!CoreMedia.sourceUsesJavascriptPlayer({ src: url });
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the parameters from a URL and stores them in an object.
|
||||
*
|
||||
* @param url URL to treat.
|
||||
* @returns Object with the params.
|
||||
*/
|
||||
static extractUrlParams(url: string): CoreUrlParams {
|
||||
const regex = /[?&]+([^=&]+)=?([^&]*)?/gi;
|
||||
const subParamsPlaceholder = '@@@SUBPARAMS@@@';
|
||||
const params: CoreUrlParams = {};
|
||||
const urlAndHash = url.split('#');
|
||||
const questionMarkSplit = urlAndHash[0].split('?');
|
||||
let subParams: string;
|
||||
|
||||
if (questionMarkSplit.length > 2) {
|
||||
// There is more than one question mark in the URL. This can happen if any of the params is a URL with params.
|
||||
// We only want to treat the first level of params, so we'll remove this second list of params and restore it later.
|
||||
questionMarkSplit.splice(0, 2);
|
||||
|
||||
subParams = '?' + questionMarkSplit.join('?');
|
||||
urlAndHash[0] = urlAndHash[0].replace(subParams, subParamsPlaceholder);
|
||||
}
|
||||
|
||||
urlAndHash[0].replace(regex, (match: string, key: string, value: string): string => {
|
||||
params[key] = value !== undefined ? CoreTextUtils.decodeURIComponent(value) : '';
|
||||
|
||||
if (subParams) {
|
||||
params[key] = params[key].replace(subParamsPlaceholder, subParams);
|
||||
}
|
||||
|
||||
return match;
|
||||
});
|
||||
|
||||
if (urlAndHash.length > 1) {
|
||||
// Remove the URL from the array.
|
||||
urlAndHash.shift();
|
||||
|
||||
// Add the hash as a param with a special name. Use a join in case there is more than one #.
|
||||
params.urlHash = urlAndHash.join('#');
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic function for adding the wstoken to Moodle urls and for pointing to the correct script.
|
||||
* For download remote files from Moodle we need to use the special /webservice/pluginfile passing
|
||||
* the ws token as a get parameter.
|
||||
*
|
||||
* @param url The url to be fixed.
|
||||
* @param token Token to use.
|
||||
* @param siteUrl The URL of the site the URL belongs to.
|
||||
* @param accessKey User access key for tokenpluginfile.
|
||||
* @returns Fixed URL.
|
||||
*/
|
||||
static fixPluginfileURL(url: string, token: string, siteUrl: string, accessKey?: string): string {
|
||||
if (!url) {
|
||||
return '';
|
||||
}
|
||||
|
||||
url = url.replace(/&/g, '&');
|
||||
|
||||
const canUseTokenPluginFile = accessKey && CoreUrl.canUseTokenPluginFile(url, siteUrl, accessKey);
|
||||
|
||||
// First check if we need to fix this url or is already fixed.
|
||||
if (!canUseTokenPluginFile && url.indexOf('token=') != -1) {
|
||||
return url;
|
||||
}
|
||||
|
||||
// Check if is a valid URL (contains the pluginfile endpoint) and belongs to the site.
|
||||
if (!CoreUrl.isPluginFileUrl(url) || url.indexOf(CoreTextUtils.addEndingSlash(siteUrl)) !== 0) {
|
||||
return url;
|
||||
}
|
||||
|
||||
if (canUseTokenPluginFile) {
|
||||
// Use tokenpluginfile.php.
|
||||
url = url.replace(/(\/webservice)?\/pluginfile\.php/, '/tokenpluginfile.php/' + accessKey);
|
||||
} else {
|
||||
// Use pluginfile.php. Some webservices returns directly the correct download url, others not.
|
||||
if (url.indexOf(CorePath.concatenatePaths(siteUrl, 'pluginfile.php')) === 0) {
|
||||
url = url.replace('/pluginfile', '/webservice/pluginfile');
|
||||
}
|
||||
|
||||
url = CoreUrl.addParamsToUrl(url, { token });
|
||||
}
|
||||
|
||||
// Always send offline=1 (it's for external repositories).
|
||||
return CoreUrl.addParamsToUrl(url, { offline: '1', lang: CoreLang.getCurrentLanguageSync(CoreLangFormat.LMS) });
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a URL, trim, lowercase, etc...
|
||||
*
|
||||
* @param url The url to be formatted.
|
||||
* @returns Fromatted url.
|
||||
*/
|
||||
static formatURL(url: string): string {
|
||||
url = url.trim();
|
||||
|
||||
// Check if the URL starts by http or https.
|
||||
if (! /^http(s)?:\/\/.*/i.test(url)) {
|
||||
// Test first allways https.
|
||||
url = 'https://' + url;
|
||||
}
|
||||
|
||||
// http always in lowercase.
|
||||
url = url.replace(/^http/i, 'http');
|
||||
url = url.replace(/^https/i, 'https');
|
||||
|
||||
// Replace last slash.
|
||||
url = url.replace(/\/$/, '');
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Youtube Embed Video URL or undefined if not found.
|
||||
*
|
||||
* @param url URL
|
||||
* @returns Youtube Embed Video URL or undefined if not found.
|
||||
*/
|
||||
static getYoutubeEmbedUrl(url?: string): string | void {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
let videoId = '';
|
||||
const params: CoreUrlParams = {};
|
||||
|
||||
url = CoreTextUtils.decodeHTML(url);
|
||||
|
||||
// Get the video ID.
|
||||
let match = url.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/);
|
||||
|
||||
if (match && match[2].length === 11) {
|
||||
videoId = match[2];
|
||||
}
|
||||
|
||||
// No videoId, do not continue.
|
||||
if (!videoId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now get the playlist (if any).
|
||||
match = url.match(/[?&]list=([^#&?]+)/);
|
||||
|
||||
if (match && match[1]) {
|
||||
params.list = match[1];
|
||||
}
|
||||
|
||||
// Now get the start time (if any).
|
||||
match = url.match(/[?&]start=(\d+)/);
|
||||
|
||||
if (match && match[1]) {
|
||||
params.start = parseInt(match[1], 10).toString();
|
||||
} else {
|
||||
// No start param, but it could have a time param.
|
||||
match = url.match(/[?&]t=(\d+h)?(\d+m)?(\d+s)?/);
|
||||
if (match) {
|
||||
const start = (match[1] ? parseInt(match[1], 10) * 3600 : 0) +
|
||||
(match[2] ? parseInt(match[2], 10) * 60 : 0) +
|
||||
(match[3] ? parseInt(match[3], 10) : 0);
|
||||
params.start = start.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return CoreUrl.addParamsToUrl('https://www.youtube.com/embed/' + videoId, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a URL, returns what's after the last '/' without params.
|
||||
* Example:
|
||||
* http://mysite.com/a/course.html?id=1 -> course.html
|
||||
*
|
||||
* @param url URL to treat.
|
||||
* @returns Last file without params.
|
||||
*/
|
||||
static getLastFileWithoutParams(url: string): string {
|
||||
const parsedUrl = CoreUrl.parse(url);
|
||||
if (!parsedUrl) {
|
||||
return '';
|
||||
}
|
||||
const path = parsedUrl.path ?? '';
|
||||
|
||||
return path.split('/').pop() ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the protocol from a URL.
|
||||
* E.g. http://www.google.com returns 'http'.
|
||||
*
|
||||
* @param url URL to treat.
|
||||
* @returns Protocol, undefined if no protocol found.
|
||||
*/
|
||||
static getUrlProtocol(url: string): string | void {
|
||||
return CoreUrl.parse(url)?.protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a username from a URL like: user@mysite.com.
|
||||
*
|
||||
* @param url URL to treat.
|
||||
* @returns Username. Undefined if no username found.
|
||||
* @todo Use CoreUrl.parse. It cannot use it right now because it won't detect username on custom URL with double protocol.
|
||||
*/
|
||||
static getUsernameFromUrl(url: string): string | undefined {
|
||||
if (url.indexOf('@') < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get URL without protocol.
|
||||
const withoutProtocol = url.replace(/^[^?@/]*:\/\//, '');
|
||||
const matches = withoutProtocol.match(/[^@]*/);
|
||||
|
||||
// Make sure that @ is at the start of the URL, not in a param at the end.
|
||||
if (matches && matches.length && !matches[0].match(/[/|?]/)) {
|
||||
const credentials = matches[0];
|
||||
|
||||
return credentials.split(':')[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a URL has any protocol (not a relative URL).
|
||||
*
|
||||
* @param url The url to test against the pattern.
|
||||
* @returns Whether the url is absolute.
|
||||
*/
|
||||
static isAbsoluteURL(url: string): boolean {
|
||||
return /^[^:]{2,}:\/\//i.test(url) || /^(tel:|mailto:|geo:)/.test(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a URL is downloadable: plugin file OR theme/image.php OR gravatar.
|
||||
*
|
||||
* @param url The URL to test.
|
||||
* @returns Whether the URL is downloadable.
|
||||
*/
|
||||
static isDownloadableUrl(url: string): boolean {
|
||||
return CoreUrl.isPluginFileUrl(url) ||
|
||||
CoreUrl.isTokenPluginFileUrl(url) ||
|
||||
CoreUrl.isThemeImageUrl(url) ||
|
||||
CoreUrl.isGravatarUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a URL is a gravatar URL.
|
||||
*
|
||||
* @param url The URL to test.
|
||||
* @returns Whether the URL is a gravatar URL.
|
||||
*/
|
||||
static isGravatarUrl(url: string): boolean {
|
||||
return url?.indexOf('gravatar.com/avatar') !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a URL uses http or https protocol.
|
||||
*
|
||||
* @param url The url to test.
|
||||
* @returns Whether the url uses http or https protocol.
|
||||
* @todo Use CoreUrl.parse
|
||||
*/
|
||||
static isHttpURL(url: string): boolean {
|
||||
return /^https?:\/\/.+/i.test(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an URL belongs to a local file.
|
||||
*
|
||||
* @param url URL to check.
|
||||
* @returns Whether the URL belongs to a local file.
|
||||
*/
|
||||
static isLocalFileUrl(url: string): boolean {
|
||||
const urlParts = CoreUrl.parse(url);
|
||||
|
||||
return CoreUrl.isLocalFileUrlScheme(urlParts?.protocol || '', urlParts?.domain || '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a URL scheme belongs to a local file.
|
||||
*
|
||||
* @param scheme Scheme to check.
|
||||
* @returns Whether the scheme belongs to a local file.
|
||||
*/
|
||||
static isLocalFileUrlScheme(scheme: string, domain: string): boolean {
|
||||
if (!scheme) {
|
||||
return false;
|
||||
}
|
||||
scheme = scheme.toLowerCase();
|
||||
|
||||
return scheme === 'cdvfile' ||
|
||||
scheme === 'file' ||
|
||||
scheme === 'filesystem' ||
|
||||
scheme === CoreConstants.CONFIG.ioswebviewscheme ||
|
||||
(CorePlatform.isMobile() && scheme === 'http' && domain === 'localhost'); // @todo Get served domain from ENV.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a URL is a pluginfile URL.
|
||||
*
|
||||
* @param url The URL to test.
|
||||
* @returns Whether the URL is a pluginfile URL.
|
||||
*/
|
||||
static isPluginFileUrl(url: string): boolean {
|
||||
return url.indexOf('/pluginfile.php') !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a URL is a tokenpluginfile URL.
|
||||
*
|
||||
* @param url The URL to test.
|
||||
* @returns Whether the URL is a tokenpluginfile URL.
|
||||
*/
|
||||
static isTokenPluginFileUrl(url: string): boolean {
|
||||
return url.indexOf('/tokenpluginfile.php') !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a URL is a theme image URL.
|
||||
*
|
||||
* @param imageUrl The URL to test.
|
||||
* @param siteUrl The Site Url.
|
||||
* @returns Whether the URL is a theme image URL.
|
||||
*/
|
||||
static isThemeImageUrl(imageUrl: string, siteUrl?: string): boolean {
|
||||
if (siteUrl) {
|
||||
return imageUrl.startsWith(`${siteUrl}/theme/image.php`);
|
||||
}
|
||||
|
||||
return imageUrl?.indexOf('/theme/image.php') !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an specific param from an image URL.
|
||||
*
|
||||
* @param imageUrl Image Url
|
||||
* @param param Param to get from the URL.
|
||||
* @param siteUrl Site URL.
|
||||
* @returns Param from the URL.
|
||||
*/
|
||||
static getThemeImageUrlParam(imageUrl: string, param: string, siteUrl?: string): string {
|
||||
if (!CoreUrl.isThemeImageUrl(imageUrl, siteUrl)) {
|
||||
// Cannot be guessed.
|
||||
return '';
|
||||
}
|
||||
|
||||
const matches = imageUrl.match('/theme/image.php/(.*)');
|
||||
if (matches?.[1]) {
|
||||
// Slash arguments found.
|
||||
const slasharguments = matches[1].split('/');
|
||||
|
||||
if (slasharguments.length < 4) {
|
||||
// Image not found, malformed URL.
|
||||
return '';
|
||||
}
|
||||
|
||||
// Join from the third element to the end.
|
||||
const image = slasharguments.slice(3).join('/');
|
||||
switch (param) {
|
||||
case 'theme':
|
||||
return slasharguments[0];
|
||||
case 'component':
|
||||
return slasharguments[1];
|
||||
case 'rev':
|
||||
return slasharguments[2];
|
||||
case 'image':
|
||||
// Remove possible url params.
|
||||
return CoreUrl.removeUrlParts(image, [CoreUrlPartNames.Query, CoreUrlPartNames.Fragment]);
|
||||
default:
|
||||
return CoreUrl.extractUrlParams(image)[param] || '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// URL arguments found.
|
||||
const iconParams = CoreUrl.extractUrlParams(imageUrl);
|
||||
|
||||
switch (param) {
|
||||
case 'theme':
|
||||
return iconParams[param] || 'standard';
|
||||
case 'component':
|
||||
return iconParams[param] || 'core';
|
||||
case 'rev':
|
||||
return iconParams[param] || '-1';
|
||||
case 'svg':
|
||||
return iconParams[param] || '1';
|
||||
case 'image':
|
||||
default:
|
||||
return iconParams[param] || '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL without the desired parts.
|
||||
*
|
||||
* @param url URL to treat.
|
||||
* @param parts Parts to remove.
|
||||
* @returns URL without the parts.
|
||||
*/
|
||||
static removeUrlParts(url: string, parts: CoreUrlPartNames | CoreUrlPartNames[]): string {
|
||||
if (!url) {
|
||||
return url;
|
||||
}
|
||||
|
||||
if (!Array.isArray(parts)) {
|
||||
parts = [parts];
|
||||
}
|
||||
|
||||
parts.forEach((part) => {
|
||||
switch (part) {
|
||||
case CoreUrlPartNames.WWWInDomain:
|
||||
// Remove www, no protocol.
|
||||
url = url.replace(/^www./, '');
|
||||
// Remove www, with protocol.
|
||||
url = url.replace(/\/\/www./, '//');
|
||||
break;
|
||||
case CoreUrlPartNames.Protocol:
|
||||
// Remove the protocol from url
|
||||
url = url.replace(/^.*?:\/\//, '');
|
||||
break;
|
||||
case CoreUrlPartNames.Query:
|
||||
url = url.match(/^[^?]+/)?.[0] || '';
|
||||
break;
|
||||
case CoreUrlPartNames.Fragment:
|
||||
url = url.split('#')[0];
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies a pluginfile URL to use the default pluginfile script instead of the webservice one.
|
||||
*
|
||||
* @param url The url to be fixed.
|
||||
* @param siteUrl The URL of the site the URL belongs to.
|
||||
* @returns Modified URL.
|
||||
*/
|
||||
static unfixPluginfileURL(url: string, siteUrl?: string): string {
|
||||
if (!url) {
|
||||
return '';
|
||||
}
|
||||
|
||||
url = url.replace(/&/g, '&');
|
||||
|
||||
// It site URL is supplied, check if the URL belongs to the site.
|
||||
if (siteUrl && url.indexOf(CoreTextUtils.addEndingSlash(siteUrl)) !== 0) {
|
||||
return url;
|
||||
}
|
||||
|
||||
// Check tokenpluginfile first.
|
||||
url = url.replace(/\/tokenpluginfile\.php\/[^/]+\//, '/pluginfile.php/');
|
||||
|
||||
// Treat webservice/pluginfile case.
|
||||
url = url.replace(/\/webservice\/pluginfile\.php\//, '/pluginfile.php/');
|
||||
|
||||
// Make sure the URL doesn't contain the token.
|
||||
url = url.replace(/([?&])token=[^&]*&?/, '$1');
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export type CoreUrlParams = {[key: string]: string};
|
||||
|
|
|
@ -18,7 +18,7 @@ import { CoreConfig } from '@services/config';
|
|||
import { CoreFileHelper } from '@services/file-helper';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreConstants } from '../constants';
|
||||
|
@ -40,7 +40,7 @@ export class CoreWindow {
|
|||
* @returns Promise resolved if confirmed, rejected if rejected.
|
||||
*/
|
||||
static async confirmOpenBrowserIfNeeded(url: string): Promise<void> {
|
||||
if (!CoreUrlUtils.isHttpURL(url)) {
|
||||
if (!CoreUrl.isHttpURL(url)) {
|
||||
// Only ask confirm for http(s), other cases usually launch external apps.
|
||||
return;
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ export class CoreWindow {
|
|||
* @returns Promise resolved when done.
|
||||
*/
|
||||
static async open(url: string, name?: string): Promise<void> {
|
||||
if (CoreUrlUtils.isLocalFileUrl(url)) {
|
||||
if (CoreUrl.isLocalFileUrl(url)) {
|
||||
const filename = url.substring(url.lastIndexOf('/') + 1);
|
||||
|
||||
if (!CoreFileHelper.isOpenableInApp({ filename })) {
|
||||
|
|
Loading…
Reference in New Issue