vasille
Version:
The same framework which is designed to build bulletproof frontends (core library).
126 lines (125 loc) • 3.65 kB
JavaScript
import { Listener } from "./listener.js";
/**
* Model based on Array class
* @extends Array
* @implements ListenableModel
*/
export class ArrayModel extends Array {
listener;
/**
* @param data {Array} input data
* @param ctx lifetime context of model
*/
constructor(data, ctx) {
super();
this.listener = new Listener();
if (data instanceof Array) {
for (let i = 0; i < data.length; i++) {
super.push(data[i]);
}
}
ctx?.bind(this);
}
/* Array members */
/**
* Calls `Array.fill` and notify about changes
* @param value {*} value to fill with
* @param start {?number} begin index
* @param end {?number} end index
*/
fill(value, start, end) {
/* istanbul ignore else */
if (!start) {
start = 0;
}
/* istanbul ignore else */
if (!end) {
end = this.length;
}
for (let i = start; i < end; i++) {
this.listener.emitRemoved(this[i], this[i]);
this[i] = value;
this.listener.emitAdded(value, value);
}
return this;
}
/**
* Calls `Array.pop` and notify about changes
* @return {*} removed value
*/
pop() {
/* istanbul ignore else */
if (this.length > 0) {
const v = super.pop();
this.listener.emitRemoved(v, v);
return v;
}
}
/**
* Calls `Array.push` and notify about changes
* @param items {...*} values to push
* @return {number} new length of the array
*/
push(...items) {
items.forEach(item => {
this.listener.emitAdded(item, item);
super.push(item);
});
return this.length;
}
/**
* Calls `Array.shift` and notify about changed
* @return {*} the shifted value
*/
shift() {
/* istanbul ignore else */
if (this.length > 0) {
const v = super.shift();
this.listener.emitRemoved(v, v);
return v;
}
}
/**
* Calls `Array.splice` and notify about changed
* @param start {number} start index
* @param deleteCount {?number} delete count
* @param items {...*}
* @return {ArrayModel} a pointer to this
*/
splice(start, deleteCount, ...items) {
start = Math.min(start, this.length);
deleteCount = typeof deleteCount === "number" ? deleteCount : this.length - start;
const before = this[start + deleteCount];
for (let i = 0; i < deleteCount; i++) {
const index = start + deleteCount - i - 1;
/* istanbul ignore else */
if (this[index] !== undefined) {
this.listener.emitRemoved(this[index], this[index]);
}
}
for (let i = 0; i < items.length; i++) {
this.listener.emitAdded(before, items[i]);
}
return new ArrayModel(super.splice(start, deleteCount, ...items));
}
/**
* Calls Array.unshift and notify about changed
* @param items {...*} values to insert
* @return {number} the length after prepending
*/
unshift(...items) {
for (let i = 0; i < items.length; i++) {
this.listener.emitAdded(this[i], items[i]);
}
return super.unshift(...items);
}
replace(at, with_) {
this.listener.emitAdded(this[at], with_);
this.listener.emitRemoved(this[at], this[at]);
this[at] = with_;
return this;
}
destroy() {
this.splice(0);
}
}