MOBILE-4653 utils: Move object and array related utils functions

main
Pau Ferrer Ocaña 2024-11-15 13:11:50 +01:00
parent 453a2bd8c2
commit 96f3be2ff1
73 changed files with 657 additions and 379 deletions

View File

@ -19,7 +19,7 @@ import { CoreBlockBaseComponent } from '@features/block/classes/base-block-compo
import { CoreSites } from '@services/sites';
import { ContextLevel, CoreConstants } from '@/core/constants';
import { Translate } from '@singletons';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreNavigator } from '@services/navigator';
import { CoreCourseHelper } from '@features/course/services/course-helper';
import { CoreUrl } from '@singletons/url';
@ -106,7 +106,7 @@ export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent i
});
// Sort the modnames alphabetically.
modFullNames = CoreUtils.sortValues(modFullNames);
modFullNames = CoreObject.sortValues(modFullNames);
for (const modName in modFullNames) {
const iconModName = modName === 'resources' ? 'page' : modName;

View File

@ -22,7 +22,7 @@ import { CoreFileEntry, CoreFileHelper } from '@services/file-helper';
import { CoreNetwork } from '@services/network';
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
import { makeSingleton } from '@singletons';
import { AddonBlogOffline, AddonBlogOfflineEntry } from './blog-offline';
@ -63,7 +63,7 @@ export class AddonBlogProvider {
* @returns Cache key.
*/
getEntriesCacheKey(filter: AddonBlogFilter = {}): string {
return ROOT_CACHE_KEY + CoreUtils.sortAndStringify(filter);
return ROOT_CACHE_KEY + CoreObject.sortAndStringify(filter);
}
/**
@ -77,7 +77,7 @@ export class AddonBlogProvider {
const site = await CoreSites.getSite(options?.siteId);
const data: CoreBlogGetEntriesWSParams = {
filters: CoreUtils.objectToArrayOfObjects(filter, 'name', 'value'),
filters: CoreObject.toArrayOfObjects(filter, 'name', 'value'),
page: options?.page ?? 0,
perpage: AddonBlogProvider.ENTRIES_PER_PAGE,
};
@ -290,7 +290,7 @@ export class AddonBlogProvider {
const site = await CoreSites.getSite(siteId);
const data: AddonBlogViewEntriesWSParams = {
filters: CoreUtils.objectToArrayOfObjects(filter, 'name', 'value'),
filters: CoreObject.toArrayOfObjects(filter, 'name', 'value'),
};
return site.write('core_blog_view_entries', data);

View File

@ -29,7 +29,7 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import {
AddonCalendar,
AddonCalendarWeek,
@ -464,7 +464,7 @@ class AddonCalendarMonthSlidesItemsManagerSource extends CoreSwipeSlidesDynamicI
const categories = await CoreCourses.getCategories(0, true);
// Index categories by ID.
this.categories = CoreUtils.arrayToObject(categories, 'id');
this.categories = CoreArray.toObject(categories, 'id');
} catch {
// Ignore errors.
}

View File

@ -14,7 +14,7 @@
import { Component, Input, OnInit } from '@angular/core';
import { CoreEnrolledCourseData } from '@features/courses/services/courses';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { ModalController } from '@singletons';
import { CoreEvents } from '@singletons/events';
import { AddonCalendarFilter } from '@addons/calendar/services/calendar-helper';
@ -54,7 +54,7 @@ export class AddonCalendarFilterComponent implements OnInit {
sortedCourses: CoreEnrolledCourseData[] = [];
constructor() {
CoreUtils.enumKeys(AddonCalendarEventType).forEach((name) => {
CoreObject.enumKeys(AddonCalendarEventType).forEach((name) => {
const value = AddonCalendarEventType[name];
this.typeIcons[value] = AddonCalendarEventIcons[name];
this.types.push(value);

View File

@ -33,7 +33,7 @@ import { NgZone, Translate } from '@singletons';
import { CoreNavigator } from '@services/navigator';
import { Params } from '@angular/router';
import { Subscription } from 'rxjs';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreConstants } from '@/core/constants';
import { CoreSwipeSlidesDynamicItemsManager } from '@classes/items-management/swipe-slides-dynamic-items-manager';
import { CoreSwipeSlidesComponent } from '@components/swipe-slides/swipe-slides';
@ -58,6 +58,7 @@ import {
ADDON_CALENDAR_UNDELETED_EVENT_EVENT,
AddonCalendarEventType,
} from '@addons/calendar/constants';
import { CoreObject } from '@singletons/object';
/**
* Page that displays the calendar events for a certain day.
@ -221,7 +222,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
ngOnInit(): void {
const types: string[] = [];
CoreUtils.enumKeys(AddonCalendarEventType).forEach((name) => {
CoreObject.enumKeys(AddonCalendarEventType).forEach((name) => {
const value = AddonCalendarEventType[name];
this.filter[name] = CoreNavigator.getRouteBooleanParam(name) ?? true;
types.push(value);
@ -606,7 +607,7 @@ class AddonCalendarDaySlidesItemsManagerSource extends CoreSwipeSlidesDynamicIte
const categories = await CoreCourses.getCategories(0, true);
// Index categories by ID.
this.categories = CoreUtils.arrayToObject(categories, 'id');
this.categories = CoreArray.toObject(categories, 'id');
} catch {
// Ignore errors.
}

View File

@ -25,7 +25,7 @@ import {
AddonCalendarWeekDay,
} from './calendar';
import { CoreConfig } from '@services/config';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreCourse } from '@features/course/services/course';
import { ContextLevel, CoreConstants } from '@/core/constants';
import moment from 'moment-timezone';
@ -61,7 +61,7 @@ export class AddonCalendarHelperProvider {
*/
getEventIcon(eventType: AddonCalendarEventType | string): string {
if (this.eventTypeIcons.length == 0) {
CoreUtils.enumKeys(AddonCalendarEventType).forEach((name) => {
CoreObject.enumKeys(AddonCalendarEventType).forEach((name) => {
const value = AddonCalendarEventType[name];
this.eventTypeIcons[value] = AddonCalendarEventIcons[name];
});

View File

@ -15,7 +15,7 @@
import { Injectable } from '@angular/core';
import { SQLiteDBRecordValues } from '@classes/sqlitedb';
import { CoreSites } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { makeSingleton } from '@singletons';
import { AddonCalendarSubmitCreateUpdateFormDataWSParams } from './calendar';
import {
@ -62,7 +62,7 @@ export class AddonCalendarOfflineProvider {
const result = await Promise.all(promises);
return CoreUtils.mergeArraysWithoutDuplicates(result[0], result[1]);
return CoreArray.mergeWithoutDuplicates(result[0], result[1]);
}
/**

View File

@ -19,7 +19,7 @@ import { CoreNetwork } from '@services/network';
import { CoreText } from '@singletons/text';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUrl } from '@singletons/url';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreGroups } from '@services/groups';
import { CoreLocalNotifications } from '@services/local-notifications';
import { CoreConfig } from '@services/config';
@ -1578,7 +1578,7 @@ export class AddonCalendarProvider {
}
const params: AddonCalendarSubmitCreateUpdateFormWSParams = {
formdata: CoreUtils.objectToGetParams(formData),
formdata: CoreObject.toGetParams(formData),
};
const result =
await site.write<AddonCalendarSubmitCreateUpdateFormWSResponse>('core_calendar_submit_create_update_form', params);

View File

@ -27,7 +27,7 @@ import {
AddonModAssignSubmissionStatusValues,
} from './assign';
import { AddonModAssignOffline } from './assign-offline';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreFile } from '@services/file';
import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
import { CoreGroups } from '@services/groups';
@ -314,7 +314,7 @@ export class AddonModAssignHelperProvider {
await Promise.all(promises);
return CoreUtils.objectToArray(participantsIndexed);
return CoreObject.toArray(participantsIndexed);
}
/**

View File

@ -23,7 +23,7 @@ import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreText } from '@singletons/text';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { Translate } from '@singletons';
import {
AddonModBBB,
@ -146,7 +146,7 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
const recordingsTable = await AddonModBBB.getRecordings(this.bbb.id, this.groupId, {
cmId: this.module.id,
});
const columns = CoreUtils.arrayToObject(recordingsTable.columns, 'key');
const columns = CoreArray.toObject(recordingsTable.columns, 'key');
this.recordings = recordingsTable.parsedData.map(recordingData => {
const details: RecordingDetail[] = [];

View File

@ -20,7 +20,7 @@ import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
import { CoreText } from '@singletons/text';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
import { makeSingleton, Translate } from '@singletons';
import { ADDON_MOD_BBB_COMPONENT } from '../constants';
@ -182,7 +182,7 @@ export class AddonModBBBService {
return {
...meetingInfo,
features: meetingInfo.features ? CoreUtils.objectToKeyValueMap(meetingInfo.features, 'name', 'isenabled') : undefined,
features: meetingInfo.features ? CoreObject.toKeyValueMap(meetingInfo.features, 'name', 'isenabled') : undefined,
};
}

View File

@ -26,7 +26,7 @@ import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import {
AddonModData,
@ -53,6 +53,7 @@ import {
} from '../../constants';
import { CoreModals } from '@services/modals';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreObject } from '@singletons/object';
const contentToken = '<!-- CORE-DATABASE-CONTENT-GOES-HERE -->';
@ -269,8 +270,8 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
const fields = await AddonModData.getFields(this.database.id, { cmId: this.module.id });
this.search.advanced = [];
this.fields = CoreUtils.arrayToObject(fields, 'id');
this.fieldsArray = CoreUtils.objectToArray(this.fields);
this.fields = CoreArray.toObject(fields, 'id');
this.fieldsArray = CoreObject.toArray(this.fields);
if (this.fieldsArray.length == 0) {
canSearch = false;
canAdd = false;

View File

@ -18,7 +18,7 @@ import { CoreTag } from '@features/tag/services/tag';
import { CoreSites } from '@services/sites';
import { CoreFormFields, CoreForms } from '@singletons/form';
import { CoreText } from '@singletons/text';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { ModalController } from '@singletons';
import {
AddonModDataField,
@ -89,7 +89,7 @@ export class AddonModDataSearchModalComponent implements OnInit {
this.searchForm.addControl('firstname', this.fb.control(this.advancedIndexed['firstname'] || ''));
this.searchForm.addControl('lastname', this.fb.control(this.advancedIndexed['lastname'] || ''));
this.fieldsArray = CoreUtils.objectToArray(this.fields);
this.fieldsArray = CoreObject.toArray(this.fields);
this.advancedSearch = this.renderAdvancedSearchFields();
}

View File

@ -46,6 +46,7 @@ import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
import { ADDON_MOD_DATA_COMPONENT, ADDON_MOD_DATA_ENTRY_CHANGED, AddonModDataTemplateType } from '../../constants';
import { CoreLoadings } from '@services/loadings';
import { CoreWSError } from '@classes/errors/wserror';
import { CoreArray } from '@singletons/array';
/**
* Page that displays the view edit page.
@ -180,7 +181,7 @@ export class AddonModDataEditPage implements OnInit {
this.cssClass = 'addon-data-entries-' + this.database.id;
this.fieldsArray = await AddonModData.getFields(this.database.id, { cmId: this.moduleId });
this.fields = CoreUtils.arrayToObject(this.fieldsArray, 'id');
this.fields = CoreArray.toObject(this.fieldsArray, 'id');
const entry = await AddonModDataHelper.fetchEntry(this.database, this.fieldsArray, this.entryId || 0);
this.entry = entry.entry;

View File

@ -22,7 +22,7 @@ import { CoreGroups, CoreGroupInfo } from '@services/groups';
import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { AddonModDataComponentsCompileModule } from '../../components/components-compile.module';
import {
@ -183,7 +183,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
this.title = this.database.name || this.title;
this.fieldsArray = await AddonModData.getFields(this.database.id, { cmId: this.moduleId });
this.fields = CoreUtils.arrayToObject(this.fieldsArray, 'id');
this.fields = CoreArray.toObject(this.fieldsArray, 'id');
await this.setEntryFromOffset();

View File

@ -26,7 +26,7 @@ import { CoreFileEntry } from '@services/file-helper';
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreSync, CoreSyncResult } from '@services/sync';
import { CoreErrorHelper } from '@services/error-helper';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { Translate, makeSingleton } from '@singletons';
import { CoreEvents } from '@singletons/events';
import { AddonModData, AddonModDataData } from './data';
@ -206,7 +206,7 @@ export class AddonModDataSyncProvider extends CoreCourseActivitySyncBaseProvider
offlineEntries[entry.entryid].push(entry);
});
const promises = CoreUtils.objectToArray(offlineEntries).map((entryActions) =>
const promises = CoreObject.toArray(offlineEntries).map((entryActions) =>
this.syncEntry(database, entryActions, result, siteId));
await Promise.all(promises);

View File

@ -22,7 +22,7 @@ import { CoreNetwork } from '@services/network';
import { CoreFileEntry } from '@services/file-helper';
import { CoreFilepool } from '@services/filepool';
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldsDelegate } from './data-fields-delegate';
@ -251,7 +251,7 @@ export class AddonModDataProvider {
*/
protected checkFields(fields: AddonModDataField[], contents: AddonModDataSubfieldData[]): AddonModDataFieldNotification[] {
const notifications: AddonModDataFieldNotification[] = [];
const contentsIndexed = CoreUtils.arrayToObjectMultiple(contents, 'fieldid');
const contentsIndexed = CoreArray.toObjectMultiple(contents, 'fieldid');
// App is offline, check required fields.
fields.forEach((field) => {
@ -741,7 +741,7 @@ export class AddonModDataProvider {
*/
protected formatEntryContents(entry: AddonModDataEntryWS): AddonModDataEntry {
return Object.assign(entry, {
contents: CoreUtils.arrayToObject(entry.contents, 'fieldid'),
contents: CoreArray.toObject(entry.contents, 'fieldid'),
});
}

View File

@ -20,7 +20,7 @@ import { CoreFilepool } from '@services/filepool';
import { CoreGroup, CoreGroups } from '@services/groups';
import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreWSFile } from '@services/ws';
import { makeSingleton } from '@singletons';
import { AddonModDataEntry, AddonModData, AddonModDataData } from '../data';
@ -63,7 +63,7 @@ export class AddonModDataPrefetchHandlerLazyService extends AddonModDataPrefetch
});
});
return CoreUtils.objectToArray(uniqueEntries);
return CoreObject.toArray(uniqueEntries);
}
/**
@ -133,7 +133,7 @@ export class AddonModDataPrefetchHandlerLazyService extends AddonModDataPrefetch
let files: CoreWSFile[] = [];
entries.forEach((entry) => {
CoreUtils.objectToArray(entry.contents).forEach((content) => {
CoreObject.toArray(entry.contents).forEach((content) => {
files = files.concat(<CoreWSFile[]>content.files);
});
});

View File

@ -46,6 +46,7 @@ import { CoreLoadings } from '@services/loadings';
import { CoreError } from '@classes/errors/error';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreWSError } from '@classes/errors/wserror';
import { CoreObject } from '@singletons/object';
/**
* Page that displays feedback form.
@ -158,7 +159,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
if (this.items && !this.completed && this.originalData) {
// Form submitted. Check if there is any change.
if (!CoreUtils.basicLeftCompare(responses, this.originalData, 3)) {
if (!CoreObject.basicLeftCompare(responses, this.originalData, 3)) {
await CoreDomUtils.showConfirm(Translate.instant('core.confirmcanceledit'));
}
}

View File

@ -19,7 +19,7 @@ import { CoreCourseLogHelper } from '@features/course/services/log-helper';
import { CoreNetwork } from '@services/network';
import { CoreFilepool } from '@services/filepool';
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreWSExternalFile, CoreWSExternalWarning, CoreWSStoredFile } from '@services/ws';
import { makeSingleton, Translate } from '@singletons';
import { AddonModFeedbackOffline } from './feedback-offline';
@ -170,7 +170,7 @@ export class AddonModFeedbackProvider {
// Merge all values into one array.
const offlineValuesArray = offlineResponses.reduce((array, entry) => {
const responses = <OfflineResponsesArray> CoreUtils.objectToArrayOfObjects(entry.responses, 'id', 'value');
const responses = <OfflineResponsesArray> CoreObject.toArrayOfObjects(entry.responses, 'id', 'value');
return array.concat(responses);
}, <OfflineResponsesArray> []).map((valueEntry) => {
@ -1228,7 +1228,7 @@ export class AddonModFeedbackProvider {
const params: AddonModFeedbackProcessPageWSParams = {
feedbackid: feedbackId,
page: page,
responses: CoreUtils.objectToArrayOfObjects(responses, 'name', 'value'),
responses: CoreObject.toArrayOfObjects(responses, 'name', 'value'),
goprevious: goPrevious,
};

View File

@ -63,6 +63,7 @@ import { CoreCourseContentsPage } from '@features/course/pages/contents/contents
import { CoreToasts } from '@services/toasts';
import { CoreLoadings } from '@services/loadings';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreObject } from '@singletons/object';
type SortType = 'flat-newest' | 'flat-oldest' | 'nested';
@ -463,7 +464,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
await Promise.all(convertPromises);
// Convert back to array.
onlinePosts = CoreUtils.objectToArray(onlinePostsMap);
onlinePosts = CoreObject.toArray(onlinePostsMap);
let posts = offlineReplies.concat(onlinePosts);

View File

@ -52,6 +52,7 @@ import {
import { CoreCacheUpdateFrequency } from '@/core/constants';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreWSError } from '@classes/errors/wserror';
import { CoreObject } from '@singletons/object';
declare module '@singletons/events' {
@ -221,7 +222,7 @@ export class AddonModForumProvider {
message: message,
// eslint-disable-next-line max-len
options: CoreUtils.objectToArrayOfObjects<AddonModForumAddDiscussionWSOptionsArray[0], AddonModForumAddDiscussionWSOptionsObject>(
options: CoreObject.toArrayOfObjects<AddonModForumAddDiscussionWSOptionsArray[0], AddonModForumAddDiscussionWSOptionsObject>(
options || {},
'name',
'value',
@ -1147,7 +1148,7 @@ export class AddonModForumProvider {
subject: subject,
message: message,
options: CoreUtils.objectToArrayOfObjects<
options: CoreObject.toArrayOfObjects<
AddonModForumAddDiscussionPostWSOptionsArray[0],
AddonModForumAddDiscussionPostWSOptionsObject
>(
@ -1277,7 +1278,7 @@ export class AddonModForumProvider {
}
});
CoreUser.storeUsers(CoreUtils.objectToArray(users));
CoreUser.storeUsers(CoreObject.toArray(users));
}
/**
@ -1332,7 +1333,7 @@ export class AddonModForumProvider {
subject: subject,
message: message,
options: CoreUtils.objectToArrayOfObjects<
options: CoreObject.toArrayOfObjects<
AddonModForumUpdateDiscussionPostWSOptionsArray[0],
AddonModForumUpdateDiscussionPostWSOptionsObject
>(

View File

@ -22,7 +22,7 @@ import { CoreRatingInfo } from '@features/rating/services/rating';
import { CoreTagItem } from '@features/tag/services/tag';
import { CoreNetwork } from '@services/network';
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
import { makeSingleton, Translate } from '@singletons';
import { CoreEvents } from '@singletons/events';
@ -911,7 +911,7 @@ export class AddonModGlossaryProvider {
concept: concept,
definition: definition,
definitionformat: 1,
options: CoreUtils.objectToArrayOfObjects(options || {}, 'name', 'value'),
options: CoreObject.toArrayOfObjects(options || {}, 'name', 'value'),
};
if (attachId) {
@ -955,7 +955,7 @@ export class AddonModGlossaryProvider {
concept: concept,
definition: definition,
definitionformat: 1,
options: CoreUtils.objectToArrayOfObjects(options || {}, 'name', 'value'),
options: CoreObject.toArrayOfObjects(options || {}, 'name', 'value'),
};
if (attachId) {

View File

@ -24,7 +24,7 @@ import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@
import { CoreSync } from '@services/sync';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUrl } from '@singletons/url';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreWSExternalFile } from '@services/ws';
import { ModalController, Translate } from '@singletons';
import { CoreEvents } from '@singletons/events';
@ -171,7 +171,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave {
if (this.question && !this.eolData && !this.processData && this.originalData) {
// Question shown. Check if there is any change.
if (!CoreUtils.basicLeftCompare(this.questionForm.getRawValue(), this.originalData, 3)) {
if (!CoreObject.basicLeftCompare(this.questionForm.getRawValue(), this.originalData, 3)) {
await CoreDomUtils.showConfirm(Translate.instant('core.confirmcanceledit'));
}
}

View File

@ -17,7 +17,7 @@ import { CoreSites } from '@services/sites';
import { CoreFormFields } from '@singletons/form';
import { CoreText } from '@singletons/text';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { makeSingleton } from '@singletons';
import {
AddonModLessonPageAttemptDBRecord,
@ -152,7 +152,7 @@ export class AddonModLessonOfflineProvider {
this.getLessonsFromEntries(lessons, pageAttempts || []);
this.getLessonsFromEntries(lessons, retakes || []);
return CoreUtils.objectToArray(lessons);
return CoreObject.toArray(lessons);
}
/**

View File

@ -37,6 +37,8 @@ import {
import { CoreGradeType } from '@features/grades/constants';
import { CoreCacheUpdateFrequency } from '@/core/constants';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreObject } from '@singletons/object';
import { CoreArray } from '@singletons/array';
declare module '@singletons/events' {
@ -286,7 +288,7 @@ export class AddonModLessonProvider {
const validPages = {};
let pageId = accessInfo.firstpageid;
viewedPagesIds = CoreUtils.mergeArraysWithoutDuplicates(viewedPagesIds, viewedContentPagesIds);
viewedPagesIds = CoreArray.mergeWithoutDuplicates(viewedPagesIds, viewedContentPagesIds);
// Filter out the following pages:
// - End of Cluster
@ -398,11 +400,11 @@ export class AddonModLessonProvider {
// The name was changed to "answer_editor" in 3.7. Before it was just "answer". Support both cases.
if (data['answer_editor[text]'] !== undefined) {
studentAnswer = data['answer_editor[text]'];
} else if (typeof data.answer_editor == 'object') {
} else if (typeof data.answer_editor === 'object') {
studentAnswer = (<{text: string}> data.answer_editor).text;
} else if (data['answer[text]'] !== undefined) {
studentAnswer = data['answer[text]'];
} else if (typeof data.answer == 'object') {
} else if (typeof data.answer === 'object') {
studentAnswer = (<{text: string}> data.answer).text;
} else {
studentAnswer = data.answer;
@ -3087,7 +3089,7 @@ export class AddonModLessonProvider {
const params: AddonModLessonProcessPageWSParams = {
lessonid: lessonId,
pageid: pageId,
data: CoreUtils.objectToArrayOfObjects<ProcessPageData>(data, 'name', 'value', true),
data: CoreObject.toArrayOfObjects<ProcessPageData>(data, 'name', 'value', true),
review: !!options.review,
};

View File

@ -53,6 +53,8 @@ import {
} from '../constants';
import { CoreIonicColorNames } from '@singletons/colors';
import { CoreCacheUpdateFrequency } from '@/core/constants';
import { CoreObject } from '@singletons/object';
import { CoreArray } from '@singletons/array';
declare module '@singletons/events' {
@ -227,7 +229,7 @@ export class AddonModQuizProvider {
const params: AddonModQuizGetAttemptDataWSParams = {
attemptid: attemptId,
page: page,
preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightData,
'name',
'value',
@ -550,7 +552,7 @@ export class AddonModQuizProvider {
const params: AddonModQuizGetAttemptSummaryWSParams = {
attemptid: attemptId,
preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightData,
'name',
'value',
@ -629,8 +631,8 @@ export class AddonModQuizProvider {
// Convert the arrays to objects with name -> value.
return {
someoptions: <Record<string, number>> CoreUtils.objectToKeyValueMap(response.someoptions, 'name', 'value'),
alloptions: <Record<string, number>> CoreUtils.objectToKeyValueMap(response.alloptions, 'name', 'value'),
someoptions: <Record<string, number>> CoreObject.toKeyValueMap(response.someoptions, 'name', 'value'),
alloptions: <Record<string, number>> CoreObject.toKeyValueMap(response.alloptions, 'name', 'value'),
warnings: response.warnings,
};
}
@ -1640,7 +1642,7 @@ export class AddonModQuizProvider {
const params: AddonModQuizViewAttemptWSParams = {
attemptid: attemptId,
page: page,
preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightData,
'name',
'value',
@ -1695,7 +1697,7 @@ export class AddonModQuizProvider {
): Promise<void> {
const params: AddonModQuizViewAttemptSummaryWSParams = {
attemptid: attemptId,
preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightData,
'name',
'value',
@ -1785,10 +1787,10 @@ export class AddonModQuizProvider {
const params: AddonModQuizProcessAttemptWSParams = {
attemptid: attemptId,
data: CoreUtils.objectToArrayOfObjects(data, 'name', 'value'),
data: CoreObject.toArrayOfObjects(data, 'name', 'value'),
finishattempt: !!finish,
timeup: !!timeUp,
preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightData,
'name',
'value',
@ -1834,7 +1836,7 @@ export class AddonModQuizProvider {
});
// Convert the question array to an object.
const questions = CoreUtils.arrayToObject(questionsArray, 'slot');
const questions = CoreArray.toObject(questionsArray, 'slot');
return AddonModQuizOffline.processAttempt(quiz, attempt, questions, data, finish, siteId);
}
@ -1939,8 +1941,8 @@ export class AddonModQuizProvider {
const params: AddonModQuizSaveAttemptWSParams = {
attemptid: attemptId,
data: CoreUtils.objectToArrayOfObjects(data, 'name', 'value'),
preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
data: CoreObject.toArrayOfObjects(data, 'name', 'value'),
preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightData,
'name',
'value',
@ -1995,7 +1997,7 @@ export class AddonModQuizProvider {
const params: AddonModQuizStartAttemptWSParams = {
quizid: quizId,
preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
preflightData,
'name',
'value',

View File

@ -22,7 +22,7 @@ import { IonContent } from '@ionic/angular';
import { CoreNavigator } from '@services/navigator';
import { CoreSync } from '@services/sync';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { Translate } from '@singletons';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { AddonModScormPrefetchHandler } from '../../services/handlers/prefetch';
@ -340,8 +340,8 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
this.grade = AddonModScorm.calculateScormGrade(scorm, onlineAttempts);
// Add the attempts to the SCORM in array format in ASC order, and format the grades.
this.onlineAttempts = CoreUtils.objectToArray(onlineAttempts);
this.offlineAttempts = CoreUtils.objectToArray(offlineAttempts);
this.onlineAttempts = CoreObject.toArray(onlineAttempts);
this.offlineAttempts = CoreObject.toArray(offlineAttempts);
this.onlineAttempts.sort((a, b) => a.num - b.num);
this.offlineAttempts.sort((a, b) => a.num - b.num);

View File

@ -23,7 +23,7 @@ import { CoreSync } from '@services/sync';
import { CoreText } from '@singletons/text';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUrl } from '@singletons/url';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreWS, CoreWSExternalFile, CoreWSExternalWarning, CoreWSFile, CoreWSPreSets } from '@services/ws';
import { makeSingleton, Translate } from '@singletons';
import { CoreEvents } from '@singletons/events';
@ -808,12 +808,12 @@ export class AddonModScormProvider {
response.data.forEach((sco) => {
data[sco.scoid] = {
scoid: sco.scoid,
defaultdata: <Record<string, AddonModScormDataValue>> CoreUtils.objectToKeyValueMap(
defaultdata: <Record<string, AddonModScormDataValue>> CoreObject.toKeyValueMap(
sco.defaultdata,
'element',
'value',
),
userdata: <Record<string, AddonModScormDataValue>> CoreUtils.objectToKeyValueMap(sco.userdata, 'element', 'value'),
userdata: <Record<string, AddonModScormDataValue>> CoreObject.toKeyValueMap(sco.userdata, 'element', 'value'),
};
});
@ -1114,7 +1114,7 @@ export class AddonModScormProvider {
}
if (response.options) {
const scormOptions = CoreUtils.objectToKeyValueMap(response.options, 'name', 'value');
const scormOptions = CoreObject.toKeyValueMap(response.options, 'name', 'value');
if (scormOptions.scormstandard) {
currentScorm.scormStandard = Number(scormOptions.scormstandard);

View File

@ -45,6 +45,7 @@ import { toBoolean } from '@/core/transforms/boolean';
import { CoreLoadings } from '@services/loadings';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreWSError } from '@classes/errors/wserror';
import { CoreObject } from '@singletons/object';
/**
* Component that displays workshop assessment strategy form.
@ -188,7 +189,7 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit, OnDe
// Override assessment plugins values.
this.data.assessment.form.current = AddonModWorkshop.parseFields(
CoreUtils.objectToArrayOfObjects(offlineData, 'name', 'value'),
CoreObject.toArrayOfObjects(offlineData, 'name', 'value'),
);
// Override offline files.

View File

@ -22,7 +22,7 @@ import { CoreGroupInfo, CoreGroups } from '@services/groups';
import { CoreNavigator } from '@services/navigator';
import { CorePlatform } from '@services/platform';
import { CoreModals } from '@services/modals';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { Subscription } from 'rxjs';
import {
@ -405,7 +405,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
const modalData = await CoreModals.openModal<boolean>({
component: AddonModWorkshopPhaseInfoModalComponent,
componentProps: {
phases: CoreUtils.objectToArray(this.phases),
phases: CoreObject.toArray(this.phases),
workshopPhase: this.workshop.phase,
externalUrl: this.module.url,
showSubmit: this.showSubmit,

View File

@ -20,7 +20,7 @@ import { CoreUser } from '@features/user/services/user';
import { CoreFilepool } from '@services/filepool';
import { CoreGroup, CoreGroups } from '@services/groups';
import { CoreSites, CoreSitesReadingStrategy, CoreSitesCommonWSOptions } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreWSExternalFile, CoreWSFile } from '@services/ws';
import { makeSingleton } from '@singletons';
import {
@ -248,7 +248,7 @@ export class AddonModWorkshopPrefetchHandlerLazyService extends AddonModWorkshop
});
});
return CoreUtils.objectToArray(uniqueGrades);
return CoreObject.toArray(uniqueGrades);
}
/**

View File

@ -20,7 +20,7 @@ import { CoreGradesMenuItem } from '@features/grades/services/grades-helper';
import { CoreNetwork } from '@services/network';
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
import { CoreTextFormat, defaultTextFormat } from '@singletons/text';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreStatusWithWarningsWSResponse, CoreWS, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
import { makeSingleton, Translate } from '@singletons';
import { CoreFormFields } from '@singletons/form';
@ -41,6 +41,7 @@ import {
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
import { CoreCacheUpdateFrequency } from '@/core/constants';
import { CoreWSError } from '@classes/errors/wserror';
import { CoreObject } from '@singletons/object';
declare module '@singletons/events' {
@ -366,7 +367,7 @@ export class AddonModWorkshopProvider {
const response = await site.read<AddonModWorkshopGetUserPlanWSResponse>('mod_workshop_get_user_plan', params, preSets);
return CoreUtils.arrayToObject(response.userplan.phases, 'code');
return CoreArray.toObject(response.userplan.phases, 'code');
}
/**
@ -1052,7 +1053,7 @@ export class AddonModWorkshopProvider {
warnings: response.warnings,
fields: this.parseFields(response.fields),
current: this.parseFields(response.current),
options: CoreUtils.objectToKeyValueMap<string>(response.options, 'name', 'value'),
options: CoreObject.toKeyValueMap<string>(response.options, 'name', 'value'),
};
}
@ -1183,7 +1184,7 @@ export class AddonModWorkshopProvider {
const params: AddonModWorkshopUpdateAssessmentWSParams = {
assessmentid: assessmentId,
data: CoreUtils.objectToArrayOfObjects(inputData, 'name', 'value'),
data: CoreObject.toArrayOfObjects(inputData, 'name', 'value'),
};
const response = await site.write<AddonModWorkshopUpdateAssessmentWSResponse>('mod_workshop_update_assessment', params);

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { makeSingleton } from '@singletons';
import { AddonMessageOutputDelegate } from '@addons/messageoutput/services/messageoutput-delegate';
import {
@ -53,7 +53,7 @@ export class AddonNotificationsHelperProvider {
formattedPreferences.components.forEach((component) => {
component.notifications.forEach((notification) => {
notification.processorsByName = CoreUtils.arrayToObject(notification.processors, 'name');
notification.processorsByName = CoreArray.toObject(notification.processors, 'name');
});
});

View File

@ -17,7 +17,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
import { CoreQuestionHandler } from '@features/question/services/question-delegate';
import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { makeSingleton } from '@singletons';
/**
@ -133,8 +133,8 @@ export class AddonQtypeCalculatedHandlerService implements CoreQuestionHandler {
prevAnswers: CoreQuestionsAnswers,
newAnswers: CoreQuestionsAnswers,
): boolean {
return CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer') &&
CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'unit');
return CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer') &&
CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'unit');
}
/**

View File

@ -24,7 +24,7 @@ import { CoreFileSession } from '@services/file-session';
import { CoreSites } from '@services/sites';
import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreText } from '@singletons/text';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreWSFile } from '@services/ws';
import { makeSingleton, Translate } from '@singletons';
import { CoreFileHelper } from '@services/file-helper';
@ -267,7 +267,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler {
// First check the inline text.
const answerIsEqual = allowedOptions.text ?
CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer') : true;
CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer') : true;
if (!allowedOptions.attachments || !uploadFilesSupported || !answerIsEqual) {
// No need to check attachments.

View File

@ -17,7 +17,7 @@ import { Injectable, Type } from '@angular/core';
import { AddonModQuizMultichoiceQuestion } from '@features/question/classes/base-question-component';
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
import { CoreQuestionHandler } from '@features/question/services/question-delegate';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { makeSingleton } from '@singletons';
/**
@ -120,7 +120,7 @@ export class AddonQtypeMultichoiceHandlerService implements CoreQuestionHandler
for (const name in newAnswers) {
if (name.indexOf('choice') !== -1) {
isSingle = false;
if (!CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, name)) {
if (!CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, name)) {
isMultiSame = false;
break;
}
@ -142,7 +142,7 @@ export class AddonQtypeMultichoiceHandlerService implements CoreQuestionHandler
* @returns Whether they're the same.
*/
isSameResponseSingle(prevAnswers: CoreQuestionsAnswers, newAnswers: CoreQuestionsAnswers): boolean {
return CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
return CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
}
/**

View File

@ -16,7 +16,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
import { CoreQuestionHandler } from '@features/question/services/question-delegate';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { makeSingleton } from '@singletons';
/**
@ -72,7 +72,7 @@ export class AddonQtypeShortAnswerHandlerService implements CoreQuestionHandler
prevAnswers: CoreQuestionsAnswers,
newAnswers: CoreQuestionsAnswers,
): boolean {
return CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
return CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
}
}

View File

@ -16,7 +16,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreQuestionHandler } from '@features/question/services/question-delegate';
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { AddonModQuizMultichoiceQuestion } from '@features/question/classes/base-question-component';
import { makeSingleton } from '@singletons';
@ -74,7 +74,7 @@ export class AddonQtypeTrueFalseHandlerService implements CoreQuestionHandler {
prevAnswers: CoreQuestionsAnswers,
newAnswers: CoreQuestionsAnswers,
): boolean {
return CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
return CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
}
/**

View File

@ -66,7 +66,7 @@ export class CoreInterceptor implements HttpInterceptor {
// Add the header and serialize the body if needed.
const newReq = req.clone({
headers: req.headers.set('Content-Type', 'application/x-www-form-urlencoded'),
body: typeof req.body == 'object' && String(req.body) != '[object File]' ?
body: typeof req.body === 'object' && String(req.body) != '[object File]' ?
CoreInterceptor.serialize(req.body) : req.body,
});

View File

@ -43,6 +43,8 @@ import { CoreSiteWSCacheRecord } from '@services/database/sites';
import { CoreErrorLogs } from '@singletons/error-logs';
import { CoreWait } from '@singletons/wait';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreObject } from '@singletons/object';
import { CoreArray } from '@singletons/array';
/**
* Class that represents a site (combination of site + user) where the user has authenticated but the site hasn't been validated
@ -212,7 +214,7 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite {
// Index function by name to speed up wsAvailable method.
if (infos?.functions) {
infos.functionsByName = CoreUtils.arrayToObject(infos.functions, 'name');
infos.functionsByName = CoreArray.toObject(infos.functions, 'name');
}
}
@ -1020,7 +1022,7 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite {
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
protected getCacheId(method: string, data: any): string {
return Md5.hashAsciiStr(method + ':' + CoreUtils.sortAndStringify(data));
return Md5.hashAsciiStr(method + ':' + CoreObject.sortAndStringify(data));
}
/**

View File

@ -15,7 +15,7 @@
import { OnInit, Input, Component, Optional, Inject, OnChanges, SimpleChanges } from '@angular/core';
import { CoreLogger } from '@singletons/logger';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreText } from '@singletons/text';
import { CoreCourseBlock } from '../../course/services/course';
import { Params } from '@angular/router';
@ -78,7 +78,7 @@ export abstract class CoreBlockBaseComponent implements OnInit, OnChanges, ICore
config.value = CoreText.parseJSON(config.value);
});
this.block.configsRecord = CoreUtils.arrayToObject(this.block.configs, 'name');
this.block.configsRecord = CoreArray.toObject(this.block.configs, 'name');
}
/**

View File

@ -47,6 +47,7 @@ import {
CORE_COURSE_PROGRESS_UPDATED_EVENT,
} from '@features/course/constants';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreObject } from '@singletons/object';
/**
* Page that displays the contents of a course.
@ -284,7 +285,7 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy, CoreRefreshCon
if ('courseformatoptions' in this.course && this.course.courseformatoptions) {
// Already loaded.
this.formatOptions = CoreUtils.objectToKeyValueMap(this.course.courseformatoptions, 'name', 'value');
this.formatOptions = CoreObject.toKeyValueMap(this.course.courseformatoptions, 'name', 'value');
return;
}
@ -294,7 +295,7 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy, CoreRefreshCon
course && Object.assign(this.course, course);
if (course?.courseformatoptions) {
this.formatOptions = CoreUtils.objectToKeyValueMap(course.courseformatoptions, 'name', 'value');
this.formatOptions = CoreObject.toKeyValueMap(course.courseformatoptions, 'name', 'value');
}
}

View File

@ -32,7 +32,7 @@ import { CoreLogger } from '@singletons/logger';
import { ApplicationInit, makeSingleton, Translate } from '@singletons';
import { CoreFilepool } from '@services/filepool';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import {
CoreCourseAnyCourseData,
CoreCourseBasicData,
@ -1088,7 +1088,7 @@ export class CoreCourseHelperProvider {
const totalOffline = offlineCompletions.length;
let loaded = 0;
const offlineCompletionsMap = CoreUtils.arrayToObject(offlineCompletions, 'cmid');
const offlineCompletionsMap = CoreArray.toObject(offlineCompletions, 'cmid');
const loadSectionOfflineCompletion = (section: CoreCourseWSSection): void => {
if (!section.contents || !section.contents.length) {

View File

@ -20,7 +20,6 @@ import { CoreEvents } from '@singletons/events';
import { CoreLogger } from '@singletons/logger';
import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreSite } from '@classes/sites/site';
import { CoreCacheUpdateFrequency, CoreConstants, DownloadStatus } from '@/core/constants';
import { makeSingleton, Translate } from '@singletons';
@ -75,6 +74,7 @@ import {
CORE_COURSE_STEALTH_MODULES_SECTION_ID,
} from '../constants';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreObject } from '@singletons/object';
export type CoreCourseProgressUpdated = { progress: number; courseId: number };
@ -260,7 +260,7 @@ export class CoreCourseProvider {
}
const course = await CoreCourses.getCourseByField('id', courseId, site.id);
const formatOptions = CoreUtils.objectToKeyValueMap(
const formatOptions = CoreObject.toKeyValueMap(
course.courseformatoptions ?? [],
'name',
'value',
@ -353,7 +353,7 @@ export class CoreCourseProvider {
throw Error('WS core_completion_get_activities_completion_status failed');
}
const completionStatus = CoreUtils.arrayToObject(data.statuses, 'cmid');
const completionStatus = CoreArray.toObject(data.statuses, 'cmid');
if (!includeOffline) {
return completionStatus;
}
@ -412,7 +412,7 @@ export class CoreCourseProvider {
js: (record) => ids.includes(record.cmId),
});
return CoreUtils.arrayToObject(entries, 'cmId');
return CoreArray.toObject(entries, 'cmId');
}
/**

View File

@ -18,7 +18,7 @@ import { CoreNetwork } from '@services/network';
import { CoreSites } from '@services/sites';
import { CoreText } from '@singletons/text';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { makeSingleton } from '@singletons';
import { ACTIVITY_LOG_TABLE, CoreCourseActivityLogDBRecord } from './database/log';
import { CoreStatusWithWarningsWSResponse } from '@services/ws';
@ -84,7 +84,7 @@ export class CoreCourseLogHelperProvider {
const conditions: Partial<CoreCourseActivityLogDBRecord> = {
ws,
data: CoreUtils.sortAndStringify(data),
data: CoreObject.sortAndStringify(data),
};
await site.getDb().deleteRecords(ACTIVITY_LOG_TABLE, conditions);
@ -264,7 +264,7 @@ export class CoreCourseLogHelperProvider {
component,
componentid: componentId,
ws,
data: CoreUtils.sortAndStringify(data),
data: CoreObject.sortAndStringify(data),
time: CoreTimeUtils.timestamp(),
};

View File

@ -21,7 +21,7 @@ import { CoreFileHelper } from '@services/file-helper';
import { CoreFilepool } from '@services/filepool';
import { CoreSites } from '@services/sites';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreCourse, CoreCourseAnyModuleData, CoreCourseModuleContentFile } from './course';
import { CoreCache } from '@classes/cache';
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
@ -1317,7 +1317,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
previousTime?: number,
): CourseUpdates {
// Format the response to index it by module ID.
CoreUtils.arrayToObject<false | CheckUpdatesWSInstance>(response.instances, 'id', result);
CoreArray.toObject<false | CheckUpdatesWSInstance>(response.instances, 'id', result);
// Treat warnings, adding the not supported modules.
response.warnings?.forEach((warning) => {

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
import {
CoreCourseAnyCourseData,
@ -157,7 +157,7 @@ export class CoreCoursesHelperProvider {
// Get the extra data for the courses.
return CoreCourses.getCoursesByFieldObservable('ids', courseIds, options).pipe(map(coursesInfosArray => {
const coursesInfo = CoreUtils.arrayToObject(coursesInfosArray, 'id');
const coursesInfo = CoreArray.toObject(coursesInfosArray, 'id');
courses.forEach((course) => {
this.loadCourseExtraInfo(course, coursesInfo[course.id], loadCategoryNames);

View File

@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
import { CoreError } from '@classes/errors/error';
import { CoreSites } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { makeSingleton } from '@singletons';
import { CoreLogger } from '@singletons/logger';
import { CoreEditorDraft, CoreEditorDraftPrimaryData, DRAFT_TABLE } from './database/editor';
@ -82,7 +82,7 @@ export class CoreEditorOfflineProvider {
contextlevel: contextLevel,
contextinstanceid: contextInstanceId,
elementid: elementId,
extraparams: CoreUtils.sortAndStringify(extraParams || {}),
extraparams: CoreObject.sortAndStringify(extraParams || {}),
};
}

View File

@ -24,7 +24,7 @@ import { CoreFile, CoreFileProvider, CoreFileProgressEvent } from '@services/fil
import { CoreDomUtils } from '@services/utils/dom';
import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreText } from '@singletons/text';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { makeSingleton, Translate, Camera, ActionSheetController } from '@singletons';
import { CoreLogger } from '@singletons/logger';
import { CoreCanceledError } from '@classes/errors/cancelederror';
@ -635,8 +635,8 @@ export class CoreFileUploaderHelperProvider {
};
if (fromAlbum) {
const imageSupported = !mimetypes || CoreUtils.indexOfRegexp(mimetypes, /^image\//) > -1;
const videoSupported = !mimetypes || CoreUtils.indexOfRegexp(mimetypes, /^video\//) > -1;
const imageSupported = !mimetypes || CoreArray.indexOfRegexp(mimetypes, /^image\//) > -1;
const videoSupported = !mimetypes || CoreArray.indexOfRegexp(mimetypes, /^video\//) > -1;
options.sourceType = Camera.PictureSourceType.PHOTOLIBRARY;
options.popoverOptions = {

View File

@ -47,6 +47,7 @@ import { CoreLoadings } from '@services/loadings';
import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreCourseAccessDataType } from '@features/course/constants';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreArray } from '@singletons/array';
export const GRADES_PAGE_NAME = 'grades';
export const GRADES_PARTICIPANTS_PAGE_NAME = 'participant-grades';
@ -271,7 +272,7 @@ export class CoreGradesHelperProvider {
try {
const courses = await CoreCourses.getUserCourses(undefined, undefined, CoreSitesReadingStrategy.ONLY_CACHE);
const coursesMap = CoreUtils.arrayToObject(courses, 'id');
const coursesMap = CoreArray.toObject(courses, 'id');
coursesWereMissing = this.addCourseData(grades, coursesMap);
} catch {
@ -282,7 +283,7 @@ export class CoreGradesHelperProvider {
if (coursesWereMissing) {
const courses = await CoreCourses.getCoursesByField('ids', grades.map((grade) => grade.courseid).join(','));
const coursesMap =
CoreUtils.arrayToObject(courses as Record<string, unknown>[], 'id') as
CoreArray.toObject(courses as Record<string, unknown>[], 'id') as
Record<string, CoreEnrolledCourseData> |
Record<string, CoreCourseSearchedData>;

View File

@ -18,6 +18,7 @@ import { CoreH5P } from '@features/h5p/services/h5p';
import { Translate } from '@singletons';
import { CoreH5PCore, CoreH5PLibraryData, CoreH5PLibraryAddonData, CoreH5PContentDepsTreeDependency } from './core';
import { CoreArray } from '@singletons/array';
import { CoreObject } from '@singletons/object';
const ALLOWED_STYLEABLE_TAGS = ['span', 'p', 'div', 'h1', 'h2', 'h3', 'table', 'col', 'figure', 'td', 'th', 'li'];
@ -354,7 +355,7 @@ export class CoreH5PContentValidator {
}
if (!isArray) {
list = CoreUtils.objectToArray(<Record<string, unknown>> list);
list = CoreObject.toArray(<Record<string, unknown>> list);
}
if (!list.length) {
@ -677,7 +678,7 @@ export class CoreH5PContentValidator {
*/
protected filterXssSplit(tags: string[], store: boolean = false): string {
if (store) {
this.allowedHtml = CoreUtils.arrayToObject(tags);
this.allowedHtml = CoreArray.toObject(tags);
return '';
}

View File

@ -961,7 +961,7 @@ export class CoreH5PCore {
if (params.match(pattern)) {
return true;
}
} else if (typeof params == 'object') {
} else if (typeof params === 'object') {
for (const key in params) {
const value = params[key];

View File

@ -23,7 +23,7 @@ import { CoreSites, CoreLoginSiteInfo, CoreSiteBasicInfo } from '@services/sites
import { CoreWS, CoreWSExternalWarning } from '@services/ws';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreText } from '@singletons/text';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreConstants } from '@/core/constants';
import { CoreSite } from '@classes/sites/site';
import { CoreError } from '@classes/errors/error';
@ -1368,7 +1368,7 @@ export class CoreLoginHelperProvider {
return;
}));
accountsList.otherSites = CoreUtils.objectToArray(otherSites);
accountsList.otherSites = CoreObject.toArray(otherSites);
return accountsList;
}

View File

@ -19,7 +19,7 @@ import { CoreSites } from '@services/sites';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreTabsOutletComponent, CoreTabsOutletTab } from '@components/tabs-outlet/tabs-outlet';
import { CoreMainMenuHomeDelegate, CoreMainMenuHomeHandlerToDisplay } from '../../services/home-delegate';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreMainMenuHomeHandlerService } from '@features/mainmenu/services/handlers/mainmenu';
/**
@ -62,7 +62,7 @@ export class CoreMainMenuHomePage implements OnInit {
initHandlers(handlers: CoreMainMenuHomeHandlerToDisplay[]): void {
// Re-build the list of tabs.
const loaded = CoreMainMenuHomeDelegate.areHandlersLoaded();
const handlersMap = CoreUtils.arrayToObject(handlers, 'title');
const handlersMap = CoreArray.toObject(handlers, 'title');
const newTabs = handlers.map((handler): CoreTabsOutletTab => {
const tab = this.tabs.find(tab => tab.title == handler.title);

View File

@ -18,7 +18,7 @@ import { CoreFile } from '@services/file';
import { CoreSites } from '@services/sites';
import { CoreText } from '@singletons/text';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreWSExternalFile } from '@services/ws';
import { makeSingleton } from '@singletons';
import { CorePath } from '@singletons/path';
@ -37,6 +37,7 @@ import {
QUESTION_NEEDS_GRADING_STATE_CLASSES,
QUESTION_TODO_STATE_CLASSES,
} from '@features/question/constants';
import { CoreObject } from '@singletons/object';
const QUESTION_PREFIX_REGEX = /q\d+:(\d+)_/;
const STATES: Record<string, CoreQuestionState> = {
@ -150,7 +151,7 @@ export class CoreQuestionProvider {
*/
compareAllAnswers(prevAnswers: Record<string, unknown>, newAnswers: Record<string, unknown>): boolean {
// Get all the keys.
const keys = CoreUtils.mergeArraysWithoutDuplicates(Object.keys(prevAnswers), Object.keys(newAnswers));
const keys = CoreArray.mergeWithoutDuplicates(Object.keys(prevAnswers), Object.keys(newAnswers));
// Check that all the keys have the same value on both objects.
for (const i in keys) {
@ -158,7 +159,7 @@ export class CoreQuestionProvider {
// Ignore extra answers like sequencecheck or certainty.
if (!this.isExtraAnswer(key[0])) {
if (!CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, key)) {
if (!CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, key)) {
return false;
}
}

View File

@ -18,13 +18,13 @@ import { CoreSite } from '@classes/sites/site';
import { CoreUser } from '@features/user/services/user';
import { CoreNetwork } from '@services/network';
import { CoreSites } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreWSExternalWarning } from '@services/ws';
import { makeSingleton } from '@singletons';
import { CoreEvents } from '@singletons/events';
import { CoreRatingOffline } from './rating-offline';
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
import { CoreWSError } from '@classes/errors/wserror';
import { CoreObject } from '@singletons/object';
const ROOT_CACHE_KEY = 'CoreRating:';
@ -351,8 +351,8 @@ export class CoreRatingProvider {
});
if (result) {
result.scales = CoreUtils.objectToArray(scales);
result.ratings = CoreUtils.objectToArray(ratings);
result.scales = CoreObject.toArray(scales);
result.ratings = CoreObject.toArray(ratings);
}
return result;

View File

@ -15,7 +15,7 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { CoreSiteBasicInfo, CoreSites } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreSettingsHelper } from '../../services/settings-helper';
@ -129,7 +129,7 @@ export class CoreSettingsSpaceUsagePage implements OnInit, OnDestroy {
}
});
this.accountsList.otherSites = CoreUtils.objectToArray(otherSites);
this.accountsList.otherSites = CoreObject.toArray(otherSites);
this.accountsList.count = sites.length;
this.totalSpaceUsage = totalSize;

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { CoreUtils } from '@services/utils/utils';
import { CoreObject } from '@singletons/object';
import { CoreSitePlugins, CoreSitePluginsInitHandlerData } from '../services/siteplugins';
/**
@ -55,7 +55,7 @@ export class CoreSitePluginsCompileInitComponent {
// Load first template.
if (this.handlerSchema.methodTemplates?.length) {
this.content = this.handlerSchema.methodTemplates[0].html;
this.jsData.CONTENT_TEMPLATES = CoreUtils.objectToKeyValueMap(
this.jsData.CONTENT_TEMPLATES = CoreObject.toKeyValueMap(
this.handlerSchema.methodTemplates,
'id',
'html',

View File

@ -34,6 +34,7 @@ import { CoreEnrolAction, CoreEnrolInfoIcon } from '@features/enrol/services/enr
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
import { CoreUserProfileHandlerType } from '@features/user/services/user-delegate';
import { CORE_SITE_PLUGINS_COMPONENT, CORE_SITE_PLUGINS_UPDATE_COURSE_CONTENT } from '../constants';
import { CoreObject } from '@singletons/object';
/**
* Service to provide functionalities regarding site plugins.
@ -156,13 +157,13 @@ export class CoreSitePluginsProvider {
data = Object.assign(data, initResult.jsResult || {});
// Now add some data returned by the init WS call.
data.INIT_TEMPLATES = CoreUtils.objectToKeyValueMap(initResult.templates, 'id', 'html');
data.INIT_TEMPLATES = CoreObject.toKeyValueMap(initResult.templates, 'id', 'html');
data.INIT_OTHERDATA = initResult.otherdata;
}
if (contentResult) {
// Now add the data returned by the content WS call.
data.CONTENT_TEMPLATES = CoreUtils.objectToKeyValueMap(contentResult.templates, 'id', 'html');
data.CONTENT_TEMPLATES = CoreObject.toKeyValueMap(contentResult.templates, 'id', 'html');
data.CONTENT_OTHERDATA = contentResult.otherdata;
}
@ -177,7 +178,7 @@ export class CoreSitePluginsProvider {
* @returns Cache key.
*/
getCallWSCacheKey(method: string, data: Record<string, unknown>): string {
return this.getCallWSCommonCacheKey(method) + ':' + CoreUtils.sortAndStringify(data);
return this.getCallWSCommonCacheKey(method) + ':' + CoreObject.sortAndStringify(data);
}
/**
@ -219,7 +220,7 @@ export class CoreSitePluginsProvider {
const data: CoreSitePluginsGetContentWSParams = {
component: component,
method: method,
args: CoreUtils.objectToArrayOfObjects(argsToSend, 'name', 'value', true),
args: CoreObject.toArrayOfObjects(argsToSend, 'name', 'value', true),
};
preSets = preSets || {};
@ -230,7 +231,7 @@ export class CoreSitePluginsProvider {
let otherData: Record<string, unknown> = {};
if (result.otherdata) {
otherData = <Record<string, unknown>> CoreUtils.objectToKeyValueMap(result.otherdata, 'name', 'value');
otherData = <Record<string, unknown>> CoreObject.toKeyValueMap(result.otherdata, 'name', 'value');
// Try to parse all properties that could be JSON encoded strings.
for (const name in otherData) {
@ -255,7 +256,7 @@ export class CoreSitePluginsProvider {
*/
protected getContentCacheKey(component: string, method: string, args: Record<string, unknown>): string {
return CoreSitePluginsProvider.ROOT_CACHE_KEY + 'content:' + component + ':' + method +
':' + CoreUtils.sortAndStringify(args);
':' + CoreObject.sortAndStringify(args);
}
/**
@ -346,7 +347,7 @@ export class CoreSitePluginsProvider {
* @returns Plugin list ws info.
*/
getCurrentSitePluginList(): CoreSitePluginsWSPlugin[] {
return CoreUtils.objectToArray(this.sitePlugins).map((plugin) => plugin.plugin);
return CoreObject.toArray(this.sitePlugins).map((plugin) => plugin.plugin);
}
/**
@ -507,7 +508,7 @@ export class CoreSitePluginsProvider {
for (const i in useOtherData) {
const name = useOtherData[i];
if (typeof otherData[name] == 'object' && otherData[name] !== null) {
if (typeof otherData[name] === 'object' && otherData[name] !== null) {
// Stringify objects.
args[name] = JSON.stringify(otherData[name]);
} else {
@ -517,7 +518,7 @@ export class CoreSitePluginsProvider {
} else {
// Add all the data to args.
for (const name in otherData) {
if (typeof otherData[name] == 'object' && otherData[name] !== null) {
if (typeof otherData[name] === 'object' && otherData[name] !== null) {
// Stringify objects.
args[name] = JSON.stringify(otherData[name]);
} else {

View File

@ -27,7 +27,7 @@ import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreText } from '@singletons/text';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
import { CoreUtils } from '@services/utils/utils';
import { CoreArray } from '@singletons/array';
import { CoreError } from '@classes/errors/error';
import { DownloadStatus } from '@/core/constants';
import { ApplicationInit, makeSingleton, NgZone, Translate } from '@singletons';
@ -650,7 +650,7 @@ export class CoreFilepoolProvider {
]);
// Notify now.
const filesLinksMap = CoreUtils.arrayToObjectMultiple(filesLinks, 'fileId');
const filesLinksMap = CoreArray.toObjectMultiple(filesLinks, 'fileId');
filesEntries.forEach(entry => this.notifyFileDeleted(siteId, entry.fileId, filesLinksMap[entry.fileId] || []));
}

View File

@ -154,7 +154,7 @@ export class CoreGeolocationProvider {
*/
protected isCordovaPermissionDeniedError(error?: CoreAnyError | GeolocationPositionError): boolean {
return !!error &&
typeof error == 'object' &&
typeof error === 'object' &&
'code' in error &&
'PERMISSION_DENIED' in error &&
error.code === error.PERMISSION_DENIED;

View File

@ -290,7 +290,7 @@ export class CoreLocalNotificationsProvider {
scheduled.forEach((notif) => {
notif.data = this.parseNotificationData(notif.data);
if (notif.id && typeof notif.data == 'object' && notif.data.siteId === siteId) {
if (notif.id && typeof notif.data === 'object' && notif.data.siteId === siteId) {
ids.push(notif.id);
}
});
@ -563,7 +563,7 @@ export class CoreLocalNotificationsProvider {
try {
// Check if request is valid.
if (typeof request != 'object' || request.table === undefined || request.id === undefined) {
if (typeof request !== 'object' || request.table === undefined || request.id === undefined) {
return;
}

View File

@ -461,7 +461,7 @@ export class CoreNavigatorService {
return route;
}
if (routeData && CoreUtils.basicLeftCompare(routeData, this.getRouteData(route), 3)) {
if (routeData && CoreObject.basicLeftCompare(routeData, this.getRouteData(route), 3)) {
return route;
}
@ -607,7 +607,7 @@ export class CoreNavigatorService {
protected replaceObjectParams(queryParams?: Params | null): void {
for (const name in queryParams) {
const value = queryParams[name];
if (typeof value != 'object' || value === null) {
if (typeof value !== 'object' || value === null) {
continue;
}

View File

@ -1292,7 +1292,7 @@ export class CoreSitesProvider {
return !!this.currentSite;
}
const siteId = typeof site == 'object' ? site.getId() : site;
const siteId = typeof site === 'object' ? site.getId() : site;
return this.currentSite.getId() === siteId;
}

View File

@ -447,7 +447,7 @@ export class CoreDomUtilsProvider {
let extraInfo = '';
let errorMessage: string | undefined;
if (typeof error == 'object') {
if (typeof error === 'object') {
if (this.debugDisplay) {
// Get the debug info. Escape the HTML so it is displayed as it is in the view.
if ('debuginfo' in error && error.debuginfo) {

View File

@ -455,7 +455,7 @@ export class CoreIframeUtilsProvider {
return;
}
if (element.tagName.toLowerCase() == 'object') {
if (element.tagName.toLowerCase() === 'object') {
element.setAttribute('data', url);
} else {
element.setAttribute('src', url);
@ -509,7 +509,7 @@ export class CoreIframeUtilsProvider {
(!link.target || link.target == '_self')
) {
// Load the link inside the frame itself.
if (element.tagName.toLowerCase() == 'object') {
if (element.tagName.toLowerCase() === 'object') {
element.setAttribute('data', link.href);
} else {
element.setAttribute('src', link.href);
@ -546,7 +546,7 @@ export class CoreIframeUtilsProvider {
} else if (CorePlatform.isIOS() && (!link.target || link.target == '_self') && element) {
// In cordova ios 4.1.0 links inside iframes stopped working. We'll manually treat them.
event && event.preventDefault();
if (element.tagName.toLowerCase() == 'object') {
if (element.tagName.toLowerCase() === 'object') {
element.setAttribute('data', link.href);
} else {
element.setAttribute('src', link.href);

View File

@ -424,10 +424,10 @@ export class CoreMimetypeUtilsProvider {
let mimetype: string | undefined = '';
let extension: string | undefined = '';
if (typeof obj == 'object' && CoreFileUtils.isFileEntry(obj)) {
if (typeof obj === 'object' && CoreFileUtils.isFileEntry(obj)) {
// It's a FileEntry. Don't use the file function because it's asynchronous and the type isn't reliable.
filename = obj.name;
} else if (typeof obj == 'object') {
} else if (typeof obj === 'object') {
filename = obj.filename || '';
mimetype = obj.mimetype || '';
} else {

View File

@ -30,6 +30,7 @@ import { CoreErrorHelper } from '@services/error-helper';
import { CorePromiseUtils, OrderedPromiseData } from '@singletons/promise-utils';
import { CoreOpener, CoreOpenerOpenFileOptions, CoreOpenerOpenInBrowserOptions } from '@singletons/opener';
import { CoreCountries, CoreCountry } from '@singletons/countries';
import { CoreObject } from '@singletons/object';
export type TreeNode<T> = T & { children: TreeNode<T>[] };
@ -89,19 +90,14 @@ export class CoreUtilsProvider {
* @param propertyName The name of the property to use as the key. If not provided, the whole item will be used.
* @param result Object where to put the properties. If not defined, a new object will be created.
* @returns The object.
* @deprecated since 5.0. Use CoreArray.toObject instead.
*/
arrayToObject<T>(
array: T[] = [],
propertyName?: string,
result: Record<string, T> = {},
): Record<string, T> {
for (const entry of array) {
const key = propertyName ? entry[propertyName] : entry;
result[key] = entry;
}
return result;
return CoreArray.toObject(array, propertyName, result);
}
/**
@ -124,22 +120,14 @@ export class CoreUtilsProvider {
* @param propertyName The name of the property to use as the key. If not provided, the whole item will be used.
* @param result Object where to put the properties. If not defined, a new object will be created.
* @returns The object.
* @deprecated since 5.0. Use CoreArray.toObjectMultiple instead.
*/
arrayToObjectMultiple<T>(
array: T[] = [],
propertyName?: string,
result: Record<string, T[]> = {},
): Record<string, T[]> {
for (const entry of array) {
const key = propertyName ? entry[propertyName] : entry;
if (result[key] === undefined) {
result[key] = [];
}
result[key].push(entry);
}
return result;
return CoreArray.toObjectMultiple(array, propertyName, result);
}
/**
@ -153,6 +141,7 @@ export class CoreUtilsProvider {
* @param level Current deep level (when comparing objects).
* @param undefinedIsNull True if undefined is equal to null. Defaults to true.
* @returns Whether both items are equal.
* @deprecated since 5.0. Use CoreObject.basicLeftCompare instead.
*/
basicLeftCompare(
itemA: any, // eslint-disable-line @typescript-eslint/no-explicit-any
@ -161,43 +150,7 @@ export class CoreUtilsProvider {
level: number = 0,
undefinedIsNull: boolean = true,
): boolean {
if (typeof itemA == 'function' || typeof itemB == 'function') {
return true; // Don't compare functions.
} else if (typeof itemA == 'object' && typeof itemB == 'object') {
if (level >= maxLevels) {
return true; // Max deep reached.
}
let equal = true;
for (const name in itemA) {
const value = itemA[name];
if (name == '$$hashKey') {
// Ignore $$hashKey property since it's a "calculated" property.
continue;
}
if (!this.basicLeftCompare(value, itemB[name], maxLevels, level + 1)) {
equal = false;
}
}
return equal;
} else {
if (undefinedIsNull && (
(itemA === undefined && itemB === null) || (itemA === null && itemB === undefined))) {
return true;
}
// We'll treat "2" and 2 as the same value.
const floatA = parseFloat(itemA);
const floatB = parseFloat(itemB);
if (!isNaN(floatA) && !isNaN(floatB)) {
return floatA == floatB;
}
return itemA === itemB;
}
return CoreObject.basicLeftCompare(itemA, itemB, maxLevels, level, undefinedIsNull);
}
/**
@ -291,7 +244,7 @@ export class CoreUtilsProvider {
}
return newArray;
} else if (this.isObject(source)) {
} else if (CoreObject.isObject(source)) {
// Check if the object shouldn't be copied.
if (source.toString && this.DONT_CLONE.indexOf(source.toString()) != -1) {
// Object shouldn't be copied, return it as it is.
@ -383,32 +336,10 @@ export class CoreUtilsProvider {
* @param obj Object to flatten.
* @param useDotNotation Whether to use dot notation '.' or square brackets '['.
* @returns Flattened object.
* @deprecated since 5.0. Use CoreObject.flatten instead.
*/
flattenObject(obj: Record<string, unknown>, useDotNotation?: boolean): Record<string, unknown> {
const toReturn = {};
for (const name in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, name)) {
continue;
}
const value = obj[name];
if (typeof value == 'object' && !Array.isArray(value)) {
const flatObject = this.flattenObject(value as Record<string, unknown>);
for (const subName in flatObject) {
if (!Object.prototype.hasOwnProperty.call(flatObject, subName)) {
continue;
}
const newName = useDotNotation ? name + '.' + subName : name + '[' + subName + ']';
toReturn[newName] = flatObject[subName];
}
} else {
toReturn[name] = value;
}
}
return toReturn;
return CoreObject.flatten(obj, useDotNotation);
}
/**
@ -650,9 +581,10 @@ export class CoreUtilsProvider {
*
* @param object Variable.
* @returns Type guard indicating if this is an object.
* @deprecated since 5.0. Use CoreObject.isObject instead.
*/
isObject(object: unknown): object is Record<string, unknown> {
return typeof object === 'object' && object !== null;
return CoreObject.isObject(object);
}
/**
@ -672,22 +604,10 @@ export class CoreUtilsProvider {
* @param array Array to search.
* @param regex RegExp to apply to each string.
* @returns Index of the first string that matches the RegExp. -1 if not found.
* @deprecated since 4.4. Use CoreArray.indexOfRegexp instead.
*/
indexOfRegexp(array: string[], regex: RegExp): number {
if (!array || !array.length) {
return -1;
}
for (let i = 0; i < array.length; i++) {
const entry = array[i];
const matches = entry.match(regex);
if (matches && matches.length) {
return i;
}
}
return -1;
return CoreArray.indexOfRegexp(array, regex);
}
/**
@ -787,9 +707,10 @@ export class CoreUtilsProvider {
* @param array2 The second array.
* @param [key] Key of the property that must be unique. If not specified, the whole entry.
* @returns Merged array.
* @deprecated since 5.0. Use CoreArray.mergeWithoutDuplicates instead.
*/
mergeArraysWithoutDuplicates<T>(array1: T[], array2: T[], key?: string): T[] {
return CoreArray.unique(array1.concat(array2), key) as T[];
return CoreArray.mergeWithoutDuplicates(array1, array2, key);
}
/**
@ -855,9 +776,10 @@ export class CoreUtilsProvider {
*
* @param obj Object to convert.
* @returns Array with the values of the object but losing the keys.
* @deprecated since 5.0. Use CoreObject.toArray instead.
*/
objectToArray<T>(obj: Record<string, T>): T[] {
return Object.keys(obj).map((key) => obj[key]);
return CoreObject.toArray(obj);
}
/**
@ -871,6 +793,7 @@ export class CoreUtilsProvider {
* @param sortByKey True to sort keys alphabetically, false otherwise. Has priority over sortByValue.
* @param sortByValue True to sort values alphabetically, false otherwise.
* @returns Array of objects with the name & value of each property.
* @deprecated since 5.0. Use CoreObject.toArrayOfObjects instead.
*/
objectToArrayOfObjects<
A extends Record<string,unknown> = Record<string, unknown>,
@ -882,53 +805,7 @@ export class CoreUtilsProvider {
sortByKey?: boolean,
sortByValue?: boolean,
): A[] {
// Get the entries from an object or primitive value.
const getEntries = (elKey: string, value: unknown): Record<string, unknown>[] | unknown => {
if (value === undefined || value == null) {
// Filter undefined and null values.
return;
} else if (this.isObject(value)) {
// It's an object, return at least an entry for each property.
const keys = Object.keys(value);
let entries: unknown[] = [];
keys.forEach((key) => {
const newElKey = elKey ? elKey + '[' + key + ']' : key;
const subEntries = getEntries(newElKey, value[key]);
if (subEntries) {
entries = entries.concat(subEntries);
}
});
return entries;
} else {
// Not an object, return a single entry.
const entry = {};
entry[keyName] = elKey;
entry[valueName] = value;
return entry;
}
};
if (!obj) {
return [];
}
// "obj" will always be an object, so "entries" will always be an array.
const entries = getEntries('', obj) as A[];
if (sortByKey || sortByValue) {
return entries.sort((a, b) => {
if (sortByKey) {
return (a[keyName] as number) >= (b[keyName] as number) ? 1 : -1;
} else {
return (a[valueName] as number) >= (b[valueName] as number) ? 1 : -1;
}
});
}
return entries;
return CoreObject.toArrayOfObjects(obj, keyName, valueName, sortByKey, sortByValue);
}
/**
@ -940,6 +817,7 @@ export class CoreUtilsProvider {
* @param valueName Name of the properties where the values are stored.
* @param keyPrefix Key prefix if neededs to delete it.
* @returns Object.
* @deprecated since 5.0. Use CoreObject.toKeyValueMap instead.
*/
objectToKeyValueMap<T = unknown>(
objects: Record<string, unknown>[],
@ -947,15 +825,7 @@ export class CoreUtilsProvider {
valueName: string,
keyPrefix?: string,
): {[name: string]: T} {
const prefixSubstr = keyPrefix ? keyPrefix.length : 0;
const mapped = {};
objects.forEach((item) => {
const keyValue = item[keyName] as string;
const key = prefixSubstr > 0 ? keyValue.substring(prefixSubstr) : keyValue;
mapped[key] = item[valueName];
});
return mapped;
return CoreObject.toKeyValueMap(objects, keyName, valueName, keyPrefix);
}
/**
@ -964,29 +834,10 @@ export class CoreUtilsProvider {
* @param object Object to convert.
* @param removeEmpty Whether to remove params whose value is null/undefined.
* @returns GET params.
* @deprecated since 5.0. Use CoreObject.toGetParams instead.
*/
objectToGetParams(object: Record<string, unknown>, removeEmpty: boolean = true): string {
// First of all, flatten the object so all properties are in the first level.
const flattened = this.flattenObject(object);
let result = '';
let joinChar = '';
for (const name in flattened) {
let value = flattened[name];
if (removeEmpty && (value === null || value === undefined)) {
continue;
}
if (typeof value == 'boolean') {
value = value ? 1 : 0;
}
result += joinChar + name + '=' + value;
joinChar = '&';
}
return result;
return CoreObject.toGetParams(object, removeEmpty);
}
/**
@ -995,6 +846,7 @@ export class CoreUtilsProvider {
* @param data Object.
* @param prefix Prefix to add.
* @returns Prefixed object.
* @deprecated since 5.0. Not used anymore
*/
prefixKeys(data: Record<string, unknown>, prefix: string): Record<string, unknown> {
const newObj = {};
@ -1012,9 +864,10 @@ export class CoreUtilsProvider {
*
* @param enumeration Enumeration object.
* @returns Keys of the enumeration.
* @deprecated since 5.0. Use CoreObject.enumKeys instead.
*/
enumKeys<O extends object, K extends keyof O = keyof O>(enumeration: O): K[] {
return Object.keys(enumeration).filter(k => Number.isNaN(+k)) as K[];
return CoreObject.enumKeys(enumeration);
}
/**
@ -1048,23 +901,14 @@ export class CoreUtilsProvider {
* @param obj2 The second object or array.
* @param key Key to check.
* @returns Whether the two objects/arrays have the same value (or lack of one) for a given key.
* @deprecated since 5.0. Use CoreObject.sameAtKeyMissingIsBlank instead.
*/
sameAtKeyMissingIsBlank(
obj1: Record<string, unknown> | unknown[],
obj2: Record<string, unknown> | unknown[],
key: string,
): boolean {
let value1 = obj1[key] !== undefined ? obj1[key] : '';
let value2 = obj2[key] !== undefined ? obj2[key] : '';
if (typeof value1 == 'number' || typeof value1 == 'boolean') {
value1 = '' + value1;
}
if (typeof value2 == 'number' || typeof value2 == 'boolean') {
value2 = '' + value2;
}
return value1 === value2;
return CoreObject.sameAtKeyMissingIsBlank(obj1, obj2, key);
}
/**
@ -1073,9 +917,11 @@ export class CoreUtilsProvider {
*
* @param obj Object to stringify.
* @returns Stringified object.
* @deprecated since 5.0. Use CoreObject.sortAndStringify instead.
*/
sortAndStringify(obj: Record<string, unknown>): string {
return JSON.stringify(this.sortProperties(obj));
return CoreObject.sortAndStringify(obj);
}
/**
@ -1083,19 +929,10 @@ export class CoreUtilsProvider {
*
* @param obj The object to sort. If it isn't an object, the original value will be returned.
* @returns Sorted object.
* @deprecated since 5.0. Use CoreObject.sortProperties instead.
*/
sortProperties<T>(obj: T): T {
if (obj != null && typeof obj == 'object' && !Array.isArray(obj)) {
// It's an object, sort it.
return Object.keys(obj).sort().reduce((accumulator, key) => {
// Always call sort with the value. If it isn't an object, the original value will be returned.
accumulator[key] = this.sortProperties(obj[key]);
return accumulator;
}, {} as T);
} else {
return obj;
}
return CoreObject.sortProperties(obj);
}
/**
@ -1103,16 +940,10 @@ export class CoreUtilsProvider {
*
* @param obj The object to sort. If it isn't an object, the original value will be returned.
* @returns Sorted object.
* @deprecated since 5.0. Use CoreObject.sortValues instead.
*/
sortValues<T>(obj: T): T {
if (typeof obj == 'object' && !Array.isArray(obj)) {
// It's an object, sort it. Convert it to an array to be able to sort it and then convert it back to object.
const array = this.objectToArrayOfObjects(obj as Record<string, unknown>, 'name', 'value', false, true);
return this.objectToKeyValueMap(array, 'name', 'value') as unknown as T;
} else {
return obj;
}
return CoreObject.sortValues(obj);
}
/**

View File

@ -170,7 +170,7 @@ export class CoreWSProvider {
if (value == null) {
// Skip null or undefined value.
continue;
} else if (typeof value == 'object') {
} else if (typeof value === 'object') {
// Object or array.
value = this.convertValuesToString(value, stripUnicode);
if (value == null) {
@ -498,7 +498,7 @@ export class CoreWSProvider {
}
// Check if error. Ajax layer should always return an object (if error) or an array (if success).
if (!data || typeof data != 'object') {
if (!data || typeof data !== 'object') {
const message = CoreSites.isLoggedIn()
? Translate.instant('core.siteunavailablehelp', { site: CoreSites.getCurrentSite()?.siteUrl })
: Translate.instant('core.sitenotfoundhelp');
@ -1090,7 +1090,7 @@ export class CoreWSProvider {
}),
},
});
} else if (typeof data != 'object') {
} else if (typeof data !== 'object') {
this.logger.warn('Upload file: Response of type "' + typeof data + '" received, expecting "object"');
throw await this.createCannotConnectSiteError(preSets.siteUrl, {

View File

@ -17,6 +17,62 @@
*/
export class CoreArray {
// Avoid creating singleton instances.
private constructor() {
// Nothing to do.
}
/**
* Converts an array of objects to an object, using a property of each entry as the key.
* It can also be used to convert an array of strings to an object where the keys are the elements of the array.
* E.g. [{id: 10, name: 'A'}, {id: 11, name: 'B'}] => {10: {id: 10, name: 'A'}, 11: {id: 11, name: 'B'}}
*
* @param array The array to convert.
* @param propertyName The name of the property to use as the key. If not provided, the whole item will be used.
* @param result Object where to put the properties. If not defined, a new object will be created.
* @returns The object.
*/
static toObject<T>(
array: T[] = [],
propertyName?: string,
result: Record<string, T> = {},
): Record<string, T> {
for (const entry of array) {
const key = propertyName ? entry[propertyName] : entry;
result[key] = entry;
}
return result;
}
/**
* Converts an array of objects to an indexed array, using a property of each entry as the key.
* Every entry will contain an array of the found objects of the property identifier.
* E.g. [{id: 10, name: 'A'}, {id: 10, name: 'B'}] => {10: [ {id: 10, name: 'A'}, {id: 10, name: 'B'} ] }
*
* @param array The array to convert.
* @param propertyName The name of the property to use as the key. If not provided, the whole item will be used.
* @param result Object where to put the properties. If not defined, a new object will be created.
* @returns The object.
*/
static toObjectMultiple<T>(
array: T[] = [],
propertyName?: string,
result: Record<string, T[]> = {},
): Record<string, T[]> {
for (const entry of array) {
const key = propertyName ? entry[propertyName] : entry;
if (result[key] === undefined) {
result[key] = [];
}
result[key].push(entry);
}
return result;
}
/**
* Flatten the first dimension of a multi-dimensional array.
*
@ -93,4 +149,40 @@ export class CoreArray {
});
}
/**
* Merge two arrays, removing duplicate values.
*
* @param array1 The first array.
* @param array2 The second array.
* @param [key] Key of the property that must be unique. If not specified, the whole entry.
* @returns Merged array.
*/
static mergeWithoutDuplicates<T>(array1: T[], array2: T[], key?: string): T[] {
return CoreArray.unique(array1.concat(array2), key) as T[];
}
/**
* Gets the index of the first string that matches a regular expression.
*
* @param array Array to search.
* @param regex RegExp to apply to each string.
* @returns Index of the first string that matches the RegExp. -1 if not found.
*/
static indexOfRegexp(array: string[], regex: RegExp): number {
if (!array || !array.length) {
return -1;
}
for (let i = 0; i < array.length; i++) {
const entry = array[i];
const matches = entry.match(regex);
if (matches && matches.length) {
return i;
}
}
return -1;
}
}

View File

@ -44,7 +44,7 @@ export class CoreFileUtils {
*/
static valueIsFileEntry(file: unknown): file is FileEntry {
// We cannot use instanceof because FileEntry is a type. Check some of the properties.
return !!(file && typeof file == 'object' && 'isFile' in file && 'filesystem' in file &&
return !!(file && typeof file === 'object' && 'isFile' in file && 'filesystem' in file &&
'toInternalURL' in file && 'copyTo' in file);
}

View File

@ -30,6 +30,11 @@ export type CoreObjectWithoutUndefined<T> = Pretty<{
*/
export class CoreObject {
// Avoid creating singleton instances.
private constructor() {
// Nothing to do.
}
/**
* Returns a value of an object and deletes it from the object.
*
@ -170,4 +175,335 @@ export class CoreObject {
return cleanObj as CoreObjectWithoutUndefined<T>;
}
/**
* Tests to see whether two arrays or objects have the same value at a particular key.
* Missing values are replaced by '', and the values are compared with ===.
* Booleans and numbers are cast to string before comparing.
*
* @param obj1 The first object or array.
* @param obj2 The second object or array.
* @param key Key to check.
* @returns Whether the two objects/arrays have the same value (or lack of one) for a given key.
*/
static sameAtKeyMissingIsBlank(
obj1: Record<string, unknown> | unknown[],
obj2: Record<string, unknown> | unknown[],
key: string,
): boolean {
let value1 = obj1[key] !== undefined ? obj1[key] : '';
let value2 = obj2[key] !== undefined ? obj2[key] : '';
if (typeof value1 == 'number' || typeof value1 == 'boolean') {
value1 = '' + value1;
}
if (typeof value2 == 'number' || typeof value2 == 'boolean') {
value2 = '' + value2;
}
return value1 === value2;
}
/**
* Stringify an object, sorting the properties. It doesn't sort arrays, only object properties. E.g.:
* {b: 2, a: 1} -> '{"a":1,"b":2}'
*
* @param obj Object to stringify.
* @returns Stringified object.
*/
static sortAndStringify(obj: Record<string, unknown>): string {
return JSON.stringify(CoreObject.sortProperties(obj));
}
/**
* Given an object, sort its properties and the properties of all the nested objects.
*
* @param obj The object to sort. If it isn't an object, the original value will be returned.
* @returns Sorted object.
*/
static sortProperties<T>(obj: T): T {
if (obj != null && typeof obj === 'object' && !Array.isArray(obj)) {
// It's an object, sort it.
return Object.keys(obj).sort().reduce((accumulator, key) => {
// Always call sort with the value. If it isn't an object, the original value will be returned.
accumulator[key] = CoreObject.sortProperties(obj[key]);
return accumulator;
}, {} as T);
}
return obj;
}
/**
* Given an object, sort its values. Values need to be primitive values, it cannot have subobjects.
*
* @param obj The object to sort. If it isn't an object, the original value will be returned.
* @returns Sorted object.
*/
static sortValues<T>(obj: T): T {
if (typeof obj === 'object' && !Array.isArray(obj)) {
// It's an object, sort it. Convert it to an array to be able to sort it and then convert it back to object.
const array = CoreObject.toArrayOfObjects(obj as Record<string, unknown>, 'name', 'value', false, true);
return CoreObject.toKeyValueMap(array, 'name', 'value') as unknown as T;
}
return obj;
}
/**
* Converts an object into an array, losing the keys.
*
* @param obj Object to convert.
* @returns Array with the values of the object but losing the keys.
*/
static toArray<T>(obj: Record<string, T>): T[] {
return Object.keys(obj).map((key) => obj[key]);
}
/**
* Converts an object into an array of objects, where each entry is an object containing
* the key and value of the original object.
* For example, it can convert {size: 2} into [{name: 'size', value: 2}].
*
* @param obj Object to convert.
* @param keyName Name of the properties where to store the keys.
* @param valueName Name of the properties where to store the values.
* @param sortByKey True to sort keys alphabetically, false otherwise. Has priority over sortByValue.
* @param sortByValue True to sort values alphabetically, false otherwise.
* @returns Array of objects with the name & value of each property.
*/
static toArrayOfObjects<
A extends Record<string,unknown> = Record<string, unknown>,
O extends Record<string, unknown> = Record<string, unknown>
>(
obj: O,
keyName: string,
valueName: string,
sortByKey?: boolean,
sortByValue?: boolean,
): A[] {
// Get the entries from an object or primitive value.
const getEntries = (elKey: string, value: unknown): Record<string, unknown>[] | unknown => {
if (value === undefined || value == null) {
// Filter undefined and null values.
return;
} else if (CoreObject.isObject(value)) {
// It's an object, return at least an entry for each property.
const keys = Object.keys(value);
let entries: unknown[] = [];
keys.forEach((key) => {
const newElKey = elKey ? elKey + '[' + key + ']' : key;
const subEntries = getEntries(newElKey, value[key]);
if (subEntries) {
entries = entries.concat(subEntries);
}
});
return entries;
} else {
// Not an object, return a single entry.
const entry = {};
entry[keyName] = elKey;
entry[valueName] = value;
return entry;
}
};
if (!obj) {
return [];
}
// "obj" will always be an object, so "entries" will always be an array.
const entries = getEntries('', obj) as A[];
if (sortByKey || sortByValue) {
return entries.sort((a, b) => {
if (sortByKey) {
return (a[keyName] as number) >= (b[keyName] as number) ? 1 : -1;
} else {
return (a[valueName] as number) >= (b[valueName] as number) ? 1 : -1;
}
});
}
return entries;
}
/**
* Converts an array of objects into an object with key and value. The opposite of objectToArrayOfObjects.
* For example, it can convert [{name: 'size', value: 2}] into {size: 2}.
*
* @param objects List of objects to convert.
* @param keyName Name of the properties where the keys are stored.
* @param valueName Name of the properties where the values are stored.
* @param keyPrefix Key prefix if neededs to delete it.
* @returns Object.
*/
static toKeyValueMap<T = unknown>(
objects: Record<string, unknown>[],
keyName: string,
valueName: string,
keyPrefix?: string,
): {[name: string]: T} {
const prefixSubstr = keyPrefix ? keyPrefix.length : 0;
const mapped = {};
objects.forEach((item) => {
const keyValue = item[keyName] as string;
const key = prefixSubstr > 0 ? keyValue.substring(prefixSubstr) : keyValue;
mapped[key] = item[valueName];
});
return mapped;
}
/**
* Convert an object to a format of GET param. E.g.: {a: 1, b: 2} -> a=1&b=2
*
* @param object Object to convert.
* @param removeEmpty Whether to remove params whose value is null/undefined.
* @returns GET params.
*/
static toGetParams(object: Record<string, unknown>, removeEmpty: boolean = true): string {
// First of all, flatten the object so all properties are in the first level.
const flattened = CoreObject.flatten(object);
let result = '';
let joinChar = '';
for (const name in flattened) {
let value = flattened[name];
if (removeEmpty && (value === null || value === undefined)) {
continue;
}
if (typeof value === 'boolean') {
value = value ? 1 : 0;
}
result += joinChar + name + '=' + value;
joinChar = '&';
}
return result;
}
/**
* Function to enumerate enum keys.
*
* @param enumeration Enumeration object.
* @returns Keys of the enumeration.
*/
static enumKeys<O extends object, K extends keyof O = keyof O>(enumeration: O): K[] {
return Object.keys(enumeration).filter(k => Number.isNaN(+k)) as K[];
}
/**
* Check if a value is an object.
*
* @param object Variable.
* @returns Type guard indicating if this is an object.
*/
static isObject(object: unknown): object is Record<string, unknown> {
return typeof object === 'object' && object !== null;
}
/**
* Flatten an object, moving subobjects' properties to the first level.
* It supports 2 notations: dot notation and square brackets.
* E.g.: {a: {b: 1, c: 2}, d: 3} -> {'a.b': 1, 'a.c': 2, d: 3}
*
* @param obj Object to flatten.
* @param useDotNotation Whether to use dot notation '.' or square brackets '['.
* @returns Flattened object.
*/
static flatten(obj: Record<string, unknown>, useDotNotation?: boolean): Record<string, unknown> {
const toReturn = {};
for (const name in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, name)) {
continue;
}
const value = obj[name];
if (typeof value === 'object' && !Array.isArray(value)) {
const flatObject = CoreObject.flatten(value as Record<string, unknown>);
for (const subName in flatObject) {
if (!Object.prototype.hasOwnProperty.call(flatObject, subName)) {
continue;
}
const newName = useDotNotation ? name + '.' + subName : name + '[' + subName + ']';
toReturn[newName] = flatObject[subName];
}
} else {
toReturn[name] = value;
}
}
return toReturn;
}
/**
* Compare two objects. This function won't compare functions and proto properties, it's a basic compare.
* Also, this will only check if itemA's properties are in itemB with same value. This function will still
* return true if itemB has more properties than itemA.
*
* @param itemA First object.
* @param itemB Second object.
* @param maxLevels Number of levels to reach if 2 objects are compared.
* @param level Current deep level (when comparing objects).
* @param undefinedIsNull True if undefined is equal to null. Defaults to true.
* @returns Whether both items are equal.
*/
static basicLeftCompare(
itemA: any, // eslint-disable-line @typescript-eslint/no-explicit-any
itemB: any, // eslint-disable-line @typescript-eslint/no-explicit-any
maxLevels: number = 0,
level: number = 0,
undefinedIsNull: boolean = true,
): boolean {
if (typeof itemA == 'function' || typeof itemB == 'function') {
return true; // Don't compare functions.
}
if (typeof itemA === 'object' && typeof itemB === 'object') {
if (level >= maxLevels) {
return true; // Max deep reached.
}
let equal = true;
for (const name in itemA) {
const value = itemA[name];
if (name == '$$hashKey') {
// Ignore $$hashKey property since it's a "calculated" property.
continue;
}
if (!CoreObject.basicLeftCompare(value, itemB[name], maxLevels, level + 1)) {
equal = false;
}
}
return equal;
}
if (undefinedIsNull && (
(itemA === undefined && itemB === null) || (itemA === null && itemB === undefined))) {
return true;
}
// We'll treat "2" and 2 as the same value.
const floatA = parseFloat(itemA);
const floatB = parseFloat(itemB);
if (!isNaN(floatA) && !isNaN(floatB)) {
return floatA == floatB;
}
return itemA === itemB;
}
}