forked from mystiq/hydrogen-web
create subclass for inline template views (e.g. without sub classing)
This commit is contained in:
parent
d673c8714e
commit
164d72830f
2 changed files with 23 additions and 22 deletions
|
@ -29,7 +29,6 @@ function objHasFns(obj: ClassNames<unknown>): obj is { [className: string]: bool
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export type RenderFn<T> = (t: Builder<T>, vm: T) => ViewNode;
|
export type RenderFn<T> = (t: Builder<T>, vm: T) => ViewNode;
|
||||||
type EventHandler = ((event: Event) => void);
|
type EventHandler = ((event: Event) => void);
|
||||||
type AttributeStaticValue = string | boolean;
|
type AttributeStaticValue = string | boolean;
|
||||||
|
@ -52,20 +51,13 @@ export type Builder<T> = TemplateBuilder<T> & { [tagName in typeof TAG_NAMES[str
|
||||||
- add subviews inside the template
|
- add subviews inside the template
|
||||||
*/
|
*/
|
||||||
// TODO: should we rename this to BoundView or something? As opposed to StaticView ...
|
// TODO: should we rename this to BoundView or something? As opposed to StaticView ...
|
||||||
export class TemplateView<T extends IObservableValue> extends BaseUpdateView<T> {
|
export abstract class TemplateView<T extends IObservableValue> extends BaseUpdateView<T> {
|
||||||
private _render?: RenderFn<T>;
|
|
||||||
private _eventListeners?: { node: Element, name: string, fn: EventHandler, useCapture: boolean }[] = undefined;
|
private _eventListeners?: { node: Element, name: string, fn: EventHandler, useCapture: boolean }[] = undefined;
|
||||||
private _bindings?: (() => void)[] = undefined;
|
private _bindings?: (() => void)[] = undefined;
|
||||||
private _root?: ViewNode = undefined;
|
private _root?: ViewNode = undefined;
|
||||||
// public because used by TemplateBuilder
|
// public because used by TemplateBuilder
|
||||||
_subViews?: IView[] = undefined;
|
_subViews?: IView[] = undefined;
|
||||||
|
|
||||||
constructor(value: T, render?: RenderFn<T>) {
|
|
||||||
super(value);
|
|
||||||
// TODO: can avoid this if we have a separate class for inline templates vs class template views
|
|
||||||
this._render = render;
|
|
||||||
}
|
|
||||||
|
|
||||||
_attach(): void {
|
_attach(): void {
|
||||||
if (this._eventListeners) {
|
if (this._eventListeners) {
|
||||||
for (let {node, name, fn, useCapture} of this._eventListeners) {
|
for (let {node, name, fn, useCapture} of this._eventListeners) {
|
||||||
|
@ -82,16 +74,12 @@ export class TemplateView<T extends IObservableValue> extends BaseUpdateView<T>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract render(t: Builder<T>, value: T): ViewNode;
|
||||||
|
|
||||||
mount(options?: IMountArgs): ViewNode {
|
mount(options?: IMountArgs): ViewNode {
|
||||||
const builder = new TemplateBuilder(this) as Builder<T>;
|
const builder = new TemplateBuilder(this) as Builder<T>;
|
||||||
try {
|
try {
|
||||||
if (this._render) {
|
this._root = this.render(builder, this._value);
|
||||||
this._root = this._render(builder, this._value);
|
|
||||||
} else if (this["render"]) { // overriden in subclass
|
|
||||||
this._root = this["render"](builder, this._value);
|
|
||||||
} else {
|
|
||||||
throw new Error("no render function passed in, or overriden in subclass");
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
builder.close();
|
builder.close();
|
||||||
}
|
}
|
||||||
|
@ -344,7 +332,7 @@ export class TemplateBuilder<T extends IObservableValue> {
|
||||||
// on mappedValue, use `if` or `mapView`
|
// on mappedValue, use `if` or `mapView`
|
||||||
map<R>(mapFn: (value: T) => R, renderFn: (mapped: R, t: Builder<T>, vm: T) => ViewNode): ViewNode {
|
map<R>(mapFn: (value: T) => R, renderFn: (mapped: R, t: Builder<T>, vm: T) => ViewNode): ViewNode {
|
||||||
return this.mapView(mapFn, mappedValue => {
|
return this.mapView(mapFn, mappedValue => {
|
||||||
return new TemplateView(this._value, (t, vm) => {
|
return new InlineTemplateView(this._value, (t, vm) => {
|
||||||
const rootNode = renderFn(mappedValue, t, vm);
|
const rootNode = renderFn(mappedValue, t, vm);
|
||||||
if (!rootNode) {
|
if (!rootNode) {
|
||||||
// TODO: this will confuse mapView which assumes that
|
// TODO: this will confuse mapView which assumes that
|
||||||
|
@ -366,7 +354,7 @@ export class TemplateBuilder<T extends IObservableValue> {
|
||||||
// creates a conditional subtemplate
|
// creates a conditional subtemplate
|
||||||
// use mapView if you need to map to a different view class
|
// use mapView if you need to map to a different view class
|
||||||
if(predicate: (value: T) => boolean, renderFn: (t: Builder<T>, vm: T) => ViewNode) {
|
if(predicate: (value: T) => boolean, renderFn: (t: Builder<T>, vm: T) => ViewNode) {
|
||||||
return this.ifView(predicate, vm => new TemplateView(vm, renderFn));
|
return this.ifView(predicate, vm => new InlineTemplateView(vm, renderFn));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** You probably are looking for something else, like map or mapView.
|
/** You probably are looking for something else, like map or mapView.
|
||||||
|
@ -398,3 +386,16 @@ for (const [ns, tags] of Object.entries(TAG_NAMES)) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class InlineTemplateView<T> extends TemplateView<T> {
|
||||||
|
private _render: RenderFn<T>;
|
||||||
|
|
||||||
|
constructor(value: T, render: RenderFn<T>) {
|
||||||
|
super(value);
|
||||||
|
this._render = render;
|
||||||
|
}
|
||||||
|
|
||||||
|
override render(t: Builder<T>, value: T): ViewNode {
|
||||||
|
return this._render(t, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,16 +14,16 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {TemplateView} from "../../general/TemplateView";
|
import {TemplateView, InlineTemplateView} from "../../general/TemplateView";
|
||||||
import {StaticView} from "../../general/StaticView.js";
|
import {StaticView} from "../../general/StaticView.js";
|
||||||
|
|
||||||
export class SessionBackupSettingsView extends TemplateView {
|
export class SessionBackupSettingsView extends TemplateView {
|
||||||
render(t, vm) {
|
render(t, vm) {
|
||||||
return t.mapView(vm => vm.status, status => {
|
return t.mapView(vm => vm.status, status => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "Enabled": return new TemplateView(vm, renderEnabled)
|
case "Enabled": return new InlineTemplateView(vm, renderEnabled)
|
||||||
case "SetupKey": return new TemplateView(vm, renderEnableFromKey)
|
case "SetupKey": return new InlineTemplateView(vm, renderEnableFromKey)
|
||||||
case "SetupPhrase": return new TemplateView(vm, renderEnableFromPhrase)
|
case "SetupPhrase": return new InlineTemplateView(vm, renderEnableFromPhrase)
|
||||||
case "Pending": return new StaticView(vm, t => t.p(vm.i18n`Waiting to go online…`))
|
case "Pending": return new StaticView(vm, t => t.p(vm.i18n`Waiting to go online…`))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue