parent
e36620854c
commit
a67e04bdc4
@ -0,0 +1,74 @@
|
||||
import { AbstractVAO, TMappingFn, VAO } from "./VAO.js";
|
||||
import { RenderableVAO } from "./RenderableVAO.js";
|
||||
import { VAOUtil } from "./VAOUtil.js";
|
||||
|
||||
// === TODO ===
|
||||
// [A] yielded VAO should follow array VAO
|
||||
// [B] consider if this way of passing detachable can be improved
|
||||
|
||||
const DIFF_INSERT = {};
|
||||
const DIFF_REMOVE = {};
|
||||
const DIFF_REPLACE = {};
|
||||
|
||||
export class ArrayVAO extends AbstractVAO {
|
||||
private value_: any[]
|
||||
|
||||
protected getTopics_(): string[] {
|
||||
return [
|
||||
'change',
|
||||
'item.insert',
|
||||
'item.remove',
|
||||
'item.replace'
|
||||
]
|
||||
}
|
||||
|
||||
constructor (initialValue: any[]) {
|
||||
super();
|
||||
if ( ! Array.isArray(initialValue) ) {
|
||||
throw new Error('ArrayVAO expects an array');
|
||||
}
|
||||
this.value_ = initialValue;
|
||||
}
|
||||
|
||||
// TODO: move to AbstractVAO if this isn't modified by version 1.2.0
|
||||
set (value: any[]) {
|
||||
let o = this.value_;
|
||||
this.value_ = value;
|
||||
if ( o !== this.value_ ) {
|
||||
this.pub('change');
|
||||
}
|
||||
}
|
||||
|
||||
get (): any {
|
||||
return this.value_;
|
||||
}
|
||||
|
||||
each (mappingFn: TMappingFn): VAO[] {
|
||||
const results = [];
|
||||
// TODO: [A]
|
||||
for ( const item of this.value_ ) {
|
||||
const vao = VAOUtil.getAppropriateVAO(item);
|
||||
const [renderable, detachable] =
|
||||
vao.map(mappingFn, RenderableVAO);
|
||||
// TODO: [B]
|
||||
;(renderable as RenderableVAO).detachable?.detach?.();
|
||||
results.push(renderable)
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// diffArrays_(oldArray, newArray) {
|
||||
// let ptrOld = 0;
|
||||
// let ptrNew = 0;
|
||||
|
||||
// const events = [];
|
||||
|
||||
// while ( ptrOld < oldArray.length ) {
|
||||
// }
|
||||
|
||||
// while ( otrNew < newArray.length ) {
|
||||
// events.push();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
import { ScalarVAO } from "./ScalarVAO.js";
|
||||
import { Detachable } from "./VAO.js";
|
||||
import { Renderable, INotifyMounted } from "../component/componentdefs.js";
|
||||
|
||||
export class RenderableVAO extends ScalarVAO {
|
||||
protected renderChildren_: Renderable[] | null = null;
|
||||
protected elements_: Element[];
|
||||
protected parent_: Element | null = null;
|
||||
protected rerenderSubscription_: Detachable | null;
|
||||
|
||||
public detachable: Detachable | null = null;
|
||||
|
||||
constructor (value: any) {
|
||||
super(value);
|
||||
|
||||
this.elements_ = [];
|
||||
this.rerenderSubscription_ = null;
|
||||
}
|
||||
|
||||
createElements (): Element[] {
|
||||
let renderables = this.get();
|
||||
let renderablesTS: Renderable[] = Array.isArray(renderables)
|
||||
? renderables : [renderables];
|
||||
|
||||
const elements = [];
|
||||
for ( const renderable of renderablesTS ) {
|
||||
const theseElements = renderable.createElements();
|
||||
elements.push(...theseElements);
|
||||
}
|
||||
|
||||
this.elements_ = elements;
|
||||
return elements;
|
||||
}
|
||||
|
||||
rerenderSelf () {
|
||||
if ( ! this.parent_ ) {
|
||||
throw new Error('cannot re-render; no existing element');
|
||||
}
|
||||
|
||||
if ( this.elements_.length === 0 ) {
|
||||
throw new Error('cannot re-render a component with zero elements');
|
||||
}
|
||||
|
||||
this.onWillDetachFromDOM_();
|
||||
|
||||
// The reference element lets us know where to put new elements
|
||||
const referenceElement = this.elements_[0];
|
||||
|
||||
// Remove following elements - we're going to replace the first one
|
||||
for ( const element of this.elements_.slice(1) ) {
|
||||
element.remove();
|
||||
}
|
||||
|
||||
const newElements = this.createElements();
|
||||
referenceElement.replaceWith(...newElements);
|
||||
this.notifyMounted({
|
||||
parent: this.parent_,
|
||||
})
|
||||
}
|
||||
|
||||
notifyWillDetachFromDOM () {
|
||||
if ( this.detachable ) this.detachable.detach();
|
||||
this.onWillDetachFromDOM_();
|
||||
}
|
||||
onWillDetachFromDOM_ () {
|
||||
if ( this.rerenderSubscription_ ) {
|
||||
this.rerenderSubscription_.detach();
|
||||
}
|
||||
// Detach listeners from child renderables generated last time
|
||||
if ( ! this.renderChildren_ ) {
|
||||
throw new Error('tried to detach before rendering');
|
||||
}
|
||||
for ( const renderable of this.renderChildren_ ) {
|
||||
renderable.notifyWillDetachFromDOM();
|
||||
}
|
||||
}
|
||||
|
||||
notifyMounted(event: INotifyMounted) {
|
||||
this.parent_ = event.parent;
|
||||
|
||||
this.rerenderSubscription_ = this.sub('change', () => {
|
||||
this.rerenderSelf();
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
import { ScalarVAO } from "./ScalarVAO.js";
|
||||
import { ArrayVAO } from "./ArrayVAO.js";
|
||||
import { AbstractVAO, VAO } from "./VAO.js";
|
||||
|
||||
export class VAOUtil {
|
||||
static getAppropriateVAO (value: any): VAO {
|
||||
if ( value instanceof AbstractVAO ) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if ( Array.isArray(value) ) {
|
||||
return new ArrayVAO(value);
|
||||
}
|
||||
|
||||
return new ScalarVAO(value);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue