(function() {
/**
* to be used as a base class for data containers
* this is a Set of objects that will not allow duplicates!
* @augments Help4.jscore.Base
*/
Help4.jscore.DataContainer = class extends Help4.jscore.Base {
/**
* @override
* @param {?Object[]} [init = []]
*/
constructor(init) {
super({
statics: {
_store: {init: init || [], destroy: false},
onChange: {init: new Help4.EmbeddedEvent()}
}
});
}
/** @returns {Help4.jscore.DataContainer} */
clean() {
if (this._store.length) {
const oldValue = this.toArray();
this._store = [];
this.onChange.onEvent({value: [], oldValue});
}
return this;
}
/** @returns {number} */
count() {
return this._store.length;
}
/** @returns {Help4.jscore.DataContainer} */
clone() {
return new this.constructor(this.toArray());
}
/**
* @param {Help4.jscore.DataContainer} instance
* @returns {boolean}
*/
equals(instance) {
if (instance === this) return true;
const a1 = this.toArray();
const a2 = instance.toArray();
return Help4.equalArrays(a1, a2);
}
/**
* @param {Object} item
* @returns {boolean}
*/
includes(item) {
return !!this._store.find(i => Help4.equalObjects(i, item));
}
/**
* @param {number} index
* @returns {Object|null}
*/
get(index) {
return this._store[index] || null;
}
/**
* @param {Object} items
* @returns {Help4.jscore.DataContainer}
*/
add(...items) {
const {_store} = this;
const oldValue = this.toArray();
let changed = false;
for (const item of items) {
if (!this.includes(item)) {
_store.push(Help4.cloneObject(item));
changed = true;
}
}
changed && this.onChange.onEvent({value: this.toArray(), oldValue});
return this;
}
/**
* @param {Array<Object>} items
* @returns {Help4.jscore.DataContainer}
*/
set(...items) {
const changed = this._store.length || items.length;
const oldValue = this.toArray();
this._store = [];
const {_store} = this;
for (const item of items) {
this.includes(item) || _store.push(Help4.cloneObject(item));
}
changed && this.onChange.onEvent({value: this.toArray(), oldValue});
return this;
}
/**
* @param {Object} item
* @returns {Help4.jscore.DataContainer}
*/
remove(item) {
const {_store} = this;
const index = _store.findIndex(i => Help4.equalObjects(i, item));
if (index >= 0) {
const oldValue = this.toArray();
_store.splice(index, 1);
this.onChange.onEvent({value: this.toArray(), oldValue});
}
return this;
}
/**
* @param {Object} query
* @returns {Object|null}
*/
find(query) {
/**
* @param {*} query
* @param {*} store
* @returns {boolean|null|Object}
*/
const find = (query, store) => {
if (query == null || store == null) return query === store;
const isQueryObject = typeof query === 'object';
const isStoreObject = typeof store === 'object';
const isStoreArray = Help4.isArray(store);
if (isQueryObject && isStoreArray) {
const keys = Object.keys(query);
for (const item of store) {
if (keys.every(key => !!find(query[key], item[key]))) return item;
}
return null;
}
if (isQueryObject && isStoreObject) {
for (const [key, value] of Object.entries(query)) {
if (!Help4.equalValues(value, store[key])) return false;
}
return true;
}
return Help4.equalValues(query, store);
}
return find(query, this._store);
}
/** @returns {Array<Object>} */
toArray() {
return Help4.cloneArray(this._store);
}
/**
* for (const control of container) {
* ...
* }
*
* @returns {{next: (function(): {value: *, done: boolean})}}
*/
[Symbol.iterator]() {
let index = -1;
return {
next: () => ({
value: this._store[++index],
done: !(index in this._store)
})
};
}
}
})();