MOBILE-4565 utils: Move some array functions to CoreArray
parent
f9ddfb48c9
commit
93b420311d
|
@ -28,6 +28,7 @@ import { CoreDomUtils } from '@services/utils/dom';
|
|||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreTime } from '@singletons/time';
|
||||
|
||||
|
@ -218,7 +219,7 @@ export class AddonBlogIndexPage implements OnInit, OnDestroy {
|
|||
if (refresh) {
|
||||
this.entries = result.entries;
|
||||
} else {
|
||||
this.entries = CoreUtils.uniqueArray(this.entries
|
||||
this.entries = CoreArray.unique(this.entries
|
||||
.concat(result.entries), 'id')
|
||||
.sort((a, b) => b.created - a.created);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import { CoreTextUtils } from '@services/utils/text';
|
|||
import { CoreXAPIIRI } from '@features/xapi/classes/iri';
|
||||
import { CoreXAPIItemAgent } from '@features/xapi/classes/item-agent';
|
||||
import { CoreWSError } from '@classes/errors/wserror';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
|
||||
/**
|
||||
* Service to sync H5P activities.
|
||||
|
@ -76,7 +77,7 @@ export class AddonModH5PActivitySyncProvider extends CoreCourseActivitySyncBaseP
|
|||
]);
|
||||
|
||||
const entries = (<(CoreXAPIStatementDBRecord|CoreXAPIStateDBRecord)[]> statements).concat(states);
|
||||
const contextIds = CoreUtils.uniqueArray(entries.map(entry => 'contextid' in entry ? entry.contextid : entry.itemid));
|
||||
const contextIds = CoreArray.unique(entries.map(entry => 'contextid' in entry ? entry.contextid : entry.itemid));
|
||||
|
||||
// Sync all activities.
|
||||
const promises = contextIds.map(async (contextId) => {
|
||||
|
|
|
@ -24,6 +24,7 @@ import { CoreEvents } from '@singletons/events';
|
|||
import { AddonNotesDBRecord, AddonNotesDeletedDBRecord } from './database/notes';
|
||||
import { AddonNotes, AddonNotesCreateNoteData } from './notes';
|
||||
import { AddonNotesOffline } from './notes-offline';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
|
||||
/**
|
||||
* Service to sync notes.
|
||||
|
@ -67,7 +68,7 @@ export class AddonNotesSyncProvider extends CoreSyncBaseProvider<AddonNotesSyncR
|
|||
courseIds = courseIds.concat(notes.map((note) => note.courseid));
|
||||
});
|
||||
|
||||
CoreUtils.uniqueArray(courseIds);
|
||||
CoreArray.unique(courseIds);
|
||||
|
||||
// Sync all courses.
|
||||
const promises = courseIds.map(async (courseId) => {
|
||||
|
|
|
@ -40,6 +40,7 @@ import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
|||
import { CorePromisedValue } from '@classes/promised-value';
|
||||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
|
||||
/**
|
||||
* Directive to handle external content.
|
||||
|
@ -279,7 +280,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges, O
|
|||
return;
|
||||
}
|
||||
|
||||
const urls = CoreUtils.uniqueArray(Array.from(inlineStyles.match(/https?:\/\/[^"') ;]*/g) ?? []));
|
||||
const urls = CoreArray.unique(Array.from(inlineStyles.match(/https?:\/\/[^"') ;]*/g) ?? []));
|
||||
if (!urls.length) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import { makeSingleton } from '@singletons';
|
|||
import { CoreEnrolAction, CoreEnrolDelegate, CoreEnrolInfoIcon } from './enrol-delegate';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreEnrol, CoreEnrolEnrolmentMethod } from './enrol';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
|
||||
/**
|
||||
* Service that provides helper functions for enrolment plugins.
|
||||
|
@ -32,7 +33,7 @@ export class CoreEnrolHelperService {
|
|||
* @returns Enrolment icons to show.
|
||||
*/
|
||||
async getEnrolmentIcons(methodTypes: string[], courseId: number): Promise<CoreEnrolInfoIcon[]> {
|
||||
methodTypes = CoreUtils.uniqueArray(methodTypes);
|
||||
methodTypes = CoreArray.unique(methodTypes);
|
||||
|
||||
let enrolmentIcons: CoreEnrolInfoIcon[] = [];
|
||||
let addBrowserOption = false;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreFileUploaderHandler, CoreFileUploaderHandlerData, CoreFileUploaderHandlerResult } from '../fileuploader-delegate';
|
||||
import { CoreFileUploaderHelper } from '../fileuploader-helper';
|
||||
|
@ -41,7 +41,7 @@ export class CoreFileUploaderAlbumHandlerService implements CoreFileUploaderHand
|
|||
*/
|
||||
getSupportedMimetypes(mimetypes: string[]): string[] {
|
||||
// Album allows picking images and videos.
|
||||
return CoreUtils.filterByRegexp(mimetypes, /^(image|video)\//);
|
||||
return CoreArray.filterByRegexp(mimetypes, /^(image|video)\//);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,10 +16,11 @@ import { Injectable } from '@angular/core';
|
|||
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreFileUploaderHandler, CoreFileUploaderHandlerData, CoreFileUploaderHandlerResult } from '../fileuploader-delegate';
|
||||
import { CoreFileUploaderHelper } from '../fileuploader-helper';
|
||||
|
||||
/**
|
||||
* Handler to record an audio to upload it.
|
||||
*/
|
||||
|
@ -42,10 +43,10 @@ export class CoreFileUploaderAudioHandlerService implements CoreFileUploaderHand
|
|||
getSupportedMimetypes(mimetypes: string[]): string[] {
|
||||
if (CorePlatform.isIOS()) {
|
||||
// In iOS it's recorded as WAV.
|
||||
return CoreUtils.filterByRegexp(mimetypes, /^audio\/wav$/);
|
||||
return CoreArray.filterByRegexp(mimetypes, /^audio\/wav$/);
|
||||
} else if (CorePlatform.isAndroid()) {
|
||||
// In Android we don't know the format the audio will be recorded, so accept any audio mimetype.
|
||||
return CoreUtils.filterByRegexp(mimetypes, /^audio\//);
|
||||
return CoreArray.filterByRegexp(mimetypes, /^audio\//);
|
||||
} else {
|
||||
// In browser, support audio formats that are supported by MediaRecorder.
|
||||
if (MediaRecorder) {
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreFileUploaderHandler, CoreFileUploaderHandlerData, CoreFileUploaderHandlerResult } from '../fileuploader-delegate';
|
||||
import { CoreFileUploaderHelper } from '../fileuploader-helper';
|
||||
|
@ -42,7 +42,7 @@ export class CoreFileUploaderCameraHandlerService implements CoreFileUploaderHan
|
|||
*/
|
||||
getSupportedMimetypes(mimetypes: string[]): string[] {
|
||||
// Camera only supports JPEG and PNG.
|
||||
return CoreUtils.filterByRegexp(mimetypes, /^image\/(jpeg|png)$/);
|
||||
return CoreArray.filterByRegexp(mimetypes, /^image\/(jpeg|png)$/);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,10 +16,11 @@ import { Injectable } from '@angular/core';
|
|||
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreFileUploaderHandler, CoreFileUploaderHandlerData, CoreFileUploaderHandlerResult } from '../fileuploader-delegate';
|
||||
import { CoreFileUploaderHelper } from '../fileuploader-helper';
|
||||
|
||||
/**
|
||||
* Handler to record a video to upload it.
|
||||
*/
|
||||
|
@ -42,10 +43,10 @@ export class CoreFileUploaderVideoHandlerService implements CoreFileUploaderHand
|
|||
getSupportedMimetypes(mimetypes: string[]): string[] {
|
||||
if (CorePlatform.isIOS()) {
|
||||
// In iOS it's recorded as MOV.
|
||||
return CoreUtils.filterByRegexp(mimetypes, /^video\/quicktime$/);
|
||||
return CoreArray.filterByRegexp(mimetypes, /^video\/quicktime$/);
|
||||
} else if (CorePlatform.isAndroid()) {
|
||||
// In Android we don't know the format the video will be recorded, so accept any video mimetype.
|
||||
return CoreUtils.filterByRegexp(mimetypes, /^video\//);
|
||||
return CoreArray.filterByRegexp(mimetypes, /^video\//);
|
||||
} else {
|
||||
// In browser, support video formats that are supported by MediaRecorder.
|
||||
if (MediaRecorder) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
import { CoreH5P } from '@features/h5p/services/h5p';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreH5PCore, CoreH5PLibraryData, CoreH5PLibraryAddonData, CoreH5PContentDepsTreeDependency } from './core';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
|
||||
const ALLOWED_STYLEABLE_TAGS = ['span', 'p', 'div', 'h1', 'h2', 'h3', 'td'];
|
||||
|
||||
|
@ -131,7 +132,7 @@ export class CoreH5PContentValidator {
|
|||
tags.push('s');
|
||||
}
|
||||
|
||||
tags = CoreUtils.uniqueArray(tags);
|
||||
tags = CoreArray.unique(tags);
|
||||
|
||||
// Determine allowed style tags
|
||||
const stylePatterns: RegExp[] = [];
|
||||
|
@ -372,7 +373,7 @@ export class CoreH5PContentValidator {
|
|||
if (semantics.extraAttributes) {
|
||||
validKeys = validKeys.concat(semantics.extraAttributes);
|
||||
}
|
||||
validKeys = CoreUtils.uniqueArray(validKeys);
|
||||
validKeys = CoreArray.unique(validKeys);
|
||||
|
||||
this.filterParams(file, validKeys);
|
||||
|
||||
|
@ -556,7 +557,7 @@ export class CoreH5PContentValidator {
|
|||
|
||||
let validKeys = ['library', 'params', 'subContentId', 'metadata'];
|
||||
if (semantics.extraAttributes) {
|
||||
validKeys = CoreUtils.uniqueArray(validKeys.concat(semantics.extraAttributes));
|
||||
validKeys = CoreArray.unique(validKeys.concat(semantics.extraAttributes));
|
||||
}
|
||||
|
||||
this.filterParams(value, validKeys);
|
||||
|
|
|
@ -40,6 +40,7 @@ import { CoreCancellablePromise } from '@classes/cancellable-promise';
|
|||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||
import { CoreUrlUtils } from './url';
|
||||
import { QRScanner } from '@features/native/plugins';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
|
||||
export type TreeNode<T> = T & { children: TreeNode<T>[] };
|
||||
|
||||
|
@ -350,6 +351,7 @@ export class CoreUtilsProvider {
|
|||
* @param from Object to copy the properties from.
|
||||
* @param to Object where to store the properties.
|
||||
* @param clone Whether the properties should be cloned (so they are different instances).
|
||||
* @deprecated since 4.4. Not used anymore.
|
||||
*/
|
||||
copyProperties(from: Record<string, unknown>, to: Record<string, unknown>, clone: boolean = true): void {
|
||||
for (const name in from) {
|
||||
|
@ -387,6 +389,7 @@ export class CoreUtilsProvider {
|
|||
* Empties an array without losing its reference.
|
||||
*
|
||||
* @param array Array to empty.
|
||||
* @deprecated since 4.4. Not used anymore.
|
||||
*/
|
||||
emptyArray(array: unknown[]): void {
|
||||
array.length = 0; // Empty array without losing its reference.
|
||||
|
@ -396,6 +399,7 @@ export class CoreUtilsProvider {
|
|||
* Removes all properties from an object without losing its reference.
|
||||
*
|
||||
* @param object Object to remove the properties.
|
||||
* @deprecated since 4.4. Not used anymore.
|
||||
*/
|
||||
emptyObject(object: Record<string, unknown>): void {
|
||||
for (const key in object) {
|
||||
|
@ -482,17 +486,10 @@ export class CoreUtilsProvider {
|
|||
* @param array Array to filter.
|
||||
* @param regex RegExp to apply to each string.
|
||||
* @returns Filtered array.
|
||||
* @deprecated since 4.4. Use CoreArray.filterByRegexp instead.
|
||||
*/
|
||||
filterByRegexp(array: string[], regex: RegExp): string[] {
|
||||
if (!array || !array.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array.filter((entry) => {
|
||||
const matches = entry.match(regex);
|
||||
|
||||
return matches && matches.length;
|
||||
});
|
||||
return CoreArray.filterByRegexp(array, regex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -956,7 +953,7 @@ export class CoreUtilsProvider {
|
|||
* @returns Merged array.
|
||||
*/
|
||||
mergeArraysWithoutDuplicates<T>(array1: T[], array2: T[], key?: string): T[] {
|
||||
return this.uniqueArray(array1.concat(array2), key) as T[];
|
||||
return CoreArray.unique(array1.concat(array2), key) as T[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1390,6 +1387,7 @@ export class CoreUtilsProvider {
|
|||
* @param data Object.
|
||||
* @param prefix Prefix to add.
|
||||
* @returns Prefixed object.
|
||||
* @deprecated since 4.4. Not used anymore.
|
||||
*/
|
||||
prefixKeys(data: Record<string, unknown>, prefix: string): Record<string, unknown> {
|
||||
const newObj = {};
|
||||
|
@ -1611,21 +1609,10 @@ export class CoreUtilsProvider {
|
|||
* @param array The array to treat.
|
||||
* @param [key] Key of the property that must be unique. If not specified, the whole entry.
|
||||
* @returns Array without duplicate values.
|
||||
* @deprecated since 4.4. Use CoreArray.unique instead.
|
||||
*/
|
||||
uniqueArray<T>(array: T[], key?: string): T[] {
|
||||
const unique = {}; // Use an object to make it faster to check if it's duplicate.
|
||||
|
||||
return array.filter(entry => {
|
||||
const value = key ? entry[key] : entry;
|
||||
|
||||
if (value in unique) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unique[value] = true;
|
||||
|
||||
return true;
|
||||
});
|
||||
return CoreArray.unique(array, key);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -66,4 +66,46 @@ export class CoreArray {
|
|||
return newArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array without duplicate values.
|
||||
*
|
||||
* @param array The array to treat.
|
||||
* @param [key] Key of the property that must be unique. If not specified, the whole entry.
|
||||
* @returns Array without duplicate values.
|
||||
*/
|
||||
static unique<T>(array: T[], key?: string): T[] {
|
||||
const unique = {}; // Use an object to make it faster to check if it's duplicate.
|
||||
|
||||
return array.filter(entry => {
|
||||
const value = key ? entry[key] : entry;
|
||||
|
||||
if (value in unique) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unique[value] = true;
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of strings, return only the ones that match a regular expression.
|
||||
*
|
||||
* @param array Array to filter.
|
||||
* @param regex RegExp to apply to each string.
|
||||
* @returns Filtered array.
|
||||
*/
|
||||
static filterByRegexp(array: string[], regex: RegExp): string[] {
|
||||
if (!array || !array.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array.filter((entry) => {
|
||||
const matches = entry.match(regex);
|
||||
|
||||
return matches && matches.length;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,4 +23,18 @@ describe('CoreArray singleton', () => {
|
|||
expect(CoreArray.withoutItem(originalArray, 'not found')).toEqual(['foo', 'bar', 'baz']);
|
||||
});
|
||||
|
||||
it('gets unique array', () => {
|
||||
const originalArray = ['foo', 'bar', 'foo', 'baz'];
|
||||
|
||||
expect(CoreArray.unique(originalArray)).toEqual(['foo', 'bar', 'baz']);
|
||||
});
|
||||
|
||||
it('filters array by regexp', () => {
|
||||
const originalArray = ['foo', 'bar', 'baz', 'qux'];
|
||||
|
||||
expect(CoreArray.filterByRegexp(originalArray, /ba/)).toEqual(['bar', 'baz']);
|
||||
expect(CoreArray.filterByRegexp(originalArray, /foo/)).toEqual(['foo']);
|
||||
expect(CoreArray.filterByRegexp([], /foo/)).toEqual([]);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue