MOBILE-4653 utils: Move object and array related utils functions
This commit is contained in:
		
							parent
							
								
									453a2bd8c2
								
							
						
					
					
						commit
						96f3be2ff1
					
				@ -19,7 +19,7 @@ import { CoreBlockBaseComponent } from '@features/block/classes/base-block-compo
 | 
				
			|||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { ContextLevel, CoreConstants } from '@/core/constants';
 | 
					import { ContextLevel, CoreConstants } from '@/core/constants';
 | 
				
			||||||
import { Translate } from '@singletons';
 | 
					import { Translate } from '@singletons';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreNavigator } from '@services/navigator';
 | 
					import { CoreNavigator } from '@services/navigator';
 | 
				
			||||||
import { CoreCourseHelper } from '@features/course/services/course-helper';
 | 
					import { CoreCourseHelper } from '@features/course/services/course-helper';
 | 
				
			||||||
import { CoreUrl } from '@singletons/url';
 | 
					import { CoreUrl } from '@singletons/url';
 | 
				
			||||||
@ -106,7 +106,7 @@ export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent i
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Sort the modnames alphabetically.
 | 
					        // Sort the modnames alphabetically.
 | 
				
			||||||
        modFullNames = CoreUtils.sortValues(modFullNames);
 | 
					        modFullNames = CoreObject.sortValues(modFullNames);
 | 
				
			||||||
        for (const modName in modFullNames) {
 | 
					        for (const modName in modFullNames) {
 | 
				
			||||||
            const iconModName = modName === 'resources' ? 'page' : modName;
 | 
					            const iconModName = modName === 'resources' ? 'page' : modName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ import { CoreFileEntry, CoreFileHelper } from '@services/file-helper';
 | 
				
			|||||||
import { CoreNetwork } from '@services/network';
 | 
					import { CoreNetwork } from '@services/network';
 | 
				
			||||||
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
 | 
					import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					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 { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import { AddonBlogOffline, AddonBlogOfflineEntry } from './blog-offline';
 | 
					import { AddonBlogOffline, AddonBlogOfflineEntry } from './blog-offline';
 | 
				
			||||||
@ -63,7 +63,7 @@ export class AddonBlogProvider {
 | 
				
			|||||||
     * @returns Cache key.
 | 
					     * @returns Cache key.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    getEntriesCacheKey(filter: AddonBlogFilter = {}): string {
 | 
					    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 site = await CoreSites.getSite(options?.siteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const data: CoreBlogGetEntriesWSParams = {
 | 
					        const data: CoreBlogGetEntriesWSParams = {
 | 
				
			||||||
            filters: CoreUtils.objectToArrayOfObjects(filter, 'name', 'value'),
 | 
					            filters: CoreObject.toArrayOfObjects(filter, 'name', 'value'),
 | 
				
			||||||
            page: options?.page ?? 0,
 | 
					            page: options?.page ?? 0,
 | 
				
			||||||
            perpage: AddonBlogProvider.ENTRIES_PER_PAGE,
 | 
					            perpage: AddonBlogProvider.ENTRIES_PER_PAGE,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@ -290,7 +290,7 @@ export class AddonBlogProvider {
 | 
				
			|||||||
        const site = await CoreSites.getSite(siteId);
 | 
					        const site = await CoreSites.getSite(siteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const data: AddonBlogViewEntriesWSParams = {
 | 
					        const data: AddonBlogViewEntriesWSParams = {
 | 
				
			||||||
            filters: CoreUtils.objectToArrayOfObjects(filter, 'name', 'value'),
 | 
					            filters: CoreObject.toArrayOfObjects(filter, 'name', 'value'),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return site.write('core_blog_view_entries', data);
 | 
					        return site.write('core_blog_view_entries', data);
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,7 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
				
			|||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
					import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    AddonCalendar,
 | 
					    AddonCalendar,
 | 
				
			||||||
    AddonCalendarWeek,
 | 
					    AddonCalendarWeek,
 | 
				
			||||||
@ -464,7 +464,7 @@ class AddonCalendarMonthSlidesItemsManagerSource extends CoreSwipeSlidesDynamicI
 | 
				
			|||||||
            const categories = await CoreCourses.getCategories(0, true);
 | 
					            const categories = await CoreCourses.getCategories(0, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Index categories by ID.
 | 
					            // Index categories by ID.
 | 
				
			||||||
            this.categories = CoreUtils.arrayToObject(categories, 'id');
 | 
					            this.categories = CoreArray.toObject(categories, 'id');
 | 
				
			||||||
        } catch {
 | 
					        } catch {
 | 
				
			||||||
            // Ignore errors.
 | 
					            // Ignore errors.
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { Component, Input, OnInit } from '@angular/core';
 | 
					import { Component, Input, OnInit } from '@angular/core';
 | 
				
			||||||
import { CoreEnrolledCourseData } from '@features/courses/services/courses';
 | 
					import { CoreEnrolledCourseData } from '@features/courses/services/courses';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { ModalController } from '@singletons';
 | 
					import { ModalController } from '@singletons';
 | 
				
			||||||
import { CoreEvents } from '@singletons/events';
 | 
					import { CoreEvents } from '@singletons/events';
 | 
				
			||||||
import { AddonCalendarFilter } from '@addons/calendar/services/calendar-helper';
 | 
					import { AddonCalendarFilter } from '@addons/calendar/services/calendar-helper';
 | 
				
			||||||
@ -54,7 +54,7 @@ export class AddonCalendarFilterComponent implements OnInit {
 | 
				
			|||||||
    sortedCourses: CoreEnrolledCourseData[] = [];
 | 
					    sortedCourses: CoreEnrolledCourseData[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        CoreUtils.enumKeys(AddonCalendarEventType).forEach((name) => {
 | 
					        CoreObject.enumKeys(AddonCalendarEventType).forEach((name) => {
 | 
				
			||||||
            const value = AddonCalendarEventType[name];
 | 
					            const value = AddonCalendarEventType[name];
 | 
				
			||||||
            this.typeIcons[value] = AddonCalendarEventIcons[name];
 | 
					            this.typeIcons[value] = AddonCalendarEventIcons[name];
 | 
				
			||||||
            this.types.push(value);
 | 
					            this.types.push(value);
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@ import { NgZone, Translate } from '@singletons';
 | 
				
			|||||||
import { CoreNavigator } from '@services/navigator';
 | 
					import { CoreNavigator } from '@services/navigator';
 | 
				
			||||||
import { Params } from '@angular/router';
 | 
					import { Params } from '@angular/router';
 | 
				
			||||||
import { Subscription } from 'rxjs';
 | 
					import { Subscription } from 'rxjs';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { CoreConstants } from '@/core/constants';
 | 
					import { CoreConstants } from '@/core/constants';
 | 
				
			||||||
import { CoreSwipeSlidesDynamicItemsManager } from '@classes/items-management/swipe-slides-dynamic-items-manager';
 | 
					import { CoreSwipeSlidesDynamicItemsManager } from '@classes/items-management/swipe-slides-dynamic-items-manager';
 | 
				
			||||||
import { CoreSwipeSlidesComponent } from '@components/swipe-slides/swipe-slides';
 | 
					import { CoreSwipeSlidesComponent } from '@components/swipe-slides/swipe-slides';
 | 
				
			||||||
@ -58,6 +58,7 @@ import {
 | 
				
			|||||||
    ADDON_CALENDAR_UNDELETED_EVENT_EVENT,
 | 
					    ADDON_CALENDAR_UNDELETED_EVENT_EVENT,
 | 
				
			||||||
    AddonCalendarEventType,
 | 
					    AddonCalendarEventType,
 | 
				
			||||||
} from '@addons/calendar/constants';
 | 
					} from '@addons/calendar/constants';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Page that displays the calendar events for a certain day.
 | 
					 * Page that displays the calendar events for a certain day.
 | 
				
			||||||
@ -221,7 +222,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
 | 
				
			|||||||
    ngOnInit(): void {
 | 
					    ngOnInit(): void {
 | 
				
			||||||
        const types: string[] = [];
 | 
					        const types: string[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CoreUtils.enumKeys(AddonCalendarEventType).forEach((name) => {
 | 
					        CoreObject.enumKeys(AddonCalendarEventType).forEach((name) => {
 | 
				
			||||||
            const value = AddonCalendarEventType[name];
 | 
					            const value = AddonCalendarEventType[name];
 | 
				
			||||||
            this.filter[name] = CoreNavigator.getRouteBooleanParam(name) ?? true;
 | 
					            this.filter[name] = CoreNavigator.getRouteBooleanParam(name) ?? true;
 | 
				
			||||||
            types.push(value);
 | 
					            types.push(value);
 | 
				
			||||||
@ -606,7 +607,7 @@ class AddonCalendarDaySlidesItemsManagerSource extends CoreSwipeSlidesDynamicIte
 | 
				
			|||||||
            const categories = await CoreCourses.getCategories(0, true);
 | 
					            const categories = await CoreCourses.getCategories(0, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Index categories by ID.
 | 
					            // Index categories by ID.
 | 
				
			||||||
            this.categories = CoreUtils.arrayToObject(categories, 'id');
 | 
					            this.categories = CoreArray.toObject(categories, 'id');
 | 
				
			||||||
        } catch {
 | 
					        } catch {
 | 
				
			||||||
            // Ignore errors.
 | 
					            // Ignore errors.
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -25,7 +25,7 @@ import {
 | 
				
			|||||||
    AddonCalendarWeekDay,
 | 
					    AddonCalendarWeekDay,
 | 
				
			||||||
} from './calendar';
 | 
					} from './calendar';
 | 
				
			||||||
import { CoreConfig } from '@services/config';
 | 
					import { CoreConfig } from '@services/config';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreCourse } from '@features/course/services/course';
 | 
					import { CoreCourse } from '@features/course/services/course';
 | 
				
			||||||
import { ContextLevel, CoreConstants } from '@/core/constants';
 | 
					import { ContextLevel, CoreConstants } from '@/core/constants';
 | 
				
			||||||
import moment from 'moment-timezone';
 | 
					import moment from 'moment-timezone';
 | 
				
			||||||
@ -61,7 +61,7 @@ export class AddonCalendarHelperProvider {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    getEventIcon(eventType: AddonCalendarEventType | string): string {
 | 
					    getEventIcon(eventType: AddonCalendarEventType | string): string {
 | 
				
			||||||
        if (this.eventTypeIcons.length == 0) {
 | 
					        if (this.eventTypeIcons.length == 0) {
 | 
				
			||||||
            CoreUtils.enumKeys(AddonCalendarEventType).forEach((name) => {
 | 
					            CoreObject.enumKeys(AddonCalendarEventType).forEach((name) => {
 | 
				
			||||||
                const value = AddonCalendarEventType[name];
 | 
					                const value = AddonCalendarEventType[name];
 | 
				
			||||||
                this.eventTypeIcons[value] = AddonCalendarEventIcons[name];
 | 
					                this.eventTypeIcons[value] = AddonCalendarEventIcons[name];
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@
 | 
				
			|||||||
import { Injectable } from '@angular/core';
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
import { SQLiteDBRecordValues } from '@classes/sqlitedb';
 | 
					import { SQLiteDBRecordValues } from '@classes/sqlitedb';
 | 
				
			||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import { AddonCalendarSubmitCreateUpdateFormDataWSParams } from './calendar';
 | 
					import { AddonCalendarSubmitCreateUpdateFormDataWSParams } from './calendar';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -62,7 +62,7 @@ export class AddonCalendarOfflineProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const result = await Promise.all(promises);
 | 
					        const result = await Promise.all(promises);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return CoreUtils.mergeArraysWithoutDuplicates(result[0], result[1]);
 | 
					        return CoreArray.mergeWithoutDuplicates(result[0], result[1]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ import { CoreNetwork } from '@services/network';
 | 
				
			|||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUrl } from '@singletons/url';
 | 
					import { CoreUrl } from '@singletons/url';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreGroups } from '@services/groups';
 | 
					import { CoreGroups } from '@services/groups';
 | 
				
			||||||
import { CoreLocalNotifications } from '@services/local-notifications';
 | 
					import { CoreLocalNotifications } from '@services/local-notifications';
 | 
				
			||||||
import { CoreConfig } from '@services/config';
 | 
					import { CoreConfig } from '@services/config';
 | 
				
			||||||
@ -1578,7 +1578,7 @@ export class AddonCalendarProvider {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const params: AddonCalendarSubmitCreateUpdateFormWSParams = {
 | 
					        const params: AddonCalendarSubmitCreateUpdateFormWSParams = {
 | 
				
			||||||
            formdata: CoreUtils.objectToGetParams(formData),
 | 
					            formdata: CoreObject.toGetParams(formData),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        const result =
 | 
					        const result =
 | 
				
			||||||
            await site.write<AddonCalendarSubmitCreateUpdateFormWSResponse>('core_calendar_submit_create_update_form', params);
 | 
					            await site.write<AddonCalendarSubmitCreateUpdateFormWSResponse>('core_calendar_submit_create_update_form', params);
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ import {
 | 
				
			|||||||
    AddonModAssignSubmissionStatusValues,
 | 
					    AddonModAssignSubmissionStatusValues,
 | 
				
			||||||
} from './assign';
 | 
					} from './assign';
 | 
				
			||||||
import { AddonModAssignOffline } from './assign-offline';
 | 
					import { AddonModAssignOffline } from './assign-offline';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreFile } from '@services/file';
 | 
					import { CoreFile } from '@services/file';
 | 
				
			||||||
import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
 | 
					import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
 | 
				
			||||||
import { CoreGroups } from '@services/groups';
 | 
					import { CoreGroups } from '@services/groups';
 | 
				
			||||||
@ -314,7 +314,7 @@ export class AddonModAssignHelperProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        await Promise.all(promises);
 | 
					        await Promise.all(promises);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return CoreUtils.objectToArray(participantsIndexed);
 | 
					        return CoreObject.toArray(participantsIndexed);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ import { CoreSites } from '@services/sites';
 | 
				
			|||||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
					import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { Translate } from '@singletons';
 | 
					import { Translate } from '@singletons';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    AddonModBBB,
 | 
					    AddonModBBB,
 | 
				
			||||||
@ -146,7 +146,7 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
 | 
				
			|||||||
        const recordingsTable = await AddonModBBB.getRecordings(this.bbb.id, this.groupId, {
 | 
					        const recordingsTable = await AddonModBBB.getRecordings(this.bbb.id, this.groupId, {
 | 
				
			||||||
            cmId: this.module.id,
 | 
					            cmId: this.module.id,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        const columns = CoreUtils.arrayToObject(recordingsTable.columns, 'key');
 | 
					        const columns = CoreArray.toObject(recordingsTable.columns, 'key');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.recordings = recordingsTable.parsedData.map(recordingData => {
 | 
					        this.recordings = recordingsTable.parsedData.map(recordingData => {
 | 
				
			||||||
            const details: RecordingDetail[] = [];
 | 
					            const details: RecordingDetail[] = [];
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
 | 
				
			|||||||
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
 | 
					import { CoreCourseLogHelper } from '@features/course/services/log-helper';
 | 
				
			||||||
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
 | 
					import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
 | 
				
			||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
 | 
					import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
 | 
				
			||||||
import { makeSingleton, Translate } from '@singletons';
 | 
					import { makeSingleton, Translate } from '@singletons';
 | 
				
			||||||
import { ADDON_MOD_BBB_COMPONENT } from '../constants';
 | 
					import { ADDON_MOD_BBB_COMPONENT } from '../constants';
 | 
				
			||||||
@ -182,7 +182,7 @@ export class AddonModBBBService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            ...meetingInfo,
 | 
					            ...meetingInfo,
 | 
				
			||||||
            features: meetingInfo.features ? CoreUtils.objectToKeyValueMap(meetingInfo.features, 'name', 'isenabled') : undefined,
 | 
					            features: meetingInfo.features ? CoreObject.toKeyValueMap(meetingInfo.features, 'name', 'isenabled') : undefined,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -26,7 +26,7 @@ import { CoreNavigator } from '@services/navigator';
 | 
				
			|||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
					import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
					import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    AddonModData,
 | 
					    AddonModData,
 | 
				
			||||||
@ -53,6 +53,7 @@ import {
 | 
				
			|||||||
} from '../../constants';
 | 
					} from '../../constants';
 | 
				
			||||||
import { CoreModals } from '@services/modals';
 | 
					import { CoreModals } from '@services/modals';
 | 
				
			||||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
					import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const contentToken = '<!-- CORE-DATABASE-CONTENT-GOES-HERE -->';
 | 
					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 });
 | 
					        const fields = await AddonModData.getFields(this.database.id, { cmId: this.module.id });
 | 
				
			||||||
        this.search.advanced = [];
 | 
					        this.search.advanced = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.fields = CoreUtils.arrayToObject(fields, 'id');
 | 
					        this.fields = CoreArray.toObject(fields, 'id');
 | 
				
			||||||
        this.fieldsArray = CoreUtils.objectToArray(this.fields);
 | 
					        this.fieldsArray = CoreObject.toArray(this.fields);
 | 
				
			||||||
        if (this.fieldsArray.length == 0) {
 | 
					        if (this.fieldsArray.length == 0) {
 | 
				
			||||||
            canSearch = false;
 | 
					            canSearch = false;
 | 
				
			||||||
            canAdd = false;
 | 
					            canAdd = false;
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ import { CoreTag } from '@features/tag/services/tag';
 | 
				
			|||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreFormFields, CoreForms } from '@singletons/form';
 | 
					import { CoreFormFields, CoreForms } from '@singletons/form';
 | 
				
			||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { ModalController } from '@singletons';
 | 
					import { ModalController } from '@singletons';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    AddonModDataField,
 | 
					    AddonModDataField,
 | 
				
			||||||
@ -89,7 +89,7 @@ export class AddonModDataSearchModalComponent implements OnInit {
 | 
				
			|||||||
        this.searchForm.addControl('firstname', this.fb.control(this.advancedIndexed['firstname'] || ''));
 | 
					        this.searchForm.addControl('firstname', this.fb.control(this.advancedIndexed['firstname'] || ''));
 | 
				
			||||||
        this.searchForm.addControl('lastname', this.fb.control(this.advancedIndexed['lastname'] || ''));
 | 
					        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();
 | 
					        this.advancedSearch = this.renderAdvancedSearchFields();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -46,6 +46,7 @@ import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
 | 
				
			|||||||
import { ADDON_MOD_DATA_COMPONENT, ADDON_MOD_DATA_ENTRY_CHANGED, AddonModDataTemplateType } from '../../constants';
 | 
					import { ADDON_MOD_DATA_COMPONENT, ADDON_MOD_DATA_ENTRY_CHANGED, AddonModDataTemplateType } from '../../constants';
 | 
				
			||||||
import { CoreLoadings } from '@services/loadings';
 | 
					import { CoreLoadings } from '@services/loadings';
 | 
				
			||||||
import { CoreWSError } from '@classes/errors/wserror';
 | 
					import { CoreWSError } from '@classes/errors/wserror';
 | 
				
			||||||
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Page that displays the view edit page.
 | 
					 * 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.cssClass = 'addon-data-entries-' + this.database.id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.fieldsArray = await AddonModData.getFields(this.database.id, { cmId: this.moduleId });
 | 
					            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);
 | 
					            const entry = await AddonModDataHelper.fetchEntry(this.database, this.fieldsArray, this.entryId || 0);
 | 
				
			||||||
            this.entry = entry.entry;
 | 
					            this.entry = entry.entry;
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ import { CoreGroups, CoreGroupInfo } from '@services/groups';
 | 
				
			|||||||
import { CoreNavigator } from '@services/navigator';
 | 
					import { CoreNavigator } from '@services/navigator';
 | 
				
			||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
					import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
					import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
				
			||||||
import { AddonModDataComponentsCompileModule } from '../../components/components-compile.module';
 | 
					import { AddonModDataComponentsCompileModule } from '../../components/components-compile.module';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -183,7 +183,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
 | 
				
			|||||||
            this.title = this.database.name || this.title;
 | 
					            this.title = this.database.name || this.title;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.fieldsArray = await AddonModData.getFields(this.database.id, { cmId: this.moduleId });
 | 
					            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();
 | 
					            await this.setEntryFromOffset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -26,7 +26,7 @@ import { CoreFileEntry } from '@services/file-helper';
 | 
				
			|||||||
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
 | 
					import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
 | 
				
			||||||
import { CoreSync, CoreSyncResult } from '@services/sync';
 | 
					import { CoreSync, CoreSyncResult } from '@services/sync';
 | 
				
			||||||
import { CoreErrorHelper } from '@services/error-helper';
 | 
					import { CoreErrorHelper } from '@services/error-helper';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { Translate, makeSingleton } from '@singletons';
 | 
					import { Translate, makeSingleton } from '@singletons';
 | 
				
			||||||
import { CoreEvents } from '@singletons/events';
 | 
					import { CoreEvents } from '@singletons/events';
 | 
				
			||||||
import { AddonModData, AddonModDataData } from './data';
 | 
					import { AddonModData, AddonModDataData } from './data';
 | 
				
			||||||
@ -206,7 +206,7 @@ export class AddonModDataSyncProvider extends CoreCourseActivitySyncBaseProvider
 | 
				
			|||||||
            offlineEntries[entry.entryid].push(entry);
 | 
					            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));
 | 
					            this.syncEntry(database, entryActions, result, siteId));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await Promise.all(promises);
 | 
					        await Promise.all(promises);
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ import { CoreNetwork } from '@services/network';
 | 
				
			|||||||
import { CoreFileEntry } from '@services/file-helper';
 | 
					import { CoreFileEntry } from '@services/file-helper';
 | 
				
			||||||
import { CoreFilepool } from '@services/filepool';
 | 
					import { CoreFilepool } from '@services/filepool';
 | 
				
			||||||
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
 | 
					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 { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
 | 
				
			||||||
import { makeSingleton, Translate } from '@singletons';
 | 
					import { makeSingleton, Translate } from '@singletons';
 | 
				
			||||||
import { AddonModDataFieldsDelegate } from './data-fields-delegate';
 | 
					import { AddonModDataFieldsDelegate } from './data-fields-delegate';
 | 
				
			||||||
@ -251,7 +251,7 @@ export class AddonModDataProvider {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    protected checkFields(fields: AddonModDataField[], contents: AddonModDataSubfieldData[]): AddonModDataFieldNotification[] {
 | 
					    protected checkFields(fields: AddonModDataField[], contents: AddonModDataSubfieldData[]): AddonModDataFieldNotification[] {
 | 
				
			||||||
        const notifications: AddonModDataFieldNotification[] = [];
 | 
					        const notifications: AddonModDataFieldNotification[] = [];
 | 
				
			||||||
        const contentsIndexed = CoreUtils.arrayToObjectMultiple(contents, 'fieldid');
 | 
					        const contentsIndexed = CoreArray.toObjectMultiple(contents, 'fieldid');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // App is offline, check required fields.
 | 
					        // App is offline, check required fields.
 | 
				
			||||||
        fields.forEach((field) => {
 | 
					        fields.forEach((field) => {
 | 
				
			||||||
@ -741,7 +741,7 @@ export class AddonModDataProvider {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    protected formatEntryContents(entry: AddonModDataEntryWS): AddonModDataEntry {
 | 
					    protected formatEntryContents(entry: AddonModDataEntryWS): AddonModDataEntry {
 | 
				
			||||||
        return Object.assign(entry, {
 | 
					        return Object.assign(entry, {
 | 
				
			||||||
            contents: CoreUtils.arrayToObject(entry.contents, 'fieldid'),
 | 
					            contents: CoreArray.toObject(entry.contents, 'fieldid'),
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ import { CoreFilepool } from '@services/filepool';
 | 
				
			|||||||
import { CoreGroup, CoreGroups } from '@services/groups';
 | 
					import { CoreGroup, CoreGroups } from '@services/groups';
 | 
				
			||||||
import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites';
 | 
					import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreWSFile } from '@services/ws';
 | 
					import { CoreWSFile } from '@services/ws';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import { AddonModDataEntry, AddonModData, AddonModDataData } from '../data';
 | 
					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[] = [];
 | 
					        let files: CoreWSFile[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        entries.forEach((entry) => {
 | 
					        entries.forEach((entry) => {
 | 
				
			||||||
            CoreUtils.objectToArray(entry.contents).forEach((content) => {
 | 
					            CoreObject.toArray(entry.contents).forEach((content) => {
 | 
				
			||||||
                files = files.concat(<CoreWSFile[]>content.files);
 | 
					                files = files.concat(<CoreWSFile[]>content.files);
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
				
			|||||||
@ -46,6 +46,7 @@ import { CoreLoadings } from '@services/loadings';
 | 
				
			|||||||
import { CoreError } from '@classes/errors/error';
 | 
					import { CoreError } from '@classes/errors/error';
 | 
				
			||||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
					import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
				
			||||||
import { CoreWSError } from '@classes/errors/wserror';
 | 
					import { CoreWSError } from '@classes/errors/wserror';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Page that displays feedback form.
 | 
					 * Page that displays feedback form.
 | 
				
			||||||
@ -158,7 +159,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (this.items && !this.completed && this.originalData) {
 | 
					            if (this.items && !this.completed && this.originalData) {
 | 
				
			||||||
                // Form submitted. Check if there is any change.
 | 
					                // 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'));
 | 
					                    await CoreDomUtils.showConfirm(Translate.instant('core.confirmcanceledit'));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ import { CoreCourseLogHelper } from '@features/course/services/log-helper';
 | 
				
			|||||||
import { CoreNetwork } from '@services/network';
 | 
					import { CoreNetwork } from '@services/network';
 | 
				
			||||||
import { CoreFilepool } from '@services/filepool';
 | 
					import { CoreFilepool } from '@services/filepool';
 | 
				
			||||||
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
 | 
					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 { CoreWSExternalFile, CoreWSExternalWarning, CoreWSStoredFile } from '@services/ws';
 | 
				
			||||||
import { makeSingleton, Translate } from '@singletons';
 | 
					import { makeSingleton, Translate } from '@singletons';
 | 
				
			||||||
import { AddonModFeedbackOffline } from './feedback-offline';
 | 
					import { AddonModFeedbackOffline } from './feedback-offline';
 | 
				
			||||||
@ -170,7 +170,7 @@ export class AddonModFeedbackProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Merge all values into one array.
 | 
					        // Merge all values into one array.
 | 
				
			||||||
        const offlineValuesArray = offlineResponses.reduce((array, entry) => {
 | 
					        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);
 | 
					            return array.concat(responses);
 | 
				
			||||||
        }, <OfflineResponsesArray> []).map((valueEntry) => {
 | 
					        }, <OfflineResponsesArray> []).map((valueEntry) => {
 | 
				
			||||||
@ -1228,7 +1228,7 @@ export class AddonModFeedbackProvider {
 | 
				
			|||||||
        const params: AddonModFeedbackProcessPageWSParams = {
 | 
					        const params: AddonModFeedbackProcessPageWSParams = {
 | 
				
			||||||
            feedbackid: feedbackId,
 | 
					            feedbackid: feedbackId,
 | 
				
			||||||
            page: page,
 | 
					            page: page,
 | 
				
			||||||
            responses: CoreUtils.objectToArrayOfObjects(responses, 'name', 'value'),
 | 
					            responses: CoreObject.toArrayOfObjects(responses, 'name', 'value'),
 | 
				
			||||||
            goprevious: goPrevious,
 | 
					            goprevious: goPrevious,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -63,6 +63,7 @@ import { CoreCourseContentsPage } from '@features/course/pages/contents/contents
 | 
				
			|||||||
import { CoreToasts } from '@services/toasts';
 | 
					import { CoreToasts } from '@services/toasts';
 | 
				
			||||||
import { CoreLoadings } from '@services/loadings';
 | 
					import { CoreLoadings } from '@services/loadings';
 | 
				
			||||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
					import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SortType = 'flat-newest' | 'flat-oldest' | 'nested';
 | 
					type SortType = 'flat-newest' | 'flat-oldest' | 'nested';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -463,7 +464,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
 | 
				
			|||||||
            await Promise.all(convertPromises);
 | 
					            await Promise.all(convertPromises);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Convert back to array.
 | 
					            // Convert back to array.
 | 
				
			||||||
            onlinePosts = CoreUtils.objectToArray(onlinePostsMap);
 | 
					            onlinePosts = CoreObject.toArray(onlinePostsMap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let posts = offlineReplies.concat(onlinePosts);
 | 
					            let posts = offlineReplies.concat(onlinePosts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,7 @@ import {
 | 
				
			|||||||
import { CoreCacheUpdateFrequency } from '@/core/constants';
 | 
					import { CoreCacheUpdateFrequency } from '@/core/constants';
 | 
				
			||||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
					import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
				
			||||||
import { CoreWSError } from '@classes/errors/wserror';
 | 
					import { CoreWSError } from '@classes/errors/wserror';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
declare module '@singletons/events' {
 | 
					declare module '@singletons/events' {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -221,7 +222,7 @@ export class AddonModForumProvider {
 | 
				
			|||||||
            message: message,
 | 
					            message: message,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // eslint-disable-next-line max-len
 | 
					            // eslint-disable-next-line max-len
 | 
				
			||||||
            options: CoreUtils.objectToArrayOfObjects<AddonModForumAddDiscussionWSOptionsArray[0], AddonModForumAddDiscussionWSOptionsObject>(
 | 
					            options: CoreObject.toArrayOfObjects<AddonModForumAddDiscussionWSOptionsArray[0], AddonModForumAddDiscussionWSOptionsObject>(
 | 
				
			||||||
                options || {},
 | 
					                options || {},
 | 
				
			||||||
                'name',
 | 
					                'name',
 | 
				
			||||||
                'value',
 | 
					                'value',
 | 
				
			||||||
@ -1147,7 +1148,7 @@ export class AddonModForumProvider {
 | 
				
			|||||||
            subject: subject,
 | 
					            subject: subject,
 | 
				
			||||||
            message: message,
 | 
					            message: message,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            options: CoreUtils.objectToArrayOfObjects<
 | 
					            options: CoreObject.toArrayOfObjects<
 | 
				
			||||||
            AddonModForumAddDiscussionPostWSOptionsArray[0],
 | 
					            AddonModForumAddDiscussionPostWSOptionsArray[0],
 | 
				
			||||||
            AddonModForumAddDiscussionPostWSOptionsObject
 | 
					            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,
 | 
					            subject: subject,
 | 
				
			||||||
            message: message,
 | 
					            message: message,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            options: CoreUtils.objectToArrayOfObjects<
 | 
					            options: CoreObject.toArrayOfObjects<
 | 
				
			||||||
            AddonModForumUpdateDiscussionPostWSOptionsArray[0],
 | 
					            AddonModForumUpdateDiscussionPostWSOptionsArray[0],
 | 
				
			||||||
            AddonModForumUpdateDiscussionPostWSOptionsObject
 | 
					            AddonModForumUpdateDiscussionPostWSOptionsObject
 | 
				
			||||||
            >(
 | 
					            >(
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ import { CoreRatingInfo } from '@features/rating/services/rating';
 | 
				
			|||||||
import { CoreTagItem } from '@features/tag/services/tag';
 | 
					import { CoreTagItem } from '@features/tag/services/tag';
 | 
				
			||||||
import { CoreNetwork } from '@services/network';
 | 
					import { CoreNetwork } from '@services/network';
 | 
				
			||||||
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
 | 
					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 { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
 | 
				
			||||||
import { makeSingleton, Translate } from '@singletons';
 | 
					import { makeSingleton, Translate } from '@singletons';
 | 
				
			||||||
import { CoreEvents } from '@singletons/events';
 | 
					import { CoreEvents } from '@singletons/events';
 | 
				
			||||||
@ -911,7 +911,7 @@ export class AddonModGlossaryProvider {
 | 
				
			|||||||
            concept: concept,
 | 
					            concept: concept,
 | 
				
			||||||
            definition: definition,
 | 
					            definition: definition,
 | 
				
			||||||
            definitionformat: 1,
 | 
					            definitionformat: 1,
 | 
				
			||||||
            options: CoreUtils.objectToArrayOfObjects(options || {}, 'name', 'value'),
 | 
					            options: CoreObject.toArrayOfObjects(options || {}, 'name', 'value'),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (attachId) {
 | 
					        if (attachId) {
 | 
				
			||||||
@ -955,7 +955,7 @@ export class AddonModGlossaryProvider {
 | 
				
			|||||||
            concept: concept,
 | 
					            concept: concept,
 | 
				
			||||||
            definition: definition,
 | 
					            definition: definition,
 | 
				
			||||||
            definitionformat: 1,
 | 
					            definitionformat: 1,
 | 
				
			||||||
            options: CoreUtils.objectToArrayOfObjects(options || {}, 'name', 'value'),
 | 
					            options: CoreObject.toArrayOfObjects(options || {}, 'name', 'value'),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (attachId) {
 | 
					        if (attachId) {
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,7 @@ import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@
 | 
				
			|||||||
import { CoreSync } from '@services/sync';
 | 
					import { CoreSync } from '@services/sync';
 | 
				
			||||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
					import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			||||||
import { CoreUrl } from '@singletons/url';
 | 
					import { CoreUrl } from '@singletons/url';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreWSExternalFile } from '@services/ws';
 | 
					import { CoreWSExternalFile } from '@services/ws';
 | 
				
			||||||
import { ModalController, Translate } from '@singletons';
 | 
					import { ModalController, Translate } from '@singletons';
 | 
				
			||||||
import { CoreEvents } from '@singletons/events';
 | 
					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) {
 | 
					        if (this.question && !this.eolData && !this.processData && this.originalData) {
 | 
				
			||||||
            // Question shown. Check if there is any change.
 | 
					            // 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'));
 | 
					                await CoreDomUtils.showConfirm(Translate.instant('core.confirmcanceledit'));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ import { CoreSites } from '@services/sites';
 | 
				
			|||||||
import { CoreFormFields } from '@singletons/form';
 | 
					import { CoreFormFields } from '@singletons/form';
 | 
				
			||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    AddonModLessonPageAttemptDBRecord,
 | 
					    AddonModLessonPageAttemptDBRecord,
 | 
				
			||||||
@ -152,7 +152,7 @@ export class AddonModLessonOfflineProvider {
 | 
				
			|||||||
        this.getLessonsFromEntries(lessons, pageAttempts || []);
 | 
					        this.getLessonsFromEntries(lessons, pageAttempts || []);
 | 
				
			||||||
        this.getLessonsFromEntries(lessons, retakes || []);
 | 
					        this.getLessonsFromEntries(lessons, retakes || []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return CoreUtils.objectToArray(lessons);
 | 
					        return CoreObject.toArray(lessons);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -37,6 +37,8 @@ import {
 | 
				
			|||||||
import { CoreGradeType } from '@features/grades/constants';
 | 
					import { CoreGradeType } from '@features/grades/constants';
 | 
				
			||||||
import { CoreCacheUpdateFrequency } from '@/core/constants';
 | 
					import { CoreCacheUpdateFrequency } from '@/core/constants';
 | 
				
			||||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
					import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
declare module '@singletons/events' {
 | 
					declare module '@singletons/events' {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -286,7 +288,7 @@ export class AddonModLessonProvider {
 | 
				
			|||||||
        const validPages = {};
 | 
					        const validPages = {};
 | 
				
			||||||
        let pageId = accessInfo.firstpageid;
 | 
					        let pageId = accessInfo.firstpageid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        viewedPagesIds = CoreUtils.mergeArraysWithoutDuplicates(viewedPagesIds, viewedContentPagesIds);
 | 
					        viewedPagesIds = CoreArray.mergeWithoutDuplicates(viewedPagesIds, viewedContentPagesIds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Filter out the following pages:
 | 
					        // Filter out the following pages:
 | 
				
			||||||
        // - End of Cluster
 | 
					        // - 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.
 | 
					        // The name was changed to "answer_editor" in 3.7. Before it was just "answer". Support both cases.
 | 
				
			||||||
        if (data['answer_editor[text]'] !== undefined) {
 | 
					        if (data['answer_editor[text]'] !== undefined) {
 | 
				
			||||||
            studentAnswer = data['answer_editor[text]'];
 | 
					            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;
 | 
					            studentAnswer = (<{text: string}> data.answer_editor).text;
 | 
				
			||||||
        } else if (data['answer[text]'] !== undefined) {
 | 
					        } else if (data['answer[text]'] !== undefined) {
 | 
				
			||||||
            studentAnswer = data['answer[text]'];
 | 
					            studentAnswer = data['answer[text]'];
 | 
				
			||||||
        } else if (typeof data.answer == 'object') {
 | 
					        } else if (typeof data.answer === 'object') {
 | 
				
			||||||
            studentAnswer = (<{text: string}> data.answer).text;
 | 
					            studentAnswer = (<{text: string}> data.answer).text;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            studentAnswer = data.answer;
 | 
					            studentAnswer = data.answer;
 | 
				
			||||||
@ -3087,7 +3089,7 @@ export class AddonModLessonProvider {
 | 
				
			|||||||
        const params: AddonModLessonProcessPageWSParams = {
 | 
					        const params: AddonModLessonProcessPageWSParams = {
 | 
				
			||||||
            lessonid: lessonId,
 | 
					            lessonid: lessonId,
 | 
				
			||||||
            pageid: pageId,
 | 
					            pageid: pageId,
 | 
				
			||||||
            data: CoreUtils.objectToArrayOfObjects<ProcessPageData>(data, 'name', 'value', true),
 | 
					            data: CoreObject.toArrayOfObjects<ProcessPageData>(data, 'name', 'value', true),
 | 
				
			||||||
            review: !!options.review,
 | 
					            review: !!options.review,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -53,6 +53,8 @@ import {
 | 
				
			|||||||
} from '../constants';
 | 
					} from '../constants';
 | 
				
			||||||
import { CoreIonicColorNames } from '@singletons/colors';
 | 
					import { CoreIonicColorNames } from '@singletons/colors';
 | 
				
			||||||
import { CoreCacheUpdateFrequency } from '@/core/constants';
 | 
					import { CoreCacheUpdateFrequency } from '@/core/constants';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
declare module '@singletons/events' {
 | 
					declare module '@singletons/events' {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -227,7 +229,7 @@ export class AddonModQuizProvider {
 | 
				
			|||||||
        const params: AddonModQuizGetAttemptDataWSParams = {
 | 
					        const params: AddonModQuizGetAttemptDataWSParams = {
 | 
				
			||||||
            attemptid: attemptId,
 | 
					            attemptid: attemptId,
 | 
				
			||||||
            page: page,
 | 
					            page: page,
 | 
				
			||||||
            preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
					            preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
				
			||||||
                preflightData,
 | 
					                preflightData,
 | 
				
			||||||
                'name',
 | 
					                'name',
 | 
				
			||||||
                'value',
 | 
					                'value',
 | 
				
			||||||
@ -550,7 +552,7 @@ export class AddonModQuizProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const params: AddonModQuizGetAttemptSummaryWSParams = {
 | 
					        const params: AddonModQuizGetAttemptSummaryWSParams = {
 | 
				
			||||||
            attemptid: attemptId,
 | 
					            attemptid: attemptId,
 | 
				
			||||||
            preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
					            preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
				
			||||||
                preflightData,
 | 
					                preflightData,
 | 
				
			||||||
                'name',
 | 
					                'name',
 | 
				
			||||||
                'value',
 | 
					                'value',
 | 
				
			||||||
@ -629,8 +631,8 @@ export class AddonModQuizProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Convert the arrays to objects with name -> value.
 | 
					        // Convert the arrays to objects with name -> value.
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            someoptions: <Record<string, number>> CoreUtils.objectToKeyValueMap(response.someoptions, 'name', 'value'),
 | 
					            someoptions: <Record<string, number>> CoreObject.toKeyValueMap(response.someoptions, 'name', 'value'),
 | 
				
			||||||
            alloptions: <Record<string, number>> CoreUtils.objectToKeyValueMap(response.alloptions, 'name', 'value'),
 | 
					            alloptions: <Record<string, number>> CoreObject.toKeyValueMap(response.alloptions, 'name', 'value'),
 | 
				
			||||||
            warnings: response.warnings,
 | 
					            warnings: response.warnings,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1640,7 +1642,7 @@ export class AddonModQuizProvider {
 | 
				
			|||||||
        const params: AddonModQuizViewAttemptWSParams = {
 | 
					        const params: AddonModQuizViewAttemptWSParams = {
 | 
				
			||||||
            attemptid: attemptId,
 | 
					            attemptid: attemptId,
 | 
				
			||||||
            page: page,
 | 
					            page: page,
 | 
				
			||||||
            preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
					            preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
				
			||||||
                preflightData,
 | 
					                preflightData,
 | 
				
			||||||
                'name',
 | 
					                'name',
 | 
				
			||||||
                'value',
 | 
					                'value',
 | 
				
			||||||
@ -1695,7 +1697,7 @@ export class AddonModQuizProvider {
 | 
				
			|||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const params: AddonModQuizViewAttemptSummaryWSParams = {
 | 
					        const params: AddonModQuizViewAttemptSummaryWSParams = {
 | 
				
			||||||
            attemptid: attemptId,
 | 
					            attemptid: attemptId,
 | 
				
			||||||
            preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
					            preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
				
			||||||
                preflightData,
 | 
					                preflightData,
 | 
				
			||||||
                'name',
 | 
					                'name',
 | 
				
			||||||
                'value',
 | 
					                'value',
 | 
				
			||||||
@ -1785,10 +1787,10 @@ export class AddonModQuizProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const params: AddonModQuizProcessAttemptWSParams = {
 | 
					        const params: AddonModQuizProcessAttemptWSParams = {
 | 
				
			||||||
            attemptid: attemptId,
 | 
					            attemptid: attemptId,
 | 
				
			||||||
            data: CoreUtils.objectToArrayOfObjects(data, 'name', 'value'),
 | 
					            data: CoreObject.toArrayOfObjects(data, 'name', 'value'),
 | 
				
			||||||
            finishattempt: !!finish,
 | 
					            finishattempt: !!finish,
 | 
				
			||||||
            timeup: !!timeUp,
 | 
					            timeup: !!timeUp,
 | 
				
			||||||
            preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
					            preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
				
			||||||
                preflightData,
 | 
					                preflightData,
 | 
				
			||||||
                'name',
 | 
					                'name',
 | 
				
			||||||
                'value',
 | 
					                'value',
 | 
				
			||||||
@ -1834,7 +1836,7 @@ export class AddonModQuizProvider {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Convert the question array to an object.
 | 
					        // 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);
 | 
					        return AddonModQuizOffline.processAttempt(quiz, attempt, questions, data, finish, siteId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1939,8 +1941,8 @@ export class AddonModQuizProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const params: AddonModQuizSaveAttemptWSParams = {
 | 
					        const params: AddonModQuizSaveAttemptWSParams = {
 | 
				
			||||||
            attemptid: attemptId,
 | 
					            attemptid: attemptId,
 | 
				
			||||||
            data: CoreUtils.objectToArrayOfObjects(data, 'name', 'value'),
 | 
					            data: CoreObject.toArrayOfObjects(data, 'name', 'value'),
 | 
				
			||||||
            preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
					            preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
				
			||||||
                preflightData,
 | 
					                preflightData,
 | 
				
			||||||
                'name',
 | 
					                'name',
 | 
				
			||||||
                'value',
 | 
					                'value',
 | 
				
			||||||
@ -1995,7 +1997,7 @@ export class AddonModQuizProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const params: AddonModQuizStartAttemptWSParams = {
 | 
					        const params: AddonModQuizStartAttemptWSParams = {
 | 
				
			||||||
            quizid: quizId,
 | 
					            quizid: quizId,
 | 
				
			||||||
            preflightdata: CoreUtils.objectToArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
					            preflightdata: CoreObject.toArrayOfObjects<AddonModQuizPreflightDataWSParam>(
 | 
				
			||||||
                preflightData,
 | 
					                preflightData,
 | 
				
			||||||
                'name',
 | 
					                'name',
 | 
				
			||||||
                'value',
 | 
					                'value',
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ import { IonContent } from '@ionic/angular';
 | 
				
			|||||||
import { CoreNavigator } from '@services/navigator';
 | 
					import { CoreNavigator } from '@services/navigator';
 | 
				
			||||||
import { CoreSync } from '@services/sync';
 | 
					import { CoreSync } from '@services/sync';
 | 
				
			||||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
					import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { Translate } from '@singletons';
 | 
					import { Translate } from '@singletons';
 | 
				
			||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
					import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
				
			||||||
import { AddonModScormPrefetchHandler } from '../../services/handlers/prefetch';
 | 
					import { AddonModScormPrefetchHandler } from '../../services/handlers/prefetch';
 | 
				
			||||||
@ -340,8 +340,8 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
 | 
				
			|||||||
        this.grade = AddonModScorm.calculateScormGrade(scorm, onlineAttempts);
 | 
					        this.grade = AddonModScorm.calculateScormGrade(scorm, onlineAttempts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Add the attempts to the SCORM in array format in ASC order, and format the grades.
 | 
					        // Add the attempts to the SCORM in array format in ASC order, and format the grades.
 | 
				
			||||||
        this.onlineAttempts = CoreUtils.objectToArray(onlineAttempts);
 | 
					        this.onlineAttempts = CoreObject.toArray(onlineAttempts);
 | 
				
			||||||
        this.offlineAttempts = CoreUtils.objectToArray(offlineAttempts);
 | 
					        this.offlineAttempts = CoreObject.toArray(offlineAttempts);
 | 
				
			||||||
        this.onlineAttempts.sort((a, b) => a.num - b.num);
 | 
					        this.onlineAttempts.sort((a, b) => a.num - b.num);
 | 
				
			||||||
        this.offlineAttempts.sort((a, b) => a.num - b.num);
 | 
					        this.offlineAttempts.sort((a, b) => a.num - b.num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ import { CoreSync } from '@services/sync';
 | 
				
			|||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUrl } from '@singletons/url';
 | 
					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 { CoreWS, CoreWSExternalFile, CoreWSExternalWarning, CoreWSFile, CoreWSPreSets } from '@services/ws';
 | 
				
			||||||
import { makeSingleton, Translate } from '@singletons';
 | 
					import { makeSingleton, Translate } from '@singletons';
 | 
				
			||||||
import { CoreEvents } from '@singletons/events';
 | 
					import { CoreEvents } from '@singletons/events';
 | 
				
			||||||
@ -808,12 +808,12 @@ export class AddonModScormProvider {
 | 
				
			|||||||
        response.data.forEach((sco) => {
 | 
					        response.data.forEach((sco) => {
 | 
				
			||||||
            data[sco.scoid] = {
 | 
					            data[sco.scoid] = {
 | 
				
			||||||
                scoid: sco.scoid,
 | 
					                scoid: sco.scoid,
 | 
				
			||||||
                defaultdata: <Record<string, AddonModScormDataValue>> CoreUtils.objectToKeyValueMap(
 | 
					                defaultdata: <Record<string, AddonModScormDataValue>> CoreObject.toKeyValueMap(
 | 
				
			||||||
                    sco.defaultdata,
 | 
					                    sco.defaultdata,
 | 
				
			||||||
                    'element',
 | 
					                    'element',
 | 
				
			||||||
                    'value',
 | 
					                    '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) {
 | 
					        if (response.options) {
 | 
				
			||||||
            const scormOptions = CoreUtils.objectToKeyValueMap(response.options, 'name', 'value');
 | 
					            const scormOptions = CoreObject.toKeyValueMap(response.options, 'name', 'value');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (scormOptions.scormstandard) {
 | 
					            if (scormOptions.scormstandard) {
 | 
				
			||||||
                currentScorm.scormStandard = Number(scormOptions.scormstandard);
 | 
					                currentScorm.scormStandard = Number(scormOptions.scormstandard);
 | 
				
			||||||
 | 
				
			|||||||
@ -45,6 +45,7 @@ import { toBoolean } from '@/core/transforms/boolean';
 | 
				
			|||||||
import { CoreLoadings } from '@services/loadings';
 | 
					import { CoreLoadings } from '@services/loadings';
 | 
				
			||||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
					import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
				
			||||||
import { CoreWSError } from '@classes/errors/wserror';
 | 
					import { CoreWSError } from '@classes/errors/wserror';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Component that displays workshop assessment strategy form.
 | 
					 * Component that displays workshop assessment strategy form.
 | 
				
			||||||
@ -188,7 +189,7 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit, OnDe
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                // Override assessment plugins values.
 | 
					                // Override assessment plugins values.
 | 
				
			||||||
                this.data.assessment.form.current = AddonModWorkshop.parseFields(
 | 
					                this.data.assessment.form.current = AddonModWorkshop.parseFields(
 | 
				
			||||||
                    CoreUtils.objectToArrayOfObjects(offlineData, 'name', 'value'),
 | 
					                    CoreObject.toArrayOfObjects(offlineData, 'name', 'value'),
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Override offline files.
 | 
					                // Override offline files.
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ import { CoreGroupInfo, CoreGroups } from '@services/groups';
 | 
				
			|||||||
import { CoreNavigator } from '@services/navigator';
 | 
					import { CoreNavigator } from '@services/navigator';
 | 
				
			||||||
import { CorePlatform } from '@services/platform';
 | 
					import { CorePlatform } from '@services/platform';
 | 
				
			||||||
import { CoreModals } from '@services/modals';
 | 
					import { CoreModals } from '@services/modals';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
					import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
				
			||||||
import { Subscription } from 'rxjs';
 | 
					import { Subscription } from 'rxjs';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -405,7 +405,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
 | 
				
			|||||||
        const modalData = await CoreModals.openModal<boolean>({
 | 
					        const modalData = await CoreModals.openModal<boolean>({
 | 
				
			||||||
            component: AddonModWorkshopPhaseInfoModalComponent,
 | 
					            component: AddonModWorkshopPhaseInfoModalComponent,
 | 
				
			||||||
            componentProps: {
 | 
					            componentProps: {
 | 
				
			||||||
                phases: CoreUtils.objectToArray(this.phases),
 | 
					                phases: CoreObject.toArray(this.phases),
 | 
				
			||||||
                workshopPhase: this.workshop.phase,
 | 
					                workshopPhase: this.workshop.phase,
 | 
				
			||||||
                externalUrl: this.module.url,
 | 
					                externalUrl: this.module.url,
 | 
				
			||||||
                showSubmit: this.showSubmit,
 | 
					                showSubmit: this.showSubmit,
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ import { CoreUser } from '@features/user/services/user';
 | 
				
			|||||||
import { CoreFilepool } from '@services/filepool';
 | 
					import { CoreFilepool } from '@services/filepool';
 | 
				
			||||||
import { CoreGroup, CoreGroups } from '@services/groups';
 | 
					import { CoreGroup, CoreGroups } from '@services/groups';
 | 
				
			||||||
import { CoreSites, CoreSitesReadingStrategy, CoreSitesCommonWSOptions } from '@services/sites';
 | 
					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 { CoreWSExternalFile, CoreWSFile } from '@services/ws';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -248,7 +248,7 @@ export class AddonModWorkshopPrefetchHandlerLazyService extends AddonModWorkshop
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return CoreUtils.objectToArray(uniqueGrades);
 | 
					        return CoreObject.toArray(uniqueGrades);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ import { CoreGradesMenuItem } from '@features/grades/services/grades-helper';
 | 
				
			|||||||
import { CoreNetwork } from '@services/network';
 | 
					import { CoreNetwork } from '@services/network';
 | 
				
			||||||
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
 | 
					import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
 | 
				
			||||||
import { CoreTextFormat, defaultTextFormat } from '@singletons/text';
 | 
					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 { CoreStatusWithWarningsWSResponse, CoreWS, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
 | 
				
			||||||
import { makeSingleton, Translate } from '@singletons';
 | 
					import { makeSingleton, Translate } from '@singletons';
 | 
				
			||||||
import { CoreFormFields } from '@singletons/form';
 | 
					import { CoreFormFields } from '@singletons/form';
 | 
				
			||||||
@ -41,6 +41,7 @@ import {
 | 
				
			|||||||
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
 | 
					import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
 | 
				
			||||||
import { CoreCacheUpdateFrequency } from '@/core/constants';
 | 
					import { CoreCacheUpdateFrequency } from '@/core/constants';
 | 
				
			||||||
import { CoreWSError } from '@classes/errors/wserror';
 | 
					import { CoreWSError } from '@classes/errors/wserror';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
declare module '@singletons/events' {
 | 
					declare module '@singletons/events' {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -366,7 +367,7 @@ export class AddonModWorkshopProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const response = await site.read<AddonModWorkshopGetUserPlanWSResponse>('mod_workshop_get_user_plan', params, preSets);
 | 
					        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,
 | 
					            warnings: response.warnings,
 | 
				
			||||||
            fields: this.parseFields(response.fields),
 | 
					            fields: this.parseFields(response.fields),
 | 
				
			||||||
            current: this.parseFields(response.current),
 | 
					            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 = {
 | 
					        const params: AddonModWorkshopUpdateAssessmentWSParams = {
 | 
				
			||||||
            assessmentid: assessmentId,
 | 
					            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);
 | 
					        const response = await site.write<AddonModWorkshopUpdateAssessmentWSResponse>('mod_workshop_update_assessment', params);
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { Injectable } from '@angular/core';
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import { AddonMessageOutputDelegate } from '@addons/messageoutput/services/messageoutput-delegate';
 | 
					import { AddonMessageOutputDelegate } from '@addons/messageoutput/services/messageoutput-delegate';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -53,7 +53,7 @@ export class AddonNotificationsHelperProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        formattedPreferences.components.forEach((component) => {
 | 
					        formattedPreferences.components.forEach((component) => {
 | 
				
			||||||
            component.notifications.forEach((notification) => {
 | 
					            component.notifications.forEach((notification) => {
 | 
				
			||||||
                notification.processorsByName = CoreUtils.arrayToObject(notification.processors, 'name');
 | 
					                notification.processorsByName = CoreArray.toObject(notification.processors, 'name');
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ import { Injectable, Type } from '@angular/core';
 | 
				
			|||||||
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
 | 
					import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
 | 
				
			||||||
import { CoreQuestionHandler } from '@features/question/services/question-delegate';
 | 
					import { CoreQuestionHandler } from '@features/question/services/question-delegate';
 | 
				
			||||||
import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
 | 
					import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -133,8 +133,8 @@ export class AddonQtypeCalculatedHandlerService implements CoreQuestionHandler {
 | 
				
			|||||||
        prevAnswers: CoreQuestionsAnswers,
 | 
					        prevAnswers: CoreQuestionsAnswers,
 | 
				
			||||||
        newAnswers: CoreQuestionsAnswers,
 | 
					        newAnswers: CoreQuestionsAnswers,
 | 
				
			||||||
    ): boolean {
 | 
					    ): boolean {
 | 
				
			||||||
        return CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer') &&
 | 
					        return CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer') &&
 | 
				
			||||||
            CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'unit');
 | 
					            CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'unit');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,7 @@ import { CoreFileSession } from '@services/file-session';
 | 
				
			|||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
 | 
					import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
 | 
				
			||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreWSFile } from '@services/ws';
 | 
					import { CoreWSFile } from '@services/ws';
 | 
				
			||||||
import { makeSingleton, Translate } from '@singletons';
 | 
					import { makeSingleton, Translate } from '@singletons';
 | 
				
			||||||
import { CoreFileHelper } from '@services/file-helper';
 | 
					import { CoreFileHelper } from '@services/file-helper';
 | 
				
			||||||
@ -267,7 +267,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // First check the inline text.
 | 
					        // First check the inline text.
 | 
				
			||||||
        const answerIsEqual = allowedOptions.text ?
 | 
					        const answerIsEqual = allowedOptions.text ?
 | 
				
			||||||
            CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer') : true;
 | 
					            CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer') : true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!allowedOptions.attachments || !uploadFilesSupported || !answerIsEqual) {
 | 
					        if (!allowedOptions.attachments || !uploadFilesSupported || !answerIsEqual) {
 | 
				
			||||||
            // No need to check attachments.
 | 
					            // No need to check attachments.
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ import { Injectable, Type } from '@angular/core';
 | 
				
			|||||||
import { AddonModQuizMultichoiceQuestion } from '@features/question/classes/base-question-component';
 | 
					import { AddonModQuizMultichoiceQuestion } from '@features/question/classes/base-question-component';
 | 
				
			||||||
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
 | 
					import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
 | 
				
			||||||
import { CoreQuestionHandler } from '@features/question/services/question-delegate';
 | 
					import { CoreQuestionHandler } from '@features/question/services/question-delegate';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -120,7 +120,7 @@ export class AddonQtypeMultichoiceHandlerService implements CoreQuestionHandler
 | 
				
			|||||||
        for (const name in newAnswers) {
 | 
					        for (const name in newAnswers) {
 | 
				
			||||||
            if (name.indexOf('choice') !== -1) {
 | 
					            if (name.indexOf('choice') !== -1) {
 | 
				
			||||||
                isSingle = false;
 | 
					                isSingle = false;
 | 
				
			||||||
                if (!CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, name)) {
 | 
					                if (!CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, name)) {
 | 
				
			||||||
                    isMultiSame = false;
 | 
					                    isMultiSame = false;
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -142,7 +142,7 @@ export class AddonQtypeMultichoiceHandlerService implements CoreQuestionHandler
 | 
				
			|||||||
     * @returns Whether they're the same.
 | 
					     * @returns Whether they're the same.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    isSameResponseSingle(prevAnswers: CoreQuestionsAnswers, newAnswers: CoreQuestionsAnswers): boolean {
 | 
					    isSameResponseSingle(prevAnswers: CoreQuestionsAnswers, newAnswers: CoreQuestionsAnswers): boolean {
 | 
				
			||||||
        return CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
 | 
					        return CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ import { Injectable, Type } from '@angular/core';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
 | 
					import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
 | 
				
			||||||
import { CoreQuestionHandler } from '@features/question/services/question-delegate';
 | 
					import { CoreQuestionHandler } from '@features/question/services/question-delegate';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -72,7 +72,7 @@ export class AddonQtypeShortAnswerHandlerService implements CoreQuestionHandler
 | 
				
			|||||||
        prevAnswers: CoreQuestionsAnswers,
 | 
					        prevAnswers: CoreQuestionsAnswers,
 | 
				
			||||||
        newAnswers: CoreQuestionsAnswers,
 | 
					        newAnswers: CoreQuestionsAnswers,
 | 
				
			||||||
    ): boolean {
 | 
					    ): boolean {
 | 
				
			||||||
        return CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
 | 
					        return CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ import { Injectable, Type } from '@angular/core';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { CoreQuestionHandler } from '@features/question/services/question-delegate';
 | 
					import { CoreQuestionHandler } from '@features/question/services/question-delegate';
 | 
				
			||||||
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
 | 
					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 { AddonModQuizMultichoiceQuestion } from '@features/question/classes/base-question-component';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -74,7 +74,7 @@ export class AddonQtypeTrueFalseHandlerService implements CoreQuestionHandler {
 | 
				
			|||||||
        prevAnswers: CoreQuestionsAnswers,
 | 
					        prevAnswers: CoreQuestionsAnswers,
 | 
				
			||||||
        newAnswers: CoreQuestionsAnswers,
 | 
					        newAnswers: CoreQuestionsAnswers,
 | 
				
			||||||
    ): boolean {
 | 
					    ): boolean {
 | 
				
			||||||
        return CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
 | 
					        return CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -66,7 +66,7 @@ export class CoreInterceptor implements HttpInterceptor {
 | 
				
			|||||||
        // Add the header and serialize the body if needed.
 | 
					        // Add the header and serialize the body if needed.
 | 
				
			||||||
        const newReq = req.clone({
 | 
					        const newReq = req.clone({
 | 
				
			||||||
            headers: req.headers.set('Content-Type', 'application/x-www-form-urlencoded'),
 | 
					            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,
 | 
					                CoreInterceptor.serialize(req.body) : req.body,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -43,6 +43,8 @@ import { CoreSiteWSCacheRecord } from '@services/database/sites';
 | 
				
			|||||||
import { CoreErrorLogs } from '@singletons/error-logs';
 | 
					import { CoreErrorLogs } from '@singletons/error-logs';
 | 
				
			||||||
import { CoreWait } from '@singletons/wait';
 | 
					import { CoreWait } from '@singletons/wait';
 | 
				
			||||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
					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
 | 
					 * 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.
 | 
					        // Index function by name to speed up wsAvailable method.
 | 
				
			||||||
        if (infos?.functions) {
 | 
					        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
 | 
					    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
    protected getCacheId(method: string, data: any): string {
 | 
					    protected getCacheId(method: string, data: any): string {
 | 
				
			||||||
        return Md5.hashAsciiStr(method + ':' + CoreUtils.sortAndStringify(data));
 | 
					        return Md5.hashAsciiStr(method + ':' + CoreObject.sortAndStringify(data));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@
 | 
				
			|||||||
import { OnInit, Input, Component, Optional, Inject, OnChanges, SimpleChanges } from '@angular/core';
 | 
					import { OnInit, Input, Component, Optional, Inject, OnChanges, SimpleChanges } from '@angular/core';
 | 
				
			||||||
import { CoreLogger } from '@singletons/logger';
 | 
					import { CoreLogger } from '@singletons/logger';
 | 
				
			||||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
					import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreCourseBlock } from '../../course/services/course';
 | 
					import { CoreCourseBlock } from '../../course/services/course';
 | 
				
			||||||
import { Params } from '@angular/router';
 | 
					import { Params } from '@angular/router';
 | 
				
			||||||
@ -78,7 +78,7 @@ export abstract class CoreBlockBaseComponent implements OnInit, OnChanges, ICore
 | 
				
			|||||||
            config.value = CoreText.parseJSON(config.value);
 | 
					            config.value = CoreText.parseJSON(config.value);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.block.configsRecord = CoreUtils.arrayToObject(this.block.configs, 'name');
 | 
					        this.block.configsRecord = CoreArray.toObject(this.block.configs, 'name');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -47,6 +47,7 @@ import {
 | 
				
			|||||||
    CORE_COURSE_PROGRESS_UPDATED_EVENT,
 | 
					    CORE_COURSE_PROGRESS_UPDATED_EVENT,
 | 
				
			||||||
} from '@features/course/constants';
 | 
					} from '@features/course/constants';
 | 
				
			||||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
					import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Page that displays the contents of a course.
 | 
					 * 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) {
 | 
					        if ('courseformatoptions' in this.course && this.course.courseformatoptions) {
 | 
				
			||||||
            // Already loaded.
 | 
					            // Already loaded.
 | 
				
			||||||
            this.formatOptions = CoreUtils.objectToKeyValueMap(this.course.courseformatoptions, 'name', 'value');
 | 
					            this.formatOptions = CoreObject.toKeyValueMap(this.course.courseformatoptions, 'name', 'value');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -294,7 +295,7 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy, CoreRefreshCon
 | 
				
			|||||||
        course && Object.assign(this.course, course);
 | 
					        course && Object.assign(this.course, course);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (course?.courseformatoptions) {
 | 
					        if (course?.courseformatoptions) {
 | 
				
			||||||
            this.formatOptions = CoreUtils.objectToKeyValueMap(course.courseformatoptions, 'name', 'value');
 | 
					            this.formatOptions = CoreObject.toKeyValueMap(course.courseformatoptions, 'name', 'value');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -32,7 +32,7 @@ import { CoreLogger } from '@singletons/logger';
 | 
				
			|||||||
import { ApplicationInit, makeSingleton, Translate } from '@singletons';
 | 
					import { ApplicationInit, makeSingleton, Translate } from '@singletons';
 | 
				
			||||||
import { CoreFilepool } from '@services/filepool';
 | 
					import { CoreFilepool } from '@services/filepool';
 | 
				
			||||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
					import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    CoreCourseAnyCourseData,
 | 
					    CoreCourseAnyCourseData,
 | 
				
			||||||
    CoreCourseBasicData,
 | 
					    CoreCourseBasicData,
 | 
				
			||||||
@ -1088,7 +1088,7 @@ export class CoreCourseHelperProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const totalOffline = offlineCompletions.length;
 | 
					        const totalOffline = offlineCompletions.length;
 | 
				
			||||||
        let loaded = 0;
 | 
					        let loaded = 0;
 | 
				
			||||||
        const offlineCompletionsMap = CoreUtils.arrayToObject(offlineCompletions, 'cmid');
 | 
					        const offlineCompletionsMap = CoreArray.toObject(offlineCompletions, 'cmid');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const loadSectionOfflineCompletion = (section: CoreCourseWSSection): void => {
 | 
					        const loadSectionOfflineCompletion = (section: CoreCourseWSSection): void => {
 | 
				
			||||||
            if (!section.contents || !section.contents.length) {
 | 
					            if (!section.contents || !section.contents.length) {
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,6 @@ import { CoreEvents } from '@singletons/events';
 | 
				
			|||||||
import { CoreLogger } from '@singletons/logger';
 | 
					import { CoreLogger } from '@singletons/logger';
 | 
				
			||||||
import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites';
 | 
					import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					 | 
				
			||||||
import { CoreSite } from '@classes/sites/site';
 | 
					import { CoreSite } from '@classes/sites/site';
 | 
				
			||||||
import { CoreCacheUpdateFrequency, CoreConstants, DownloadStatus } from '@/core/constants';
 | 
					import { CoreCacheUpdateFrequency, CoreConstants, DownloadStatus } from '@/core/constants';
 | 
				
			||||||
import { makeSingleton, Translate } from '@singletons';
 | 
					import { makeSingleton, Translate } from '@singletons';
 | 
				
			||||||
@ -75,6 +74,7 @@ import {
 | 
				
			|||||||
    CORE_COURSE_STEALTH_MODULES_SECTION_ID,
 | 
					    CORE_COURSE_STEALTH_MODULES_SECTION_ID,
 | 
				
			||||||
} from '../constants';
 | 
					} from '../constants';
 | 
				
			||||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
					import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type CoreCourseProgressUpdated = { progress: number; courseId: number };
 | 
					export type CoreCourseProgressUpdated = { progress: number; courseId: number };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -260,7 +260,7 @@ export class CoreCourseProvider {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const course = await CoreCourses.getCourseByField('id', courseId, site.id);
 | 
					        const course = await CoreCourses.getCourseByField('id', courseId, site.id);
 | 
				
			||||||
        const formatOptions = CoreUtils.objectToKeyValueMap(
 | 
					        const formatOptions = CoreObject.toKeyValueMap(
 | 
				
			||||||
            course.courseformatoptions ?? [],
 | 
					            course.courseformatoptions ?? [],
 | 
				
			||||||
            'name',
 | 
					            'name',
 | 
				
			||||||
            'value',
 | 
					            'value',
 | 
				
			||||||
@ -353,7 +353,7 @@ export class CoreCourseProvider {
 | 
				
			|||||||
            throw Error('WS core_completion_get_activities_completion_status failed');
 | 
					            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) {
 | 
					        if (!includeOffline) {
 | 
				
			||||||
            return completionStatus;
 | 
					            return completionStatus;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -412,7 +412,7 @@ export class CoreCourseProvider {
 | 
				
			|||||||
            js: (record) => ids.includes(record.cmId),
 | 
					            js: (record) => ids.includes(record.cmId),
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return CoreUtils.arrayToObject(entries, 'cmId');
 | 
					        return CoreArray.toObject(entries, 'cmId');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ import { CoreNetwork } from '@services/network';
 | 
				
			|||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import { ACTIVITY_LOG_TABLE, CoreCourseActivityLogDBRecord } from './database/log';
 | 
					import { ACTIVITY_LOG_TABLE, CoreCourseActivityLogDBRecord } from './database/log';
 | 
				
			||||||
import { CoreStatusWithWarningsWSResponse } from '@services/ws';
 | 
					import { CoreStatusWithWarningsWSResponse } from '@services/ws';
 | 
				
			||||||
@ -84,7 +84,7 @@ export class CoreCourseLogHelperProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const conditions: Partial<CoreCourseActivityLogDBRecord> = {
 | 
					        const conditions: Partial<CoreCourseActivityLogDBRecord> = {
 | 
				
			||||||
            ws,
 | 
					            ws,
 | 
				
			||||||
            data: CoreUtils.sortAndStringify(data),
 | 
					            data: CoreObject.sortAndStringify(data),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await site.getDb().deleteRecords(ACTIVITY_LOG_TABLE, conditions);
 | 
					        await site.getDb().deleteRecords(ACTIVITY_LOG_TABLE, conditions);
 | 
				
			||||||
@ -264,7 +264,7 @@ export class CoreCourseLogHelperProvider {
 | 
				
			|||||||
            component,
 | 
					            component,
 | 
				
			||||||
            componentid: componentId,
 | 
					            componentid: componentId,
 | 
				
			||||||
            ws,
 | 
					            ws,
 | 
				
			||||||
            data: CoreUtils.sortAndStringify(data),
 | 
					            data: CoreObject.sortAndStringify(data),
 | 
				
			||||||
            time: CoreTimeUtils.timestamp(),
 | 
					            time: CoreTimeUtils.timestamp(),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,7 @@ import { CoreFileHelper } from '@services/file-helper';
 | 
				
			|||||||
import { CoreFilepool } from '@services/filepool';
 | 
					import { CoreFilepool } from '@services/filepool';
 | 
				
			||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { CoreCourse, CoreCourseAnyModuleData, CoreCourseModuleContentFile } from './course';
 | 
					import { CoreCourse, CoreCourseAnyModuleData, CoreCourseModuleContentFile } from './course';
 | 
				
			||||||
import { CoreCache } from '@classes/cache';
 | 
					import { CoreCache } from '@classes/cache';
 | 
				
			||||||
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
 | 
					import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
 | 
				
			||||||
@ -1317,7 +1317,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
 | 
				
			|||||||
        previousTime?: number,
 | 
					        previousTime?: number,
 | 
				
			||||||
    ): CourseUpdates {
 | 
					    ): CourseUpdates {
 | 
				
			||||||
        // Format the response to index it by module ID.
 | 
					        // 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.
 | 
					        // Treat warnings, adding the not supported modules.
 | 
				
			||||||
        response.warnings?.forEach((warning) => {
 | 
					        response.warnings?.forEach((warning) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,7 @@
 | 
				
			|||||||
// limitations under the License.
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Injectable } from '@angular/core';
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
 | 
					import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    CoreCourseAnyCourseData,
 | 
					    CoreCourseAnyCourseData,
 | 
				
			||||||
@ -157,7 +157,7 @@ export class CoreCoursesHelperProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Get the extra data for the courses.
 | 
					        // Get the extra data for the courses.
 | 
				
			||||||
        return CoreCourses.getCoursesByFieldObservable('ids', courseIds, options).pipe(map(coursesInfosArray => {
 | 
					        return CoreCourses.getCoursesByFieldObservable('ids', courseIds, options).pipe(map(coursesInfosArray => {
 | 
				
			||||||
            const coursesInfo = CoreUtils.arrayToObject(coursesInfosArray, 'id');
 | 
					            const coursesInfo = CoreArray.toObject(coursesInfosArray, 'id');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            courses.forEach((course) => {
 | 
					            courses.forEach((course) => {
 | 
				
			||||||
                this.loadCourseExtraInfo(course, coursesInfo[course.id], loadCategoryNames);
 | 
					                this.loadCourseExtraInfo(course, coursesInfo[course.id], loadCategoryNames);
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
 | 
				
			|||||||
import { CoreError } from '@classes/errors/error';
 | 
					import { CoreError } from '@classes/errors/error';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import { CoreLogger } from '@singletons/logger';
 | 
					import { CoreLogger } from '@singletons/logger';
 | 
				
			||||||
import { CoreEditorDraft, CoreEditorDraftPrimaryData, DRAFT_TABLE } from './database/editor';
 | 
					import { CoreEditorDraft, CoreEditorDraftPrimaryData, DRAFT_TABLE } from './database/editor';
 | 
				
			||||||
@ -82,7 +82,7 @@ export class CoreEditorOfflineProvider {
 | 
				
			|||||||
            contextlevel: contextLevel,
 | 
					            contextlevel: contextLevel,
 | 
				
			||||||
            contextinstanceid: contextInstanceId,
 | 
					            contextinstanceid: contextInstanceId,
 | 
				
			||||||
            elementid: elementId,
 | 
					            elementid: elementId,
 | 
				
			||||||
            extraparams: CoreUtils.sortAndStringify(extraParams || {}),
 | 
					            extraparams: CoreObject.sortAndStringify(extraParams || {}),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,7 @@ import { CoreFile, CoreFileProvider, CoreFileProgressEvent } from '@services/fil
 | 
				
			|||||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
					import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			||||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
 | 
					import { CoreMimetypeUtils } from '@services/utils/mimetype';
 | 
				
			||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { makeSingleton, Translate, Camera, ActionSheetController } from '@singletons';
 | 
					import { makeSingleton, Translate, Camera, ActionSheetController } from '@singletons';
 | 
				
			||||||
import { CoreLogger } from '@singletons/logger';
 | 
					import { CoreLogger } from '@singletons/logger';
 | 
				
			||||||
import { CoreCanceledError } from '@classes/errors/cancelederror';
 | 
					import { CoreCanceledError } from '@classes/errors/cancelederror';
 | 
				
			||||||
@ -635,8 +635,8 @@ export class CoreFileUploaderHelperProvider {
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (fromAlbum) {
 | 
					        if (fromAlbum) {
 | 
				
			||||||
            const imageSupported = !mimetypes || CoreUtils.indexOfRegexp(mimetypes, /^image\//) > -1;
 | 
					            const imageSupported = !mimetypes || CoreArray.indexOfRegexp(mimetypes, /^image\//) > -1;
 | 
				
			||||||
            const videoSupported = !mimetypes || CoreUtils.indexOfRegexp(mimetypes, /^video\//) > -1;
 | 
					            const videoSupported = !mimetypes || CoreArray.indexOfRegexp(mimetypes, /^video\//) > -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            options.sourceType = Camera.PictureSourceType.PHOTOLIBRARY;
 | 
					            options.sourceType = Camera.PictureSourceType.PHOTOLIBRARY;
 | 
				
			||||||
            options.popoverOptions = {
 | 
					            options.popoverOptions = {
 | 
				
			||||||
 | 
				
			|||||||
@ -47,6 +47,7 @@ import { CoreLoadings } from '@services/loadings';
 | 
				
			|||||||
import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
 | 
					import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
 | 
				
			||||||
import { CoreCourseAccessDataType } from '@features/course/constants';
 | 
					import { CoreCourseAccessDataType } from '@features/course/constants';
 | 
				
			||||||
import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
					import { CorePromiseUtils } from '@singletons/promise-utils';
 | 
				
			||||||
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const GRADES_PAGE_NAME = 'grades';
 | 
					export const GRADES_PAGE_NAME = 'grades';
 | 
				
			||||||
export const GRADES_PARTICIPANTS_PAGE_NAME = 'participant-grades';
 | 
					export const GRADES_PARTICIPANTS_PAGE_NAME = 'participant-grades';
 | 
				
			||||||
@ -271,7 +272,7 @@ export class CoreGradesHelperProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            const courses = await CoreCourses.getUserCourses(undefined, undefined, CoreSitesReadingStrategy.ONLY_CACHE);
 | 
					            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);
 | 
					            coursesWereMissing = this.addCourseData(grades, coursesMap);
 | 
				
			||||||
        } catch {
 | 
					        } catch {
 | 
				
			||||||
@ -282,7 +283,7 @@ export class CoreGradesHelperProvider {
 | 
				
			|||||||
        if (coursesWereMissing) {
 | 
					        if (coursesWereMissing) {
 | 
				
			||||||
            const courses = await CoreCourses.getCoursesByField('ids', grades.map((grade) => grade.courseid).join(','));
 | 
					            const courses = await CoreCourses.getCoursesByField('ids', grades.map((grade) => grade.courseid).join(','));
 | 
				
			||||||
            const coursesMap =
 | 
					            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, CoreEnrolledCourseData> |
 | 
				
			||||||
                    Record<string, CoreCourseSearchedData>;
 | 
					                    Record<string, CoreCourseSearchedData>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@ import { CoreH5P } from '@features/h5p/services/h5p';
 | 
				
			|||||||
import { Translate } from '@singletons';
 | 
					import { Translate } from '@singletons';
 | 
				
			||||||
import { CoreH5PCore, CoreH5PLibraryData, CoreH5PLibraryAddonData, CoreH5PContentDepsTreeDependency } from './core';
 | 
					import { CoreH5PCore, CoreH5PLibraryData, CoreH5PLibraryAddonData, CoreH5PContentDepsTreeDependency } from './core';
 | 
				
			||||||
import { CoreArray } from '@singletons/array';
 | 
					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'];
 | 
					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) {
 | 
					        if (!isArray) {
 | 
				
			||||||
            list = CoreUtils.objectToArray(<Record<string, unknown>> list);
 | 
					            list = CoreObject.toArray(<Record<string, unknown>> list);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!list.length) {
 | 
					        if (!list.length) {
 | 
				
			||||||
@ -677,7 +678,7 @@ export class CoreH5PContentValidator {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    protected filterXssSplit(tags: string[], store: boolean = false): string {
 | 
					    protected filterXssSplit(tags: string[], store: boolean = false): string {
 | 
				
			||||||
        if (store) {
 | 
					        if (store) {
 | 
				
			||||||
            this.allowedHtml = CoreUtils.arrayToObject(tags);
 | 
					            this.allowedHtml = CoreArray.toObject(tags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return '';
 | 
					            return '';
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -961,7 +961,7 @@ export class CoreH5PCore {
 | 
				
			|||||||
            if (params.match(pattern)) {
 | 
					            if (params.match(pattern)) {
 | 
				
			||||||
                return true;
 | 
					                return true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else if (typeof params == 'object') {
 | 
					        } else if (typeof params === 'object') {
 | 
				
			||||||
            for (const key in params) {
 | 
					            for (const key in params) {
 | 
				
			||||||
                const value = params[key];
 | 
					                const value = params[key];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ import { CoreSites, CoreLoginSiteInfo, CoreSiteBasicInfo } from '@services/sites
 | 
				
			|||||||
import { CoreWS, CoreWSExternalWarning } from '@services/ws';
 | 
					import { CoreWS, CoreWSExternalWarning } from '@services/ws';
 | 
				
			||||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
					import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreConstants } from '@/core/constants';
 | 
					import { CoreConstants } from '@/core/constants';
 | 
				
			||||||
import { CoreSite } from '@classes/sites/site';
 | 
					import { CoreSite } from '@classes/sites/site';
 | 
				
			||||||
import { CoreError } from '@classes/errors/error';
 | 
					import { CoreError } from '@classes/errors/error';
 | 
				
			||||||
@ -1368,7 +1368,7 @@ export class CoreLoginHelperProvider {
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }));
 | 
					        }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        accountsList.otherSites = CoreUtils.objectToArray(otherSites);
 | 
					        accountsList.otherSites = CoreObject.toArray(otherSites);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return accountsList;
 | 
					        return accountsList;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ import { CoreSites } from '@services/sites';
 | 
				
			|||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
					import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
				
			||||||
import { CoreTabsOutletComponent, CoreTabsOutletTab } from '@components/tabs-outlet/tabs-outlet';
 | 
					import { CoreTabsOutletComponent, CoreTabsOutletTab } from '@components/tabs-outlet/tabs-outlet';
 | 
				
			||||||
import { CoreMainMenuHomeDelegate, CoreMainMenuHomeHandlerToDisplay } from '../../services/home-delegate';
 | 
					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';
 | 
					import { CoreMainMenuHomeHandlerService } from '@features/mainmenu/services/handlers/mainmenu';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -62,7 +62,7 @@ export class CoreMainMenuHomePage implements OnInit {
 | 
				
			|||||||
    initHandlers(handlers: CoreMainMenuHomeHandlerToDisplay[]): void {
 | 
					    initHandlers(handlers: CoreMainMenuHomeHandlerToDisplay[]): void {
 | 
				
			||||||
        // Re-build the list of tabs.
 | 
					        // Re-build the list of tabs.
 | 
				
			||||||
        const loaded = CoreMainMenuHomeDelegate.areHandlersLoaded();
 | 
					        const loaded = CoreMainMenuHomeDelegate.areHandlersLoaded();
 | 
				
			||||||
        const handlersMap = CoreUtils.arrayToObject(handlers, 'title');
 | 
					        const handlersMap = CoreArray.toObject(handlers, 'title');
 | 
				
			||||||
        const newTabs = handlers.map((handler): CoreTabsOutletTab => {
 | 
					        const newTabs = handlers.map((handler): CoreTabsOutletTab => {
 | 
				
			||||||
            const tab = this.tabs.find(tab => tab.title == handler.title);
 | 
					            const tab = this.tabs.find(tab => tab.title == handler.title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ import { CoreFile } from '@services/file';
 | 
				
			|||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { CoreWSExternalFile } from '@services/ws';
 | 
					import { CoreWSExternalFile } from '@services/ws';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import { CorePath } from '@singletons/path';
 | 
					import { CorePath } from '@singletons/path';
 | 
				
			||||||
@ -37,6 +37,7 @@ import {
 | 
				
			|||||||
    QUESTION_NEEDS_GRADING_STATE_CLASSES,
 | 
					    QUESTION_NEEDS_GRADING_STATE_CLASSES,
 | 
				
			||||||
    QUESTION_TODO_STATE_CLASSES,
 | 
					    QUESTION_TODO_STATE_CLASSES,
 | 
				
			||||||
} from '@features/question/constants';
 | 
					} from '@features/question/constants';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const QUESTION_PREFIX_REGEX = /q\d+:(\d+)_/;
 | 
					const QUESTION_PREFIX_REGEX = /q\d+:(\d+)_/;
 | 
				
			||||||
const STATES: Record<string, CoreQuestionState> = {
 | 
					const STATES: Record<string, CoreQuestionState> = {
 | 
				
			||||||
@ -150,7 +151,7 @@ export class CoreQuestionProvider {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    compareAllAnswers(prevAnswers: Record<string, unknown>, newAnswers: Record<string, unknown>): boolean {
 | 
					    compareAllAnswers(prevAnswers: Record<string, unknown>, newAnswers: Record<string, unknown>): boolean {
 | 
				
			||||||
        // Get all the keys.
 | 
					        // 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.
 | 
					        // Check that all the keys have the same value on both objects.
 | 
				
			||||||
        for (const i in keys) {
 | 
					        for (const i in keys) {
 | 
				
			||||||
@ -158,7 +159,7 @@ export class CoreQuestionProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            // Ignore extra answers like sequencecheck or certainty.
 | 
					            // Ignore extra answers like sequencecheck or certainty.
 | 
				
			||||||
            if (!this.isExtraAnswer(key[0])) {
 | 
					            if (!this.isExtraAnswer(key[0])) {
 | 
				
			||||||
                if (!CoreUtils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, key)) {
 | 
					                if (!CoreObject.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, key)) {
 | 
				
			||||||
                    return false;
 | 
					                    return false;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -18,13 +18,13 @@ import { CoreSite } from '@classes/sites/site';
 | 
				
			|||||||
import { CoreUser } from '@features/user/services/user';
 | 
					import { CoreUser } from '@features/user/services/user';
 | 
				
			||||||
import { CoreNetwork } from '@services/network';
 | 
					import { CoreNetwork } from '@services/network';
 | 
				
			||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					 | 
				
			||||||
import { CoreWSExternalWarning } from '@services/ws';
 | 
					import { CoreWSExternalWarning } from '@services/ws';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
import { CoreEvents } from '@singletons/events';
 | 
					import { CoreEvents } from '@singletons/events';
 | 
				
			||||||
import { CoreRatingOffline } from './rating-offline';
 | 
					import { CoreRatingOffline } from './rating-offline';
 | 
				
			||||||
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
 | 
					import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
 | 
				
			||||||
import { CoreWSError } from '@classes/errors/wserror';
 | 
					import { CoreWSError } from '@classes/errors/wserror';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ROOT_CACHE_KEY = 'CoreRating:';
 | 
					const ROOT_CACHE_KEY = 'CoreRating:';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -351,8 +351,8 @@ export class CoreRatingProvider {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (result) {
 | 
					        if (result) {
 | 
				
			||||||
            result.scales = CoreUtils.objectToArray(scales);
 | 
					            result.scales = CoreObject.toArray(scales);
 | 
				
			||||||
            result.ratings = CoreUtils.objectToArray(ratings);
 | 
					            result.ratings = CoreObject.toArray(ratings);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return result;
 | 
					        return result;
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@
 | 
				
			|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
 | 
					import { Component, OnDestroy, OnInit } from '@angular/core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CoreSiteBasicInfo, CoreSites } from '@services/sites';
 | 
					import { CoreSiteBasicInfo, CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
					import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CoreSettingsHelper } from '../../services/settings-helper';
 | 
					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.accountsList.count = sites.length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.totalSpaceUsage = totalSize;
 | 
					        this.totalSpaceUsage = totalSize;
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@
 | 
				
			|||||||
// See the License for the specific language governing permissions and
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
// limitations under the License.
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
import { CoreSitePlugins, CoreSitePluginsInitHandlerData } from '../services/siteplugins';
 | 
					import { CoreSitePlugins, CoreSitePluginsInitHandlerData } from '../services/siteplugins';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -55,7 +55,7 @@ export class CoreSitePluginsCompileInitComponent {
 | 
				
			|||||||
        // Load first template.
 | 
					        // Load first template.
 | 
				
			||||||
        if (this.handlerSchema.methodTemplates?.length) {
 | 
					        if (this.handlerSchema.methodTemplates?.length) {
 | 
				
			||||||
            this.content = this.handlerSchema.methodTemplates[0].html;
 | 
					            this.content = this.handlerSchema.methodTemplates[0].html;
 | 
				
			||||||
            this.jsData.CONTENT_TEMPLATES = CoreUtils.objectToKeyValueMap(
 | 
					            this.jsData.CONTENT_TEMPLATES = CoreObject.toKeyValueMap(
 | 
				
			||||||
                this.handlerSchema.methodTemplates,
 | 
					                this.handlerSchema.methodTemplates,
 | 
				
			||||||
                'id',
 | 
					                'id',
 | 
				
			||||||
                'html',
 | 
					                'html',
 | 
				
			||||||
 | 
				
			|||||||
@ -34,6 +34,7 @@ import { CoreEnrolAction, CoreEnrolInfoIcon } from '@features/enrol/services/enr
 | 
				
			|||||||
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
 | 
					import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
 | 
				
			||||||
import { CoreUserProfileHandlerType } from '@features/user/services/user-delegate';
 | 
					import { CoreUserProfileHandlerType } from '@features/user/services/user-delegate';
 | 
				
			||||||
import { CORE_SITE_PLUGINS_COMPONENT, CORE_SITE_PLUGINS_UPDATE_COURSE_CONTENT } from '../constants';
 | 
					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.
 | 
					 * Service to provide functionalities regarding site plugins.
 | 
				
			||||||
@ -156,13 +157,13 @@ export class CoreSitePluginsProvider {
 | 
				
			|||||||
            data = Object.assign(data, initResult.jsResult || {});
 | 
					            data = Object.assign(data, initResult.jsResult || {});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Now add some data returned by the init WS call.
 | 
					            // 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;
 | 
					            data.INIT_OTHERDATA = initResult.otherdata;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (contentResult) {
 | 
					        if (contentResult) {
 | 
				
			||||||
            // Now add the data returned by the content WS call.
 | 
					            // 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;
 | 
					            data.CONTENT_OTHERDATA = contentResult.otherdata;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -177,7 +178,7 @@ export class CoreSitePluginsProvider {
 | 
				
			|||||||
     * @returns Cache key.
 | 
					     * @returns Cache key.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    getCallWSCacheKey(method: string, data: Record<string, unknown>): string {
 | 
					    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 = {
 | 
					        const data: CoreSitePluginsGetContentWSParams = {
 | 
				
			||||||
            component: component,
 | 
					            component: component,
 | 
				
			||||||
            method: method,
 | 
					            method: method,
 | 
				
			||||||
            args: CoreUtils.objectToArrayOfObjects(argsToSend, 'name', 'value', true),
 | 
					            args: CoreObject.toArrayOfObjects(argsToSend, 'name', 'value', true),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        preSets = preSets || {};
 | 
					        preSets = preSets || {};
 | 
				
			||||||
@ -230,7 +231,7 @@ export class CoreSitePluginsProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        let otherData: Record<string, unknown> = {};
 | 
					        let otherData: Record<string, unknown> = {};
 | 
				
			||||||
        if (result.otherdata) {
 | 
					        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.
 | 
					            // Try to parse all properties that could be JSON encoded strings.
 | 
				
			||||||
            for (const name in otherData) {
 | 
					            for (const name in otherData) {
 | 
				
			||||||
@ -255,7 +256,7 @@ export class CoreSitePluginsProvider {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    protected getContentCacheKey(component: string, method: string, args: Record<string, unknown>): string {
 | 
					    protected getContentCacheKey(component: string, method: string, args: Record<string, unknown>): string {
 | 
				
			||||||
        return CoreSitePluginsProvider.ROOT_CACHE_KEY + 'content:' + component + ':' + method +
 | 
					        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.
 | 
					     * @returns Plugin list ws info.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    getCurrentSitePluginList(): CoreSitePluginsWSPlugin[] {
 | 
					    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) {
 | 
					            for (const i in useOtherData) {
 | 
				
			||||||
                const name = useOtherData[i];
 | 
					                const name = useOtherData[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (typeof otherData[name] == 'object' && otherData[name] !== null) {
 | 
					                if (typeof otherData[name] === 'object' && otherData[name] !== null) {
 | 
				
			||||||
                    // Stringify objects.
 | 
					                    // Stringify objects.
 | 
				
			||||||
                    args[name] = JSON.stringify(otherData[name]);
 | 
					                    args[name] = JSON.stringify(otherData[name]);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
@ -517,7 +518,7 @@ export class CoreSitePluginsProvider {
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // Add all the data to args.
 | 
					            // Add all the data to args.
 | 
				
			||||||
            for (const name in otherData) {
 | 
					            for (const name in otherData) {
 | 
				
			||||||
                if (typeof otherData[name] == 'object' && otherData[name] !== null) {
 | 
					                if (typeof otherData[name] === 'object' && otherData[name] !== null) {
 | 
				
			||||||
                    // Stringify objects.
 | 
					                    // Stringify objects.
 | 
				
			||||||
                    args[name] = JSON.stringify(otherData[name]);
 | 
					                    args[name] = JSON.stringify(otherData[name]);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ import { CoreMimetypeUtils } from '@services/utils/mimetype';
 | 
				
			|||||||
import { CoreText } from '@singletons/text';
 | 
					import { CoreText } from '@singletons/text';
 | 
				
			||||||
import { CoreTimeUtils } from '@services/utils/time';
 | 
					import { CoreTimeUtils } from '@services/utils/time';
 | 
				
			||||||
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
 | 
					import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
 | 
				
			||||||
import { CoreUtils } from '@services/utils/utils';
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
import { CoreError } from '@classes/errors/error';
 | 
					import { CoreError } from '@classes/errors/error';
 | 
				
			||||||
import { DownloadStatus } from '@/core/constants';
 | 
					import { DownloadStatus } from '@/core/constants';
 | 
				
			||||||
import { ApplicationInit, makeSingleton, NgZone, Translate } from '@singletons';
 | 
					import { ApplicationInit, makeSingleton, NgZone, Translate } from '@singletons';
 | 
				
			||||||
@ -650,7 +650,7 @@ export class CoreFilepoolProvider {
 | 
				
			|||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Notify now.
 | 
					        // 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] || []));
 | 
					        filesEntries.forEach(entry => this.notifyFileDeleted(siteId, entry.fileId, filesLinksMap[entry.fileId] || []));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -154,7 +154,7 @@ export class CoreGeolocationProvider {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    protected isCordovaPermissionDeniedError(error?: CoreAnyError | GeolocationPositionError): boolean {
 | 
					    protected isCordovaPermissionDeniedError(error?: CoreAnyError | GeolocationPositionError): boolean {
 | 
				
			||||||
        return !!error &&
 | 
					        return !!error &&
 | 
				
			||||||
            typeof error == 'object' &&
 | 
					            typeof error === 'object' &&
 | 
				
			||||||
            'code' in error &&
 | 
					            'code' in error &&
 | 
				
			||||||
            'PERMISSION_DENIED' in error &&
 | 
					            'PERMISSION_DENIED' in error &&
 | 
				
			||||||
            error.code === error.PERMISSION_DENIED;
 | 
					            error.code === error.PERMISSION_DENIED;
 | 
				
			||||||
 | 
				
			|||||||
@ -290,7 +290,7 @@ export class CoreLocalNotificationsProvider {
 | 
				
			|||||||
        scheduled.forEach((notif) => {
 | 
					        scheduled.forEach((notif) => {
 | 
				
			||||||
            notif.data = this.parseNotificationData(notif.data);
 | 
					            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);
 | 
					                ids.push(notif.id);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@ -563,7 +563,7 @@ export class CoreLocalNotificationsProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            // Check if request is valid.
 | 
					            // 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;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -461,7 +461,7 @@ export class CoreNavigatorService {
 | 
				
			|||||||
            return route;
 | 
					            return route;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (routeData && CoreUtils.basicLeftCompare(routeData, this.getRouteData(route), 3)) {
 | 
					        if (routeData && CoreObject.basicLeftCompare(routeData, this.getRouteData(route), 3)) {
 | 
				
			||||||
            return route;
 | 
					            return route;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -607,7 +607,7 @@ export class CoreNavigatorService {
 | 
				
			|||||||
    protected replaceObjectParams(queryParams?: Params | null): void {
 | 
					    protected replaceObjectParams(queryParams?: Params | null): void {
 | 
				
			||||||
        for (const name in queryParams) {
 | 
					        for (const name in queryParams) {
 | 
				
			||||||
            const value = queryParams[name];
 | 
					            const value = queryParams[name];
 | 
				
			||||||
            if (typeof value != 'object' || value === null) {
 | 
					            if (typeof value !== 'object' || value === null) {
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1292,7 +1292,7 @@ export class CoreSitesProvider {
 | 
				
			|||||||
            return !!this.currentSite;
 | 
					            return !!this.currentSite;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const siteId = typeof site == 'object' ? site.getId() : site;
 | 
					        const siteId = typeof site === 'object' ? site.getId() : site;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this.currentSite.getId() === siteId;
 | 
					        return this.currentSite.getId() === siteId;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -447,7 +447,7 @@ export class CoreDomUtilsProvider {
 | 
				
			|||||||
        let extraInfo = '';
 | 
					        let extraInfo = '';
 | 
				
			||||||
        let errorMessage: string | undefined;
 | 
					        let errorMessage: string | undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (typeof error == 'object') {
 | 
					        if (typeof error === 'object') {
 | 
				
			||||||
            if (this.debugDisplay) {
 | 
					            if (this.debugDisplay) {
 | 
				
			||||||
                // Get the debug info. Escape the HTML so it is displayed as it is in the view.
 | 
					                // Get the debug info. Escape the HTML so it is displayed as it is in the view.
 | 
				
			||||||
                if ('debuginfo' in error && error.debuginfo) {
 | 
					                if ('debuginfo' in error && error.debuginfo) {
 | 
				
			||||||
 | 
				
			|||||||
@ -455,7 +455,7 @@ export class CoreIframeUtilsProvider {
 | 
				
			|||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (element.tagName.toLowerCase() == 'object') {
 | 
					            if (element.tagName.toLowerCase() === 'object') {
 | 
				
			||||||
                element.setAttribute('data', url);
 | 
					                element.setAttribute('data', url);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                element.setAttribute('src', url);
 | 
					                element.setAttribute('src', url);
 | 
				
			||||||
@ -509,7 +509,7 @@ export class CoreIframeUtilsProvider {
 | 
				
			|||||||
                (!link.target || link.target == '_self')
 | 
					                (!link.target || link.target == '_self')
 | 
				
			||||||
            ) {
 | 
					            ) {
 | 
				
			||||||
                // Load the link inside the frame itself.
 | 
					                // Load the link inside the frame itself.
 | 
				
			||||||
                if (element.tagName.toLowerCase() == 'object') {
 | 
					                if (element.tagName.toLowerCase() === 'object') {
 | 
				
			||||||
                    element.setAttribute('data', link.href);
 | 
					                    element.setAttribute('data', link.href);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    element.setAttribute('src', link.href);
 | 
					                    element.setAttribute('src', link.href);
 | 
				
			||||||
@ -546,7 +546,7 @@ export class CoreIframeUtilsProvider {
 | 
				
			|||||||
        } else if (CorePlatform.isIOS() && (!link.target || link.target == '_self') && element) {
 | 
					        } 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.
 | 
					            // In cordova ios 4.1.0 links inside iframes stopped working. We'll manually treat them.
 | 
				
			||||||
            event && event.preventDefault();
 | 
					            event && event.preventDefault();
 | 
				
			||||||
            if (element.tagName.toLowerCase() == 'object') {
 | 
					            if (element.tagName.toLowerCase() === 'object') {
 | 
				
			||||||
                element.setAttribute('data', link.href);
 | 
					                element.setAttribute('data', link.href);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                element.setAttribute('src', link.href);
 | 
					                element.setAttribute('src', link.href);
 | 
				
			||||||
 | 
				
			|||||||
@ -424,10 +424,10 @@ export class CoreMimetypeUtilsProvider {
 | 
				
			|||||||
        let mimetype: string | undefined = '';
 | 
					        let mimetype: string | undefined = '';
 | 
				
			||||||
        let extension: 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.
 | 
					            // It's a FileEntry. Don't use the file function because it's asynchronous and the type isn't reliable.
 | 
				
			||||||
            filename = obj.name;
 | 
					            filename = obj.name;
 | 
				
			||||||
        } else if (typeof obj == 'object') {
 | 
					        } else if (typeof obj === 'object') {
 | 
				
			||||||
            filename = obj.filename || '';
 | 
					            filename = obj.filename || '';
 | 
				
			||||||
            mimetype = obj.mimetype || '';
 | 
					            mimetype = obj.mimetype || '';
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,7 @@ import { CoreErrorHelper } from '@services/error-helper';
 | 
				
			|||||||
import { CorePromiseUtils, OrderedPromiseData } from '@singletons/promise-utils';
 | 
					import { CorePromiseUtils, OrderedPromiseData } from '@singletons/promise-utils';
 | 
				
			||||||
import { CoreOpener, CoreOpenerOpenFileOptions, CoreOpenerOpenInBrowserOptions } from '@singletons/opener';
 | 
					import { CoreOpener, CoreOpenerOpenFileOptions, CoreOpenerOpenInBrowserOptions } from '@singletons/opener';
 | 
				
			||||||
import { CoreCountries, CoreCountry } from '@singletons/countries';
 | 
					import { CoreCountries, CoreCountry } from '@singletons/countries';
 | 
				
			||||||
 | 
					import { CoreObject } from '@singletons/object';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type TreeNode<T> = T & { children: TreeNode<T>[] };
 | 
					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 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.
 | 
					     * @param result Object where to put the properties. If not defined, a new object will be created.
 | 
				
			||||||
     * @returns The object.
 | 
					     * @returns The object.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreArray.toObject instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    arrayToObject<T>(
 | 
					    arrayToObject<T>(
 | 
				
			||||||
        array: T[] = [],
 | 
					        array: T[] = [],
 | 
				
			||||||
        propertyName?: string,
 | 
					        propertyName?: string,
 | 
				
			||||||
        result: Record<string, T> = {},
 | 
					        result: Record<string, T> = {},
 | 
				
			||||||
    ): Record<string, T> {
 | 
					    ): Record<string, T> {
 | 
				
			||||||
        for (const entry of array) {
 | 
					        return CoreArray.toObject(array, propertyName, result);
 | 
				
			||||||
            const key = propertyName ? entry[propertyName] : entry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            result[key] = entry;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return 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 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.
 | 
					     * @param result Object where to put the properties. If not defined, a new object will be created.
 | 
				
			||||||
     * @returns The object.
 | 
					     * @returns The object.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreArray.toObjectMultiple instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    arrayToObjectMultiple<T>(
 | 
					    arrayToObjectMultiple<T>(
 | 
				
			||||||
        array: T[] = [],
 | 
					        array: T[] = [],
 | 
				
			||||||
        propertyName?: string,
 | 
					        propertyName?: string,
 | 
				
			||||||
        result: Record<string, T[]> = {},
 | 
					        result: Record<string, T[]> = {},
 | 
				
			||||||
    ): Record<string, T[]> {
 | 
					    ): Record<string, T[]> {
 | 
				
			||||||
        for (const entry of array) {
 | 
					        return CoreArray.toObjectMultiple(array, propertyName, result);
 | 
				
			||||||
            const key = propertyName ? entry[propertyName] : entry;
 | 
					 | 
				
			||||||
            if (result[key] === undefined) {
 | 
					 | 
				
			||||||
                result[key] = [];
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            result[key].push(entry);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return result;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -153,6 +141,7 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
     * @param level Current deep level (when comparing objects).
 | 
					     * @param level Current deep level (when comparing objects).
 | 
				
			||||||
     * @param undefinedIsNull True if undefined is equal to null. Defaults to true.
 | 
					     * @param undefinedIsNull True if undefined is equal to null. Defaults to true.
 | 
				
			||||||
     * @returns Whether both items are equal.
 | 
					     * @returns Whether both items are equal.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreObject.basicLeftCompare instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    basicLeftCompare(
 | 
					    basicLeftCompare(
 | 
				
			||||||
        itemA: any, // eslint-disable-line @typescript-eslint/no-explicit-any
 | 
					        itemA: any, // eslint-disable-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
@ -161,43 +150,7 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
        level: number = 0,
 | 
					        level: number = 0,
 | 
				
			||||||
        undefinedIsNull: boolean = true,
 | 
					        undefinedIsNull: boolean = true,
 | 
				
			||||||
    ): boolean {
 | 
					    ): boolean {
 | 
				
			||||||
        if (typeof itemA == 'function' || typeof itemB == 'function') {
 | 
					        return CoreObject.basicLeftCompare(itemA, itemB, maxLevels, level, undefinedIsNull);
 | 
				
			||||||
            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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -291,7 +244,7 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return newArray;
 | 
					            return newArray;
 | 
				
			||||||
        } else if (this.isObject(source)) {
 | 
					        } else if (CoreObject.isObject(source)) {
 | 
				
			||||||
            // Check if the object shouldn't be copied.
 | 
					            // Check if the object shouldn't be copied.
 | 
				
			||||||
            if (source.toString && this.DONT_CLONE.indexOf(source.toString()) != -1) {
 | 
					            if (source.toString && this.DONT_CLONE.indexOf(source.toString()) != -1) {
 | 
				
			||||||
                // Object shouldn't be copied, return it as it is.
 | 
					                // Object shouldn't be copied, return it as it is.
 | 
				
			||||||
@ -383,32 +336,10 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
     * @param obj Object to flatten.
 | 
					     * @param obj Object to flatten.
 | 
				
			||||||
     * @param useDotNotation Whether to use dot notation '.' or square brackets '['.
 | 
					     * @param useDotNotation Whether to use dot notation '.' or square brackets '['.
 | 
				
			||||||
     * @returns Flattened object.
 | 
					     * @returns Flattened object.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreObject.flatten instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    flattenObject(obj: Record<string, unknown>, useDotNotation?: boolean): Record<string, unknown> {
 | 
					    flattenObject(obj: Record<string, unknown>, useDotNotation?: boolean): Record<string, unknown> {
 | 
				
			||||||
        const toReturn = {};
 | 
					        return CoreObject.flatten(obj, useDotNotation);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -650,9 +581,10 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param object Variable.
 | 
					     * @param object Variable.
 | 
				
			||||||
     * @returns Type guard indicating if this is an object.
 | 
					     * @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> {
 | 
					    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 array Array to search.
 | 
				
			||||||
     * @param regex RegExp to apply to each string.
 | 
					     * @param regex RegExp to apply to each string.
 | 
				
			||||||
     * @returns Index of the first string that matches the RegExp. -1 if not found.
 | 
					     * @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 {
 | 
					    indexOfRegexp(array: string[], regex: RegExp): number {
 | 
				
			||||||
        if (!array || !array.length) {
 | 
					        return CoreArray.indexOfRegexp(array, regex);
 | 
				
			||||||
            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;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -787,9 +707,10 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
     * @param array2 The second array.
 | 
					     * @param array2 The second array.
 | 
				
			||||||
     * @param [key] Key of the property that must be unique. If not specified, the whole entry.
 | 
					     * @param [key] Key of the property that must be unique. If not specified, the whole entry.
 | 
				
			||||||
     * @returns Merged array.
 | 
					     * @returns Merged array.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreArray.mergeWithoutDuplicates instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    mergeArraysWithoutDuplicates<T>(array1: T[], array2: T[], key?: string): T[] {
 | 
					    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.
 | 
					     * @param obj Object to convert.
 | 
				
			||||||
     * @returns Array with the values of the object but losing the keys.
 | 
					     * @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[] {
 | 
					    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 sortByKey True to sort keys alphabetically, false otherwise. Has priority over sortByValue.
 | 
				
			||||||
     * @param sortByValue True to sort values alphabetically, false otherwise.
 | 
					     * @param sortByValue True to sort values alphabetically, false otherwise.
 | 
				
			||||||
     * @returns Array of objects with the name & value of each property.
 | 
					     * @returns Array of objects with the name & value of each property.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreObject.toArrayOfObjects instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    objectToArrayOfObjects<
 | 
					    objectToArrayOfObjects<
 | 
				
			||||||
        A extends Record<string,unknown> = Record<string, unknown>,
 | 
					        A extends Record<string,unknown> = Record<string, unknown>,
 | 
				
			||||||
@ -882,53 +805,7 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
        sortByKey?: boolean,
 | 
					        sortByKey?: boolean,
 | 
				
			||||||
        sortByValue?: boolean,
 | 
					        sortByValue?: boolean,
 | 
				
			||||||
    ): A[] {
 | 
					    ): A[] {
 | 
				
			||||||
        // Get the entries from an object or primitive value.
 | 
					        return CoreObject.toArrayOfObjects(obj, keyName, valueName, sortByKey, sortByValue);
 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -940,6 +817,7 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
     * @param valueName Name of the properties where the values are stored.
 | 
					     * @param valueName Name of the properties where the values are stored.
 | 
				
			||||||
     * @param keyPrefix Key prefix if neededs to delete it.
 | 
					     * @param keyPrefix Key prefix if neededs to delete it.
 | 
				
			||||||
     * @returns Object.
 | 
					     * @returns Object.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreObject.toKeyValueMap instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    objectToKeyValueMap<T = unknown>(
 | 
					    objectToKeyValueMap<T = unknown>(
 | 
				
			||||||
        objects: Record<string, unknown>[],
 | 
					        objects: Record<string, unknown>[],
 | 
				
			||||||
@ -947,15 +825,7 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
        valueName: string,
 | 
					        valueName: string,
 | 
				
			||||||
        keyPrefix?: string,
 | 
					        keyPrefix?: string,
 | 
				
			||||||
    ): {[name: string]: T} {
 | 
					    ): {[name: string]: T} {
 | 
				
			||||||
        const prefixSubstr = keyPrefix ? keyPrefix.length : 0;
 | 
					        return CoreObject.toKeyValueMap(objects, keyName, valueName, keyPrefix);
 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -964,29 +834,10 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
     * @param object Object to convert.
 | 
					     * @param object Object to convert.
 | 
				
			||||||
     * @param removeEmpty Whether to remove params whose value is null/undefined.
 | 
					     * @param removeEmpty Whether to remove params whose value is null/undefined.
 | 
				
			||||||
     * @returns GET params.
 | 
					     * @returns GET params.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreObject.toGetParams instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    objectToGetParams(object: Record<string, unknown>, removeEmpty: boolean = true): string {
 | 
					    objectToGetParams(object: Record<string, unknown>, removeEmpty: boolean = true): string {
 | 
				
			||||||
        // First of all, flatten the object so all properties are in the first level.
 | 
					        return CoreObject.toGetParams(object, removeEmpty);
 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -995,6 +846,7 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
     * @param data Object.
 | 
					     * @param data Object.
 | 
				
			||||||
     * @param prefix Prefix to add.
 | 
					     * @param prefix Prefix to add.
 | 
				
			||||||
     * @returns Prefixed object.
 | 
					     * @returns Prefixed object.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Not used anymore
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    prefixKeys(data: Record<string, unknown>, prefix: string): Record<string, unknown> {
 | 
					    prefixKeys(data: Record<string, unknown>, prefix: string): Record<string, unknown> {
 | 
				
			||||||
        const newObj = {};
 | 
					        const newObj = {};
 | 
				
			||||||
@ -1012,9 +864,10 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param enumeration Enumeration object.
 | 
					     * @param enumeration Enumeration object.
 | 
				
			||||||
     * @returns Keys of the enumeration.
 | 
					     * @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[] {
 | 
					    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 obj2 The second object or array.
 | 
				
			||||||
     * @param key Key to check.
 | 
					     * @param key Key to check.
 | 
				
			||||||
     * @returns Whether the two objects/arrays have the same value (or lack of one) for a given key.
 | 
					     * @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(
 | 
					    sameAtKeyMissingIsBlank(
 | 
				
			||||||
        obj1: Record<string, unknown> | unknown[],
 | 
					        obj1: Record<string, unknown> | unknown[],
 | 
				
			||||||
        obj2: Record<string, unknown> | unknown[],
 | 
					        obj2: Record<string, unknown> | unknown[],
 | 
				
			||||||
        key: string,
 | 
					        key: string,
 | 
				
			||||||
    ): boolean {
 | 
					    ): boolean {
 | 
				
			||||||
        let value1 = obj1[key] !== undefined ? obj1[key] : '';
 | 
					        return CoreObject.sameAtKeyMissingIsBlank(obj1, obj2, 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;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -1073,9 +917,11 @@ export class CoreUtilsProvider {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param obj Object to stringify.
 | 
					     * @param obj Object to stringify.
 | 
				
			||||||
     * @returns Stringified object.
 | 
					     * @returns Stringified object.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreObject.sortAndStringify instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    sortAndStringify(obj: Record<string, unknown>): string {
 | 
					    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.
 | 
					     * @param obj The object to sort. If it isn't an object, the original value will be returned.
 | 
				
			||||||
     * @returns Sorted object.
 | 
					     * @returns Sorted object.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreObject.sortProperties instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    sortProperties<T>(obj: T): T {
 | 
					    sortProperties<T>(obj: T): T {
 | 
				
			||||||
        if (obj != null && typeof obj == 'object' && !Array.isArray(obj)) {
 | 
					        return CoreObject.sortProperties(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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -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.
 | 
					     * @param obj The object to sort. If it isn't an object, the original value will be returned.
 | 
				
			||||||
     * @returns Sorted object.
 | 
					     * @returns Sorted object.
 | 
				
			||||||
 | 
					     * @deprecated since 5.0. Use CoreObject.sortValues instead.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    sortValues<T>(obj: T): T {
 | 
					    sortValues<T>(obj: T): T {
 | 
				
			||||||
        if (typeof obj == 'object' && !Array.isArray(obj)) {
 | 
					        return CoreObject.sortValues(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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -170,7 +170,7 @@ export class CoreWSProvider {
 | 
				
			|||||||
            if (value == null) {
 | 
					            if (value == null) {
 | 
				
			||||||
                // Skip null or undefined value.
 | 
					                // Skip null or undefined value.
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            } else if (typeof value == 'object') {
 | 
					            } else if (typeof value === 'object') {
 | 
				
			||||||
                // Object or array.
 | 
					                // Object or array.
 | 
				
			||||||
                value = this.convertValuesToString(value, stripUnicode);
 | 
					                value = this.convertValuesToString(value, stripUnicode);
 | 
				
			||||||
                if (value == null) {
 | 
					                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).
 | 
					            // 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()
 | 
					                const message = CoreSites.isLoggedIn()
 | 
				
			||||||
                    ? Translate.instant('core.siteunavailablehelp', { site: CoreSites.getCurrentSite()?.siteUrl })
 | 
					                    ? Translate.instant('core.siteunavailablehelp', { site: CoreSites.getCurrentSite()?.siteUrl })
 | 
				
			||||||
                    : Translate.instant('core.sitenotfoundhelp');
 | 
					                    : 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"');
 | 
					            this.logger.warn('Upload file: Response of type "' + typeof data + '" received, expecting "object"');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            throw await this.createCannotConnectSiteError(preSets.siteUrl, {
 | 
					            throw await this.createCannotConnectSiteError(preSets.siteUrl, {
 | 
				
			||||||
 | 
				
			|||||||
@ -17,6 +17,62 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
export class CoreArray {
 | 
					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.
 | 
					     * 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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -44,7 +44,7 @@ export class CoreFileUtils {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    static valueIsFileEntry(file: unknown): file is FileEntry {
 | 
					    static valueIsFileEntry(file: unknown): file is FileEntry {
 | 
				
			||||||
        // We cannot use instanceof because FileEntry is a type. Check some of the properties.
 | 
					        // 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);
 | 
					            'toInternalURL' in file && 'copyTo' in file);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,11 @@ export type CoreObjectWithoutUndefined<T> = Pretty<{
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
export class CoreObject {
 | 
					export class CoreObject {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Avoid creating singleton instances.
 | 
				
			||||||
 | 
					    private constructor() {
 | 
				
			||||||
 | 
					        // Nothing to do.
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Returns a value of an object and deletes it from the object.
 | 
					     * Returns a value of an object and deletes it from the object.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -170,4 +175,335 @@ export class CoreObject {
 | 
				
			|||||||
        return cleanObj as CoreObjectWithoutUndefined<T>;
 | 
					        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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user