Compare commits

..

No commits in common. 'e36620854cc8beea97120875892a19b965e91481' and '69e2d90b95af747d91f57173cd39e010d82cddd1' have entirely different histories.

@ -1,6 +1,6 @@
import { TAttributes } from "../html/htmldefs"; import { TAttributes } from "../html/htmldefs";
import { ScalarVAO } from "../vao/ScalarVAO.js"; import { ScalarVAO } from "../vao/ScalarVAO.js";
import { AbstractVAO, Detachable, VAO, VAOConstructor } from "../vao/VAO.js"; import { AbstractVAO, Detachable, VAO } from "../vao/VAO.js";
import { Renderable, INotifyMounted } from "./componentdefs"; import { Renderable, INotifyMounted } from "./componentdefs";
// === TODO === // === TODO ===
@ -13,24 +13,11 @@ import { Renderable, INotifyMounted } from "./componentdefs";
// [F] investigate possibility of detecting/avoiding infinite recursion here // [F] investigate possibility of detecting/avoiding infinite recursion here
// [G] definition of "mounted" doesn't match React. Maybe call it something // [G] definition of "mounted" doesn't match React. Maybe call it something
// else to avoid confusion. // else to avoid confusion.
// [H] investigate possibility of using an AST test to ensure methods like
// setOrCreateVAO are called instead of re-implementing their behaviour
// [I] VAOs should install themselves into components so they can add behaviour
// to the instance proxy and implement optimizations for methods like
// Array.prototype.push, Object.assign, etc.
interface PropertyDefinition {
$?: VAOConstructor,
factory?: () => any
}
type TPropertyDefinitions = { [key: string]: PropertyDefinition }
export abstract class Component { export abstract class Component {
public attributes: TAttributes public attributes: TAttributes
public children: Renderable[] public children: Renderable[]
static properties: TPropertyDefinitions | undefined;
protected renderChildren_: Renderable[] | null = null; protected renderChildren_: Renderable[] | null = null;
protected instanceProxy_: Component | null = null; protected instanceProxy_: Component | null = null;
protected vaos_: { [name: string]: VAO } protected vaos_: { [name: string]: VAO }
@ -62,37 +49,22 @@ export abstract class Component {
this.rerenderVAOs_ = {}; this.rerenderVAOs_ = {};
this.rerenderSubscriptions_ = []; this.rerenderSubscriptions_ = [];
const constructorAsWhatItIs: typeof Component =
(this.constructor as unknown) as typeof Component;
const allProperties = constructorAsWhatItIs.allProperties_;
for ( let k in allProperties ) {
const property = allProperties[k];
const value = this.getPropertyInitialValue_(k);
if ( property.$ !== undefined ) {
const vao = this.createVAOFromProperty_(property, value);
if ( ! ( vao instanceof AbstractVAO ) ) {
throw new Error('expected a VAO');
}
// TODO: [I]
this.vaos_[k] = vao;
} else {
this.createDynamicVAO_(k, value)
}
}
for ( let k in attributes ) { for ( let k in attributes ) {
if ( attributes[k] instanceof AbstractVAO ) { if ( attributes[k] instanceof AbstractVAO ) {
this.vaos_[k] = attributes[k]; this.vaos_[k] = attributes[k];
} else { } else {
this.setOrCreateVAO_(k, attributes[k]); // TODO: [E]
const vao = new ScalarVAO(attributes[k]);
this.vaos_[k] = vao;
} }
} }
} }
createElements (): Element[] { createElements (): Element[] {
// TODO: [C] // TODO: [C]
for ( const detachable of this.rerenderSubscriptions_ ) {
detachable.detach();
}
let renderables = this.render.call(this.instanceProxy); let renderables = this.render.call(this.instanceProxy);
@ -122,8 +94,6 @@ export abstract class Component {
throw new Error('cannot re-render a component with zero elements'); throw new Error('cannot re-render a component with zero elements');
} }
this.onWillDetachFromDOM_();
// The reference element lets us know where to put new elements // The reference element lets us know where to put new elements
const referenceElement = this.elements_[0]; const referenceElement = this.elements_[0];
@ -140,36 +110,8 @@ export abstract class Component {
}) })
} }
notifyWillDetachFromDOM () { createDynamicVAO_ (vaoName: string) {
this.onWillDetachFromDOM_(); this.vaos_[vaoName] = new ScalarVAO(null);
}
onWillDetachFromDOM_ () {
// Detach rerender subscriptions
for ( const detachable of this.rerenderSubscriptions_ ) {
detachable.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();
}
}
createDynamicVAO_ (vaoName: string, value?: any) {
// TODO: [E], [I]
this.vaos_[vaoName] = new ScalarVAO(value ?? null);
}
// TODO: [H]
setOrCreateVAO_ (vaoName: string, value: any) {
if ( ! this.vaos_[vaoName] ) {
this.createDynamicVAO_(vaoName, value);
return;
}
this.vaos_[vaoName].set(value);
} }
notifyMounted(event: INotifyMounted) { notifyMounted(event: INotifyMounted) {
@ -230,52 +172,4 @@ export abstract class Component {
return this.instanceProxy_; return this.instanceProxy_;
} }
static allProperties__: TPropertyDefinitions | null;
static get allProperties_ () {
if ( this.allProperties__ ) return this.allProperties__;
const properties: TPropertyDefinitions = {};
let cls = this;
for (
;
cls.prototype instanceof Component;
cls = Object.getPrototypeOf(cls)
) {
if ( ! cls.properties ) continue;
for ( const k in cls.properties ) {
if ( properties.hasOwnProperty(k) ) {
properties[k] = Object.assign(
{ ...cls.properties[k] }, properties[k]);
} else {
properties[k] = cls.properties[k];
}
}
}
return this.allProperties__ = properties;
}
getPropertyInitialValue_ (k: string): any {
const constructorAsWhatItIs: typeof Component =
(this.constructor as unknown) as typeof Component;
const allProperties = constructorAsWhatItIs.allProperties_;
const property = allProperties[k];
if ( property.factory !== undefined ) {
return property.factory();
}
return null;
}
createVAOFromProperty_ (property: PropertyDefinition, initialValue: any): VAO {
if ( property.$ === undefined ) {
throw new Error('called createVAOFromProperty_ with invalid input');
}
return new property.$(initialValue);
}
} }

@ -61,12 +61,6 @@ export class Tag {
return [el]; return [el];
} }
notifyWillDetachFromDOM() {
for ( const axiom of this.axioms_ ) {
axiom.detach();
}
}
notifyMounted (event: INotifyMounted) { notifyMounted (event: INotifyMounted) {
console.log('notifyMounted called on a tag', this); console.log('notifyMounted called on a tag', this);
if ( this.element_ == null ) { if ( this.element_ == null ) {

@ -6,7 +6,6 @@ export interface INotifyMounted {
export interface Renderable { export interface Renderable {
createElements: () => Element[] createElements: () => Element[]
notifyWillDetachFromDOM: () => void
notifyMounted: (event: INotifyMounted) => void notifyMounted: (event: INotifyMounted) => void
} }
export interface RenderableConstructor { export interface RenderableConstructor {

@ -25,10 +25,6 @@ export interface VAO {
set (value: any): void set (value: any): void
} }
export interface VAOConstructor {
new (initialValue: any): VAO
}
export abstract class AbstractVAO implements VAO { export abstract class AbstractVAO implements VAO {
private listeners_: TListenerList private listeners_: TListenerList
constructor () { constructor () {

Loading…
Cancel
Save