Skip to content

Commit

Permalink
feat(component): enable $children property
Browse files Browse the repository at this point in the history
  • Loading branch information
EisenbergEffect committed May 8, 2018
1 parent 3927f90 commit 750f984
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 18 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ An experimental re-working of Aurelia, oriented around compile-time reflection a
* [x] Native ShadowDOM
* [x] HTML-Only Custom Elements
* [x] Template Part Replacement
* [x] `$children` and `$childrenChanged`
* [ ] Basic CSS
* [ ] CSS Modules

Expand Down
79 changes: 73 additions & 6 deletions scripts/app-bundle.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion scripts/app-bundle.js.map

Large diffs are not rendered by default.

104 changes: 93 additions & 11 deletions src/runtime/templating/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ import { IEmulatedShadowSlot, ShadowDOMEmulation } from "./shadow-dom";
import { PLATFORM } from "../platform";
import { IContainer, Registration } from "../di";
import { BindingMode } from "../binding/binding-mode";
import { Constructable } from "../interfaces";
import { IBindScope } from "../binding/observation";
import { Constructable, ICallable } from "../interfaces";
import { IBindScope, IAccessor, ISubscribable } from "../binding/observation";
import { IScope, BindingContext } from "../binding/binding-context";
import { IRenderSlot } from "./render-slot";
import { IBindSelf, IAttach, AttachContext, DetachContext } from "./lifecycle";
import { ICompiledViewSource, IBindableInstruction } from "./instructions";
import { INode, DOM, IView } from "../dom";
import { INode, DOM, IView, IChildObserver } from "../dom";
import { SubscriberCollection } from "../binding/subscriber-collection";

export interface IElementComponent extends IBindSelf, IAttach, IViewOwner {
$host: INode;
$view: IView;
$contentView: IContentView;
$slots: Record<string, IEmulatedShadowSlot>;
Expand Down Expand Up @@ -60,6 +62,20 @@ export interface BindingBehaviorType extends Constructable {
}

export const Component = {
findElements(nodes: ArrayLike<INode>): IElementComponent[] {
let components: IElementComponent[] = [];

for (let i = 0, ii = nodes.length; i < ii; ++i) {
const current = nodes[i];
const component = DOM.getComponentForNode(current);

if (component !== null) {
components.push(component);
}
}

return components;
},
valueConverter<T extends Constructable>(nameOrSource: string | IValueConverterSource, ctor: T): T & ValueConverterType {
const source = (<any>ctor).source = ensureSource<IValueConverterSource>(nameOrSource);

Expand Down Expand Up @@ -108,7 +124,7 @@ export const Component = {
constructor(...args:any[]) {
super(...args);

RuntimeBehavior.get(this, observables, CustomAttribute).applyTo(this);
RuntimeBehavior.get(this, observables, CustomAttribute).applyToAttribute(this);

if (this.$behavior.hasCreated) {
(<any>this).created();
Expand Down Expand Up @@ -226,14 +242,14 @@ export const Component = {
overrideContext: BindingContext.createOverride()
};

private $host: INode = null;
$host: INode = null;
private $shadowRoot: INode = null;
private $changeCallbacks: (() => void)[] = [];
private $behavior: RuntimeBehavior = null;

constructor(...args:any[]) {
super(...args);
RuntimeBehavior.get(this, observables, CompiledComponent).applyTo(this);
RuntimeBehavior.get(this, observables, CompiledComponent).applyToElement(this);
}

$hydrate(host: INode, replacements: Record<string, ICompiledViewSource> = PLATFORM.emptyObject, contentOverride?: INode) {
Expand Down Expand Up @@ -454,7 +470,24 @@ class RuntimeBehavior {
return behavior;
}

applyTo(instance) {
applyToAttribute(instance: IAttributeComponent) {
this.applyTo(instance);
}

applyToElement(instance: IElementComponent) {
const observers = this.applyTo(instance);

(<any>observers).$children = new ChildrenObserver(instance);

Reflect.defineProperty(instance, '$children', {
enumerable: false,
get: function() {
return this.$observers.$children.getValue();
}
});
}

private applyTo(instance) {
const observers = {};
const finalObservables = this.observables;
const observableNames = Object.getOwnPropertyNames(finalObservables);
Expand All @@ -474,19 +507,68 @@ class RuntimeBehavior {
createGetterSetter(instance, name);
}

instance.$behavior = this;

Object.defineProperty(instance, '$observers', {
Reflect.defineProperty(instance, '$observers', {
enumerable: false,
value: observers
});

instance.$behavior = this;

return observers;
}
}

function createGetterSetter(instance, name) {
Object.defineProperty(instance, name, {
Reflect.defineProperty(instance, name, {
enumerable: true,
get: function() { return this.$observers[name].getValue(); },
set: function(value) { this.$observers[name].setValue(value); }
});
}

export class ChildrenObserver extends SubscriberCollection implements IAccessor, ISubscribable, ICallable {
private observer: IChildObserver = null;
private children: IElementComponent[] = null;
private queued = false;

constructor(private component: IElementComponent) {
super();
}

getValue(): IElementComponent[] {
if (this.observer === null) {
this.observer = DOM.createChildObserver(this.component.$host, () => this.onChildrenChanged());
this.children = Component.findElements(this.observer.childNodes);
}

return this.children;
}

setValue(newValue) {}

private onChildrenChanged() {
this.children = Component.findElements(this.observer.childNodes);

if ('$childrenChanged' in this.component) {
(<any>this.component).$childrenChanged();
}

if (!this.queued) {
this.queued = true;
TaskQueue.queueMicroTask(this);
}
}

call() {
this.queued = false;
this.callSubscribers(this.children);
}

subscribe(context: string, callable: ICallable) {
this.addSubscriber(context, callable);
}

unsubscribe(context: string, callable: ICallable) {
this.removeSubscriber(context, callable);
}
}

0 comments on commit 750f984

Please sign in to comment.