Skip to content

Commit

Permalink
fix: datacontext propagation
Browse files Browse the repository at this point in the history
  • Loading branch information
npenin committed Sep 10, 2024
1 parent 2b5e54b commit f037550
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 20 deletions.
21 changes: 9 additions & 12 deletions packages/client/src/behaviors/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Binding, ObservableObject, Parser, Subscription, each } from "@akala/co
import { IScope } from "../scope.js";
import { Composer } from "../template.js";
import { AttributeComposer } from "./shared.js";
import { CallExpression, ConstantExpression, MemberExpression, NewExpression } from "@akala/core/expressions";
import { ConstantExpression, MemberExpression, NewExpression } from "@akala/core/expressions";
// import { MemberExpression, NewExpression } from "@akala/core/expressions";

type Scope = IScope<object>;
Expand All @@ -11,24 +11,24 @@ export type IDataContext<TController extends Partial<Disposable> = Partial<Dispo

export class DataContext implements Composer<IDataContext>
{
static propagateProperties: string[] = ['controller'];
static readonly propagateProperties: string[] = ['controller'];

static define(item: HTMLElement, context: Record<string, unknown>): void
{
item.setAttribute('data-context', '');
if (item['dataContext'])
if (!item['dataContext'])
item['dataContext'] = DataContext.extend(DataContext.find(item), context)
item.setAttribute('data-context', '');

}
static extend(sourceContext: Binding<IDataContext>, options: Record<string, unknown>, newContextPath?: string): Binding<IDataContext>
{
return sourceContext.pipe(new CallExpression(new ConstantExpression(Object), new ConstantExpression('assign'), [new NewExpression<{ context: any, controller: Partial<Disposable> }>(
return sourceContext.pipe(new NewExpression<{ context: any, controller: Partial<Disposable> }>(
...Object.entries(options).filter(e => e[0] !== 'context').map(e =>
new MemberExpression<any, any, any>(new ConstantExpression(e[1]), new ConstantExpression(e[0]), false)),
...DataContext.propagateProperties.map(e =>
...DataContext.propagateProperties.filter(p => !(p in options)).map(e =>
new MemberExpression<any, any, any>(new MemberExpression(null, new ConstantExpression(e), false), new ConstantExpression(e), false)),
new MemberExpression(Parser.parameterLess.parse(newContextPath || 'context') as any, new ConstantExpression('context'), false),
), new MemberExpression(null, null, false)]));
));
}

private static readonly dataContextExpression = Parser.parameterLess.parse('dataContext');
Expand All @@ -39,7 +39,7 @@ export class DataContext implements Composer<IDataContext>

optionGetter(options: object): { context: Scope; controller: Partial<Disposable>; }
{
return { context: options['$rootScope'], controller: options['controller'] };
return { context: options['$rootScope'], controller: options['controller'], ...options };
}

apply(item: HTMLElement, options?: { context: Scope, controller: Partial<Disposable> }, root?: HTMLElement | ShadowRoot): Disposable
Expand Down Expand Up @@ -118,10 +118,7 @@ export class DataBind<T extends Partial<Disposable>> extends AttributeComposer<T

getContext(item: HTMLElement, options?: T)
{
return new Binding(DataContext.find(item), new NewExpression<{ context: any, controller: T }>(
new MemberExpression(new MemberExpression(undefined, new ConstantExpression('context'), false), new ConstantExpression('context'), false),
new MemberExpression(new ConstantExpression(options) as any, new ConstantExpression('controller'), false),
));
return DataContext.find(item);
}

optionName = 'controller';
Expand Down
12 changes: 9 additions & 3 deletions packages/client/src/behaviors/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ export interface WebComponent
attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
}

export function webComponent(tagName: string)


export function webComponent(tagName: string, options?: ElementDefinitionOptions)
{
return function <T extends Partial<WebComponent>>(target: (new (element: HTMLElement) => T) & { observedAttributes?: string[] })
{
customElements.define(tagName, class extends HTMLElement
let parent = HTMLElement;
if (options?.extends)
parent = window[Object.getPrototypeOf(document.createElement(options.extends)).constructor.name] as any;

customElements.define(tagName, class extends parent
{
control: T;
constructor()
Expand Down Expand Up @@ -54,7 +60,7 @@ export function webComponent(tagName: string)

static readonly observedAttributes = target.observedAttributes;

});
}, options);
}
}
export function wcObserve(name: string)
Expand Down
31 changes: 26 additions & 5 deletions packages/client/src/controlsv2/each.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { DataContext } from "../common.js";
export class Each extends Control
{
each: Binding<unknown>;
template: Element;
template: Node;

get indexPropertyName()
{
Expand All @@ -15,7 +15,7 @@ export class Each extends Control

get valuePropertyName()
{
return this.element.getAttribute('value-property-name') || 'item';
return this.element.getAttribute('item-property-name') || 'item';
}

private options: {}[] = []
Expand All @@ -26,12 +26,19 @@ export class Each extends Control
if (this.element.childElementCount > 1)
throw new Error('Each control can only have one child element');
this.template = this.element.firstElementChild;
this.template.setAttribute('data-context', '');
this.element.removeChild(this.template);
if (this.template instanceof HTMLTemplateElement)
{
this.template = this.template.content;
if (Array.from(this.template.childNodes).filter(c => c instanceof HTMLElement).length > 1)
throw new Error('Each control can only have one child element');
}
this.element.removeChild(this.element.firstElementChild);
let observableArraySubscription: Subscription;

this.each.onChanged(ev =>
{
if (ev.value === ev.oldValue)
return;
observableArraySubscription?.();
const observableArray = Array.isArray(ev.value) ? new ObservableArray(ev.value) : ev.value;
if (observableArray instanceof ObservableArray)
Expand Down Expand Up @@ -83,9 +90,23 @@ export class Each extends Control
// const options = { [this.indexPropertyName]: observableArray.length, [this.valuePropertyName]: arg.replacedItems[i] }
this.options[arg.replacedItems[i].index][this.valuePropertyName] = arg.replacedItems[i].newItem;
}
break;
case "init":
for (let i = 0; i < arg.newItems.length; i++)
{
const item = (this.template.cloneNode(true) as HTMLElement).firstElementChild as HTMLElement;
const options = {};
Binding.defineProperty(options, this.indexPropertyName, i);
Binding.defineProperty(options, this.valuePropertyName, arg.newItems[i]);
this.options.push(options);
this.element.appendChild(item);
DataContext.define(item, options);
this.teardown(Template.composeAll([item], this.element, options));
}
break;
}
}))
}));
observableArray.init();
}
}, true)
}
Expand Down

0 comments on commit f037550

Please sign in to comment.