Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@aurelia/runtime

Package Overview
Dependencies
Maintainers
1
Versions
1117
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@aurelia/runtime - npm Package Compare versions

Comparing version 0.2.0-dev.20180927 to 0.2.0-dev.20180928

dist/templating/resources/composition-coordinator.d.ts

1

dist/dom.d.ts

@@ -75,4 +75,3 @@ import { IContainer, IResolver } from '@aurelia/kernel';

empty: INodeSequence;
fromNode(node: INode): INodeSequence;
};
//# sourceMappingURL=dom.d.ts.map

@@ -1,2 +0,2 @@

import { Constructable, Omit, Immutable } from '@aurelia/kernel';
import { Constructable, Immutable, Omit } from '@aurelia/kernel';
import { IScope } from '../binding/binding-context';

@@ -3,0 +3,0 @@ import { BindingMode } from '../binding/binding-mode';

import { Constructable, Immutable } from '@aurelia/kernel';
import { BindingFlags } from '../binding/binding-flags';
import { INode, INodeSequence, IRenderLocation } from '../dom';
import { IResourceKind, IResourceType } from '../resource';
import { IHydrateElementInstruction, ITemplateSource, TemplateDefinition } from './instructions';
import { IAttach, IBindSelf } from './lifecycle';
import { IAttach } from './lifecycle';
import { IRenderable } from './renderable';

@@ -11,4 +12,9 @@ import { IRenderingEngine } from './rendering-engine';

export declare type IElementHydrationOptions = Immutable<Pick<IHydrateElementInstruction, 'parts'>>;
export interface IBindSelf {
readonly $isBound: boolean;
$bind(flags: BindingFlags): void;
$unbind(flags: BindingFlags): void;
}
export interface ICustomElement extends IBindSelf, IAttach, Readonly<IRenderable> {
readonly $projector: IViewProjector;
readonly $projector: IElementProjector;
$hydrate(renderingEngine: IRenderingEngine, host: INode, options?: IElementHydrationOptions): void;

@@ -35,10 +41,10 @@ }

export declare const CustomElementResource: ICustomElementResource;
export interface IViewProjector {
export interface IElementProjector {
readonly host: INode;
readonly children: ArrayLike<INode>;
onChildrenChanged(callback: () => void): void;
provideEncapsulationSource(parentEncapsulationSource: INode): INode;
project(nodes: INodeSequence): void;
subscribeToChildrenChange(callback: () => void): void;
}
export declare class ShadowDOMProjector implements IViewProjector {
export declare class ShadowDOMProjector implements IElementProjector {
host: INode;

@@ -48,23 +54,28 @@ shadowRoot: INode;

readonly children: ArrayLike<INode>;
onChildrenChanged(callback: () => void): void;
subscribeToChildrenChange(callback: () => void): void;
provideEncapsulationSource(parentEncapsulationSource: INode): INode;
project(nodes: INodeSequence): void;
onElementRemoved(): void;
}
export declare class ContainerlessProjector implements IViewProjector {
export declare class ContainerlessProjector implements IElementProjector {
private customElement;
host: IRenderLocation;
private childNodes;
private requiresMount;
constructor(customElement: ICustomElement, host: INode);
readonly children: ArrayLike<INode>;
onChildrenChanged(callback: () => void): void;
subscribeToChildrenChange(callback: () => void): void;
provideEncapsulationSource(parentEncapsulationSource: INode): INode;
project(nodes: INodeSequence): void;
onElementRemoved(): void;
}
export declare class HostProjector implements IViewProjector {
export declare class HostProjector implements IElementProjector {
host: INode;
constructor(customElement: ICustomElement, host: INode);
readonly children: ArrayLike<INode>;
onChildrenChanged(callback: () => void): void;
subscribeToChildrenChange(callback: () => void): void;
provideEncapsulationSource(parentEncapsulationSource: INode): INode;
project(nodes: INodeSequence): void;
onElementRemoved(): void;
}
//# sourceMappingURL=custom-element.d.ts.map
export * from './resources';
export * from './animator';
export * from './bindable';

@@ -4,0 +3,0 @@ export * from './custom-attribute';

@@ -1,41 +0,73 @@

import { BindingFlags } from '../binding/binding-flags';
import { INode } from '../dom';
import { IRenderable } from './renderable';
export declare class AttachLifecycle {
private owner;
private tail;
private head;
private $nextAttached;
private constructor();
static start(owner: any, existingLifecycle?: AttachLifecycle): AttachLifecycle;
queueAttachedCallback(requestor: IAttach): void;
end(owner: any): void;
private attached;
export declare enum LifecycleFlags {
none = 1,
noTasks = 2,
unbindAfterDetached = 4
}
export declare class DetachLifecycle {
private owner;
private detachedHead;
private detachedTail;
private viewRemoveHead;
private viewRemoveTail;
private $nextDetached;
private $nextRemoveView;
private $nodes;
private constructor();
static start(owner: any, existingLifecycle?: DetachLifecycle): DetachLifecycle;
queueViewRemoval(requestor: IRenderable): void;
queueDetachedCallback(requestor: IAttach): void;
end(owner: any): void;
private detached;
}
export interface IAttach {
readonly $isAttached: boolean;
$attach(encapsulationSource: INode, lifecycle?: AttachLifecycle): void;
$detach(lifecycle?: DetachLifecycle): void;
$attach(encapsulationSource: INode, lifecycle: IAttachLifecycle): void;
$detach(lifecycle: IDetachLifecycle): void;
$cache(): void;
}
export interface IBindSelf {
readonly $isBound: boolean;
$bind(flags: BindingFlags): void;
$unbind(flags: BindingFlags): void;
export interface ILifecycleTask {
readonly done: boolean;
canCancel(): boolean;
cancel(): void;
wait(): Promise<void>;
}
export interface IAttachLifecycleController {
attach(requestor: IAttach): IAttachLifecycleController;
end(): ILifecycleTask;
}
declare type LifecycleAttachable = {
attached(): void;
};
declare type LifecycleNodeAddable = Pick<IRenderable, '$addNodes'> & {};
export interface IAttachLifecycle {
readonly flags: LifecycleFlags;
registerTask(task: ILifecycleTask): void;
createChild(): IAttachLifecycle;
queueAddNodes(requestor: LifecycleNodeAddable): void;
queueAttachedCallback(requestor: LifecycleAttachable): void;
}
export interface IDetachLifecycleController {
detach(requestor: IAttach): IDetachLifecycleController;
end(): ILifecycleTask;
}
declare type LifecycleDetachable = {
detached(): void;
};
declare type LifecycleNodeRemovable = Pick<IRenderable, '$removeNodes'> & {};
export declare class AggregateLifecycleTask implements ILifecycleTask {
done: boolean;
private tasks;
private waiter;
private resolve;
addTask(task: ILifecycleTask): void;
canCancel(): boolean;
cancel(): void;
wait(): Promise<void>;
private tryComplete;
private complete;
}
export interface IDetachLifecycle {
readonly flags: LifecycleFlags;
registerTask(task: ILifecycleTask): void;
createChild(): IDetachLifecycle;
queueRemoveNodes(requestor: LifecycleNodeRemovable): void;
queueDetachedCallback(requestor: LifecycleDetachable): void;
}
export declare const Lifecycle: {
beginAttach(encapsulationSource: INode, flags: LifecycleFlags): IAttachLifecycleController;
beginDetach(flags: LifecycleFlags): IDetachLifecycleController;
done: {
done: boolean;
canCancel(): boolean;
cancel(): void;
wait(): Promise<void>;
};
};
export {};
//# sourceMappingURL=lifecycle.d.ts.map
import { IScope } from '../binding/binding-context';
import { BindingFlags } from '../binding/binding-flags';
import { IBindScope } from '../binding/observation';

@@ -16,5 +15,5 @@ import { INodeSequence } from '../dom';

readonly $attachables: IAttach[];
$addChild(child: IAttach | IBindScope, flags: BindingFlags): void;
$removeChild(child: IAttach | IBindScope): void;
$addNodes(): void;
$removeNodes(): void;
}
//# sourceMappingURL=renderable.d.ts.map

@@ -6,3 +6,2 @@ import { IContainer, Immutable } from '@aurelia/kernel';

import { IObserverLocator } from '../binding/observer-locator';
import { IAnimator } from './animator';
import { ICustomAttribute, ICustomAttributeType } from './custom-attribute';

@@ -30,3 +29,2 @@ import { ICustomElement, ICustomElementType } from './custom-element';

private parser;
private animator;
private templateLookup;

@@ -36,3 +34,3 @@ private factoryLookup;

private compilers;
constructor(container: IContainer, changeSet: IChangeSet, observerLocator: IObserverLocator, eventManager: IEventManager, parser: IExpressionParser, animator: IAnimator, templateCompilers: ITemplateCompiler[]);
constructor(container: IContainer, changeSet: IChangeSet, observerLocator: IObserverLocator, eventManager: IEventManager, parser: IExpressionParser, templateCompilers: ITemplateCompiler[]);
getElementTemplate(definition: TemplateDefinition, componentType?: ICustomElementType): ITemplate;

@@ -39,0 +37,0 @@ getViewFactory(definition: Immutable<ITemplateSource>, parentContext?: IRenderContext): IViewFactory;

@@ -1,6 +0,12 @@

import { Immutable } from '@aurelia/kernel';
import { Constructable, Immutable } from '@aurelia/kernel';
import { BindingFlags } from '../../binding/binding-flags';
import { INode } from '../../dom';
import { PotentialRenderable } from '../create-element';
import { ICustomElement } from '../custom-element';
import { IHydrateElementInstruction } from '../instructions';
import { IHydrateElementInstruction, TemplateDefinition } from '../instructions';
import { IAttachLifecycle, IDetachLifecycle } from '../lifecycle';
import { IRenderable } from '../renderable';
import { IRenderingEngine } from '../rendering-engine';
import { IView, IViewFactory } from '../view';
declare type Subject = IViewFactory | IView | PotentialRenderable | Constructable | TemplateDefinition;
export interface Compose extends ICustomElement {

@@ -11,12 +17,19 @@ }

private renderingEngine;
subject: any;
subject: Subject | Promise<Subject>;
composing: boolean;
private task;
private currentView;
private properties;
private coordinator;
private lastSubject;
constructor(renderable: IRenderable, instruction: Immutable<IHydrateElementInstruction>, renderingEngine: IRenderingEngine);
binding(flags: BindingFlags): void;
attaching(encapsulationSource: INode, lifecycle: IAttachLifecycle): void;
detaching(lifecycle: IDetachLifecycle): void;
unbinding(flags: BindingFlags): void;
caching(): void;
subjectChanged(newValue: any): void;
private startComposition;
private resolveView;
private provideViewFor;
private startComposition;
private clear;
}
export {};
//# sourceMappingURL=compose.d.ts.map

@@ -0,3 +1,5 @@

import { BindingFlags } from '../../binding/binding-flags';
import { INode, IRenderLocation } from '../../dom';
import { ICustomAttribute } from '../custom-attribute';
import { IAttachLifecycle, IDetachLifecycle } from '../lifecycle';
import { IViewFactory } from '../view';

@@ -13,13 +15,12 @@ export interface If extends ICustomAttribute {

private elseView;
private $child;
private encapsulationSource;
private coordinator;
constructor(ifFactory: IViewFactory, location: IRenderLocation);
bound(): void;
attaching(encapsulationSource: INode): void;
unbound(): void;
valueChanged(newValue: any): void;
private update;
private activateBranch;
private ensureViewCreated;
private deactivateCurrentBranch;
binding(flags: BindingFlags): void;
attaching(encapsulationSource: INode, lifecycle: IAttachLifecycle): void;
detaching(lifecycle: IDetachLifecycle): void;
unbinding(flags: BindingFlags): void;
caching(): void;
valueChanged(): void;
private updateView;
private ensureView;
}

@@ -26,0 +27,0 @@ export declare class Else {

@@ -10,3 +10,3 @@ import { IContainer, Immutable } from '@aurelia/kernel';

import { ICustomAttribute, ICustomAttributeSource } from '../custom-attribute';
import { AttachLifecycle, DetachLifecycle } from '../lifecycle';
import { IAttachLifecycle, IDetachLifecycle } from '../lifecycle';
import { IRenderable } from '../renderable';

@@ -46,5 +46,6 @@ import { IRenderingEngine } from '../rendering-engine';

$bind(flags: BindingFlags, scope: IScope): void;
$attach(encapsulationSource: INode, lifecycle: AttachLifecycle): void;
$detach(lifecycle: DetachLifecycle): void;
$attach(encapsulationSource: INode, lifecycle: IAttachLifecycle): void;
$detach(lifecycle: IDetachLifecycle): void;
$unbind(flags: BindingFlags): void;
$cache(): void;
flushChanges(): void;

@@ -51,0 +52,0 @@ handleBatchedChange(indexMap?: number[]): void;

@@ -1,5 +0,5 @@

import { IScope } from '../../binding/binding-context';
import { BindingFlags } from '../../binding/binding-flags';
import { IRenderLocation } from '../../dom';
import { ICustomAttribute } from '../custom-attribute';
import { IAttachLifecycle, IDetachLifecycle } from '../lifecycle';
import { IViewFactory } from '../view';

@@ -10,7 +10,9 @@ export interface Replaceable extends ICustomAttribute {

private factory;
private $child;
private currentView;
constructor(factory: IViewFactory, location: IRenderLocation);
bound(flags: BindingFlags, scope: IScope): void;
unbound(flags: BindingFlags): void;
binding(flags: BindingFlags): void;
attaching(encapsulationSource: any, lifecycle: IAttachLifecycle): void;
detaching(lifecycle: IDetachLifecycle): void;
unbinding(flags: BindingFlags): void;
}
//# sourceMappingURL=replaceable.d.ts.map
import { BindingFlags } from '../../binding/binding-flags';
import { IRenderLocation } from '../../dom';
import { ICustomAttribute } from '../custom-attribute';
import { IAttachLifecycle, IDetachLifecycle } from '../lifecycle';
import { IViewFactory } from '../view';

@@ -10,9 +11,11 @@ export interface With extends ICustomAttribute {

value: any;
private $child;
private currentView;
constructor(factory: IViewFactory, location: IRenderLocation);
valueChanged(): void;
bound(flags: BindingFlags): void;
unbound(flags: BindingFlags): void;
binding(flags: BindingFlags): void;
attaching(encapsulationSource: any, lifecycle: IAttachLifecycle): void;
detaching(lifecycle: IDetachLifecycle): void;
unbinding(flags: BindingFlags): void;
private bindChild;
}
//# sourceMappingURL=with.d.ts.map
import { IAccessor, ISubscribable, ISubscriberCollection, MutationKind } from '../binding/observation';
export interface IRuntimeBehavior {
readonly hasCreated: boolean;
readonly hasBinding: boolean;
readonly hasBound: boolean;

@@ -9,4 +10,6 @@ readonly hasAttaching: boolean;

readonly hasDetached: boolean;
readonly hasUnbinding: boolean;
readonly hasUnbound: boolean;
readonly hasRender: boolean;
readonly hasCaching: boolean;
}

@@ -13,0 +16,0 @@ export interface IChildrenObserver extends IAccessor, ISubscribable<MutationKind.instance>, ISubscriberCollection<MutationKind.instance> {

import { IScope } from '../binding/binding-context';
import { IBindScope } from '../binding/observation';
import { IRenderLocation } from '../dom';
import { IAttach } from './lifecycle';

@@ -8,6 +9,5 @@ import { IRenderable } from './renderable';

readonly factory: IViewFactory;
onRender: RenderCallback;
renderState: any;
mount(location: IRenderLocation): void;
release(): boolean;
lockScope(scope: IScope): void;
tryReturnToCache(): boolean;
}

@@ -14,0 +14,0 @@ export interface IViewFactory {

{
"name": "@aurelia/runtime",
"version": "0.2.0-dev.20180927",
"version": "0.2.0-dev.20180928",
"main": "dist/index.umd.js",

@@ -46,3 +46,3 @@ "module": "dist/index.es6.js",

"dependencies": {
"@aurelia/kernel": "0.2.0-dev.20180927"
"@aurelia/kernel": "0.2.0-dev.20180928"
},

@@ -88,3 +88,3 @@ "devDependencies": {

},
"gitHead": "9eb0764711f930d4b5ff930bffac2501508b8d5e"
"gitHead": "48c41516655c2d1b9d9822d4fa2732a47c0b0f36"
}
import { DI, IContainer, IRegistry, PLATFORM } from '@aurelia/kernel';
import { BindingFlags } from './binding/binding-flags';
import { Lifecycle, LifecycleFlags } from './templating';
import { ICustomElement } from './templating/custom-element';

@@ -15,7 +16,7 @@ import { IRenderingEngine } from './templating/rendering-engine';

private stopTasks: (() => void)[] = [];
private isStarted = false;
private isStarted: boolean = false;
constructor(private container: IContainer = DI.createContainer()) {}
public register(...params: (IRegistry | Record<string, Partial<IRegistry>>)[]) {
public register(...params: (IRegistry | Record<string, Partial<IRegistry>>)[]): this {
this.container.register(...params);

@@ -25,5 +26,6 @@ return this;

public app(config: ISinglePageApp) {
let component: ICustomElement = config.component;
let startTask = () => {
public app(config: ISinglePageApp): this {
const component: ICustomElement = config.component;
const startTask = () => {
if (!this.components.includes(component)) {

@@ -38,3 +40,6 @@ this.components.push(component);

component.$bind(BindingFlags.fromStartTask | BindingFlags.fromBind);
component.$attach(config.host);
Lifecycle.beginAttach(config.host, LifecycleFlags.none)
.attach(component)
.end();
};

@@ -45,4 +50,13 @@

this.stopTasks.push(() => {
component.$detach();
component.$unbind(BindingFlags.fromStopTask | BindingFlags.fromUnbind);
const task = Lifecycle.beginDetach(LifecycleFlags.noTasks)
.detach(component)
.end();
const flags = BindingFlags.fromStopTask | BindingFlags.fromUnbind;
if (task.done) {
component.$unbind(flags);
} else {
task.wait().then(() => component.$unbind(flags));
}
});

@@ -57,3 +71,3 @@

public start() {
public start(): this {
this.startTasks.forEach(x => x());

@@ -64,3 +78,3 @@ this.isStarted = true;

public stop() {
public stop(): this {
this.isStarted = false;

@@ -67,0 +81,0 @@ this.stopTasks.forEach(x => x());

@@ -235,3 +235,3 @@ import { DI, IContainer, IResolver, PLATFORM } from '@aurelia/kernel';

}
}
};

@@ -252,31 +252,3 @@ // This is an implementation of INodeSequence that represents "no DOM" to render.

export const NodeSequence = {
empty: emptySequence,
// This creates an instance of INodeSequence based on an existing INode.
// It's used by the rendering engine to create an instance of IView,
// based on a single component. The rendering engine's createViewFromComponent
// method has one consumer: the compose element. The compose element uses this
// to create an IView based on a dynamically determined component instance.
// This is required because there's no way to get a "loose" component into the view
// hierarchy without it being part of an IView.
// IViews can only be added via an IViewSlot or IRenderLocation.
// So, this form of node sequence effectively enables a single component to be added into an IViewSlot.
fromNode(node: INode): INodeSequence {
return {
firstChild: node,
lastChild: node,
childNodes: [node],
findTargets(): ReadonlyArray<INode> {
return PLATFORM.emptyArray;
},
insertBefore(refNode: INode): void {
DOM.insertBefore(node, refNode);
},
appendTo(parent: INode): void {
DOM.appendChild(parent, node);
},
remove(): void {
DOM.remove(node);
}
};
}
empty: emptySequence
};

@@ -291,8 +263,8 @@

export class FragmentNodeSequence implements INodeSequence {
public firstChild: Node;
public lastChild: Node;
public childNodes: Node[];
private fragment: DocumentFragment;
firstChild: Node;
lastChild: Node;
childNodes: Node[];
constructor(fragment: DocumentFragment) {

@@ -305,33 +277,36 @@ this.fragment = fragment;

findTargets(): ArrayLike<Node> {
public findTargets(): ArrayLike<Node> {
return this.fragment.querySelectorAll('.au');
}
insertBefore(refNode: Node): void {
public insertBefore(refNode: Node): void {
refNode.parentNode.insertBefore(this.fragment, refNode);
}
appendTo(parent: Node): void {
public appendTo(parent: Node): void {
parent.appendChild(this.fragment);
}
remove(): void {
public remove(): void {
const fragment = this.fragment;
// this bind is a small perf tweak to minimize member accessors
const append = fragment.appendChild.bind(fragment);
let current = this.firstChild;
const end = this.lastChild;
let next: Node;
while (current) {
next = current.nextSibling;
append(current);
if (current.parentNode !== fragment) {
// this bind is a small perf tweak to minimize member accessors
const append = fragment.appendChild.bind(fragment);
const end = this.lastChild;
let next: Node;
if (current === end) {
break;
while (current) {
next = current.nextSibling;
append(current);
if (current === end) {
break;
}
current = next;
}
current = next;
}
}
}
import {
Constructable,
IContainer,
Immutable,
Omit,
PLATFORM,
Registration,
Writable,
Immutable
Writable
} from '@aurelia/kernel';

@@ -17,3 +17,3 @@ import { IScope } from '../binding/binding-context';

import { IBindableDescription } from './bindable';
import { AttachLifecycle, DetachLifecycle, IAttach } from './lifecycle';
import { IAttach, IAttachLifecycle, IDetachLifecycle } from './lifecycle';
import { IRenderingEngine } from './rendering-engine';

@@ -42,3 +42,2 @@ import { IRuntimeBehavior } from './runtime-behavior';

$behavior: IRuntimeBehavior;
$child: IAttach;
}

@@ -106,2 +105,3 @@

proto.$unbind = unbind;
proto.$cache = cache;

@@ -128,3 +128,2 @@ return Type;

this.$scope = null;
this.$child = this.$child || null;

@@ -150,6 +149,12 @@ renderingEngine.applyRuntimeBehavior(

const behavior = this.$behavior;
this.$scope = scope;
if (behavior.hasBinding) {
(this as any).binding(flags | BindingFlags.fromBind);
}
this.$isBound = true;
if (this.$behavior.hasBound) {
if (behavior.hasBound) {
(this as any).bound(flags | BindingFlags.fromBind, scope);

@@ -161,2 +166,8 @@ }

if (this.$isBound) {
const behavior = this.$behavior;
if (behavior.hasUnbinding) {
(this as any).unbinding(flags | BindingFlags.fromUnbind);
}
this.$isBound = false;

@@ -170,3 +181,3 @@

function attach(this: IInternalCustomAttributeImplementation, encapsulationSource: INode, lifecycle: AttachLifecycle): void {
function attach(this: IInternalCustomAttributeImplementation, encapsulationSource: INode, lifecycle: IAttachLifecycle): void {
if (this.$isAttached) {

@@ -177,30 +188,22 @@ return;

if (this.$behavior.hasAttaching) {
(this as any).attaching(encapsulationSource);
(this as any).attaching(encapsulationSource, lifecycle);
}
if (this.$child !== null) {
this.$child.$attach(encapsulationSource, lifecycle);
}
this.$isAttached = true;
if (this.$behavior.hasAttached) {
lifecycle.queueAttachedCallback(this);
lifecycle.queueAttachedCallback(this as any);
}
}
function detach(this: IInternalCustomAttributeImplementation, lifecycle: DetachLifecycle): void {
function detach(this: IInternalCustomAttributeImplementation, lifecycle: IDetachLifecycle): void {
if (this.$isAttached) {
if (this.$behavior.hasDetaching) {
(this as any).detaching();
(this as any).detaching(lifecycle);
}
if (this.$child !== null) {
this.$child.$detach(lifecycle);
}
this.$isAttached = false;
if (this.$behavior.hasDetached) {
lifecycle.queueDetachedCallback(this);
lifecycle.queueDetachedCallback(this as any);
}

@@ -210,2 +213,8 @@ }

function cache(this: IInternalCustomAttributeImplementation): void {
if (this.$behavior.hasCaching) {
(this as any).caching();
}
}
/*@internal*/

@@ -212,0 +221,0 @@ export function createCustomAttributeDescription(attributeSource: ICustomAttributeSource, Type: ICustomAttributeType): ResourceDescription<ICustomAttributeSource> {

@@ -15,4 +15,4 @@ import {

import { IHydrateElementInstruction, ITemplateSource, TemplateDefinition } from './instructions';
import { AttachLifecycle, DetachLifecycle, IAttach, IBindSelf } from './lifecycle';
import { addRenderableChild, IRenderable, removeRenderableChild } from './renderable';
import { IAttach, IAttachLifecycle, IDetachLifecycle } from './lifecycle';
import { IRenderable } from './renderable';
import { IRenderingEngine } from './rendering-engine';

@@ -26,4 +26,10 @@ import { IRuntimeBehavior } from './runtime-behavior';

export interface IBindSelf {
readonly $isBound: boolean;
$bind(flags: BindingFlags): void;
$unbind(flags: BindingFlags): void;
}
export interface ICustomElement extends IBindSelf, IAttach, Readonly<IRenderable> {
readonly $projector: IViewProjector;
readonly $projector: IElementProjector;
$hydrate(renderingEngine: IRenderingEngine, host: INode, options?: IElementHydrationOptions): void;

@@ -58,10 +64,10 @@ }

export function useShadowDOM(targetOrOptions?): any {
let options = typeof targetOrOptions === 'function' || !targetOrOptions
const options = typeof targetOrOptions === 'function' || !targetOrOptions
? defaultShadowOptions
: targetOrOptions;
let deco = function<T extends Constructable>(target: T) {
(<any>target).shadowOptions = options;
const deco = function<T extends Constructable>(target: T): T {
(target as any).shadowOptions = options;
return target;
}
};

@@ -76,6 +82,6 @@ return typeof targetOrOptions === 'function' ? deco(targetOrOptions) : deco;

export function containerless(target?): any {
let deco = function<T extends Constructable>(target: T) {
(<any>target).containerless = true;
const deco = function<T extends Constructable>(target: T): T {
(target as any).containerless = true;
return target;
}
};

@@ -118,4 +124,5 @@ return target ? deco(target) : deco;

proto.$unbind = unbind;
(proto.$addChild as any) = addRenderableChild;
(proto.$removeChild as any) = removeRenderableChild;
proto.$cache = cache;
(proto.$addNodes as any) = addNodes;
(proto.$removeNodes as any) = removeNodes;

@@ -177,2 +184,8 @@ return Type;

const behavior = this.$behavior;
if (behavior.hasBinding) {
(this as any).binding(flags | BindingFlags.fromBind);
}
const scope = this.$scope;

@@ -187,3 +200,3 @@ const bindables = this.$bindables;

if (this.$behavior.hasBound) {
if (behavior.hasBound) {
(this as any).bound(flags | BindingFlags.fromBind);

@@ -195,2 +208,8 @@ }

if (this.$isBound) {
const behavior = this.$behavior;
if (behavior.hasUnbinding) {
(this as any).unbinding(flags | BindingFlags.fromUnbind);
}
const bindables = this.$bindables;

@@ -205,3 +224,3 @@ let i = bindables.length;

if (this.$behavior.hasUnbound) {
if (behavior.hasUnbound) {
(this as any).unbound(flags | BindingFlags.fromUnbind);

@@ -212,3 +231,3 @@ }

function attach(this: IInternalCustomElementImplementation, encapsulationSource: INode, lifecycle?: AttachLifecycle): void {
function attach(this: IInternalCustomElementImplementation, encapsulationSource: INode, lifecycle: IAttachLifecycle): void {
if (this.$isAttached) {

@@ -218,4 +237,2 @@ return;

lifecycle = AttachLifecycle.start(this, lifecycle);
this.$encapsulationSource = encapsulationSource

@@ -225,3 +242,3 @@ = this.$projector.provideEncapsulationSource(encapsulationSource);

if (this.$behavior.hasAttaching) {
(this as any).attaching(encapsulationSource);
(this as any).attaching(encapsulationSource, lifecycle);
}

@@ -235,22 +252,17 @@

this.$projector.project(this.$nodes);
lifecycle.queueAddNodes(this);
this.$isAttached = true;
if (this.$behavior.hasAttached) {
lifecycle.queueAttachedCallback(this);
lifecycle.queueAttachedCallback(this as any);
}
lifecycle.end(this);
}
function detach(this: IInternalCustomElementImplementation, lifecycle?: DetachLifecycle): void {
function detach(this: IInternalCustomElementImplementation, lifecycle: IDetachLifecycle): void {
if (this.$isAttached) {
lifecycle = DetachLifecycle.start(this, lifecycle);
if (this.$behavior.hasDetaching) {
(this as any).detaching();
(this as any).detaching(lifecycle);
}
lifecycle.queueViewRemoval(this);
lifecycle.queueRemoveNodes(this);

@@ -261,3 +273,3 @@ const attachables = this.$attachables;

while (i--) {
attachables[i].$detach();
attachables[i].$detach(lifecycle);
}

@@ -268,9 +280,28 @@

if (this.$behavior.hasDetached) {
lifecycle.queueDetachedCallback(this);
lifecycle.queueDetachedCallback(this as any);
}
}
}
lifecycle.end(this);
function cache(this: IInternalCustomElementImplementation): void {
if (this.$behavior.hasCaching) {
(this as any).caching();
}
const attachables = this.$attachables;
let i = attachables.length;
while (i--) {
attachables[i].$cache();
}
}
function addNodes(this: IInternalCustomElementImplementation): void {
this.$projector.project(this.$nodes);
}
function removeNodes(this: IInternalCustomElementImplementation): void {
this.$projector.onElementRemoved();
}
/*@internal*/

@@ -296,8 +327,13 @@ export function createCustomElementDescription(templateSource: ITemplateSource, Type: ICustomElementType): TemplateDefinition {

export interface IViewProjector {
export interface IElementProjector {
readonly host: INode;
readonly children: ArrayLike<INode>;
onChildrenChanged(callback: () => void): void;
provideEncapsulationSource(parentEncapsulationSource: INode): INode;
project(nodes: INodeSequence): void;
subscribeToChildrenChange(callback: () => void): void;
/*@internal*/
onElementRemoved(): void;
}

@@ -309,3 +345,3 @@

definition: TemplateDefinition
): IViewProjector {
): IElementProjector {
if (definition.shadowOptions || definition.hasSlots) {

@@ -328,3 +364,3 @@ if (definition.containerless) {

export class ShadowDOMProjector implements IViewProjector {
export class ShadowDOMProjector implements IElementProjector {
public shadowRoot: INode;

@@ -346,3 +382,3 @@

public onChildrenChanged(callback: () => void): void {
public subscribeToChildrenChange(callback: () => void): void {
DOM.createNodeObserver(this.host, callback, childObserverOptions);

@@ -356,11 +392,19 @@ }

public project(nodes: INodeSequence): void {
nodes.appendTo(this.shadowRoot);
nodes.appendTo(this.host);
this.project = PLATFORM.noop;
}
public onElementRemoved(): void {
// No special behavior is required because the host element removal
// will result in the projected nodes being removed, since they are in
// the ShadowDOM.
}
}
export class ContainerlessProjector implements IViewProjector {
export class ContainerlessProjector implements IElementProjector {
public host: IRenderLocation;
private childNodes: ArrayLike<INode>;
private requiresMount: boolean = true;
constructor(customElement: ICustomElement, host: INode) {
constructor(private customElement: ICustomElement, host: INode) {
if (host.childNodes.length) {

@@ -380,3 +424,3 @@ this.childNodes = Array.from(host.childNodes);

public onChildrenChanged(callback: () => void): void {
public subscribeToChildrenChange(callback: () => void): void {
// Do nothing since this scenario will never have children.

@@ -394,7 +438,15 @@ }

public project(nodes: INodeSequence): void {
nodes.insertBefore(this.host);
if (this.requiresMount) {
this.requiresMount = false;
nodes.insertBefore(this.host);
}
}
public onElementRemoved(): void {
this.requiresMount = true;
this.customElement.$nodes.remove();
}
}
export class HostProjector implements IViewProjector {
export class HostProjector implements IElementProjector {
constructor(customElement: ICustomElement, public host: INode) {

@@ -408,3 +460,3 @@ (host as any).$customElement = customElement;

public onChildrenChanged(callback: () => void): void {
public subscribeToChildrenChange(callback: () => void): void {
// Do nothing since this scenario will never have children.

@@ -419,3 +471,9 @@ }

nodes.appendTo(this.host);
this.project = PLATFORM.noop;
}
public onElementRemoved(): void {
// No special behavior is required because the host element removal
// will result in the projected nodes being removed, since they are children.
}
}

@@ -422,0 +480,0 @@

export * from './resources';
export * from './animator';
export * from './bindable';

@@ -4,0 +3,0 @@ export * from './custom-attribute';

@@ -1,66 +0,298 @@

import { BindingFlags } from '../binding/binding-flags';
import { BindingFlags, IBindScope } from '../binding';
import { INode } from '../dom';
import { IRenderable } from './renderable';
export class AttachLifecycle {
private tail = null;
private head = null;
private $nextAttached = null;
export enum LifecycleFlags {
none = 0b0_001,
noTasks = 0b0_010,
unbindAfterDetached = 0b0_100,
}
private constructor(private owner) {
this.tail = this.head = this;
export interface IAttach {
readonly $isAttached: boolean;
$attach(encapsulationSource: INode, lifecycle: IAttachLifecycle): void;
$detach(lifecycle: IDetachLifecycle): void;
$cache(): void;
}
export interface ILifecycleTask {
readonly done: boolean;
canCancel(): boolean;
cancel(): void;
wait(): Promise<void>;
}
export interface IAttachLifecycleController {
attach(requestor: IAttach): IAttachLifecycleController;
end(): ILifecycleTask;
}
type LifecycleAttachable = {
/*@internal*/
$nextAttached?: LifecycleAttachable;
attached(): void;
};
type LifecycleNodeAddable = Pick<IRenderable, '$addNodes'> & {
/*@internal*/
$nextAddNodes?: LifecycleNodeAddable;
};
export interface IAttachLifecycle {
readonly flags: LifecycleFlags;
registerTask(task: ILifecycleTask): void;
createChild(): IAttachLifecycle;
queueAddNodes(requestor: LifecycleNodeAddable): void;
queueAttachedCallback(requestor: LifecycleAttachable): void;
}
export interface IDetachLifecycleController {
detach(requestor: IAttach): IDetachLifecycleController;
end(): ILifecycleTask;
}
type LifecycleDetachable = {
/*@internal*/
$nextDetached?: LifecycleDetachable;
detached(): void;
};
type LifecycleNodeRemovable = Pick<IRenderable, '$removeNodes'> & {
/*@internal*/
$nextRemoveNodes?: LifecycleNodeRemovable;
};
export class AggregateLifecycleTask implements ILifecycleTask {
public done: boolean = true;
/*@internal*/
public owner: AttachLifecycleController | DetachLifecycleController = null;
private tasks: ILifecycleTask[] = [];
private waiter: Promise<void> = null;
private resolve: () => void = null;
public addTask(task: ILifecycleTask): void {
if (!task.done) {
this.done = false;
this.tasks.push(task);
task.wait().then(() => this.tryComplete());
}
}
public static start(owner: any, existingLifecycle?: AttachLifecycle): AttachLifecycle {
return existingLifecycle || new AttachLifecycle(owner);
public canCancel(): boolean {
if (this.done) {
return false;
}
return this.tasks.every(x => x.canCancel());
}
public queueAttachedCallback(requestor: IAttach) {
this.tail.$nextAttached = requestor;
this.tail = requestor;
public cancel(): void {
if (this.canCancel()) {
this.tasks.forEach(x => x.cancel());
this.done = false;
}
}
public end(owner: any) {
if (owner === this.owner) {
let current = this.head;
let next;
public wait(): Promise<void> {
if (this.waiter === null) {
if (this.done) {
this.waiter = Promise.resolve();
} else {
this.waiter = new Promise((resolve) => this.resolve = resolve);
}
}
while (current) {
current.attached();
next = current.$nextAttached;
current.$nextAttached = null;
current = next;
return this.waiter;
}
private tryComplete(): void {
if (this.done) {
return;
}
if (this.tasks.every(x => x.done)) {
this.complete(true);
}
}
private complete(notCancelled: boolean): void {
this.done = true;
if (notCancelled && this.owner !== null) {
this.owner.processAll();
}
if (this.resolve !== null) {
this.resolve();
}
}
}
export interface IDetachLifecycle {
readonly flags: LifecycleFlags;
registerTask(task: ILifecycleTask): void;
createChild(): IDetachLifecycle;
queueRemoveNodes(requestor: LifecycleNodeRemovable): void;
queueDetachedCallback(requestor: LifecycleDetachable): void;
}
/*@internal*/
class AttachLifecycleController implements IAttachLifecycle, IAttachLifecycleController {
/*@internal*/
public $nextAddNodes: LifecycleNodeAddable;
/*@internal*/
public $nextAttached: LifecycleAttachable;
private attachedHead: LifecycleAttachable;
private attachedTail: LifecycleAttachable;
private addNodesHead: LifecycleNodeAddable;
private addNodesTail: LifecycleNodeAddable;
private task: AggregateLifecycleTask = null;
constructor(
public readonly flags: LifecycleFlags,
private parent: AttachLifecycleController = null,
private encapsulationSource: INode = null
) {
this.addNodesTail = this.addNodesHead = this;
this.attachedTail = this.attachedHead = this;
}
public attach(requestor: IAttach): IAttachLifecycleController {
requestor.$attach(this.encapsulationSource, this);
return this;
}
public queueAddNodes(requestor: LifecycleNodeAddable): void {
this.addNodesTail.$nextAddNodes = requestor;
this.addNodesTail = requestor;
}
public queueAttachedCallback(requestor: LifecycleAttachable): void {
this.attachedTail.$nextAttached = requestor;
this.attachedTail = requestor;
}
public registerTask(task: ILifecycleTask): void {
if (this.parent !== null) {
this.parent.registerTask(task);
} else {
let task = this.task;
if (task === null) {
this.task = task = new AggregateLifecycleTask();
}
task.addTask(task);
}
}
private attached() {}
public createChild(): IAttachLifecycle {
const lifecycle = new AttachLifecycleController(this.flags, this);
this.queueAddNodes(lifecycle);
this.queueAttachedCallback(lifecycle);
return lifecycle;
}
public end(): ILifecycleTask {
if (this.task !== null && !this.task.done) {
this.task.owner = this;
return this.task;
}
this.processAll();
return Lifecycle.done;
}
/*@internal*/
public processAll(): void {
this.processAddNodes();
this.processAttachedCallbacks();
}
/*@internal*/
public $addNodes(): void {
if (this.parent !== null) {
this.processAddNodes();
}
}
/*@internal*/
public attached(): void {
if (this.parent !== null) {
this.processAttachedCallbacks();
}
}
private processAddNodes(): void {
let currentAddNodes = this.addNodesHead;
let nextAddNodes;
while (currentAddNodes) {
currentAddNodes.$addNodes();
nextAddNodes = currentAddNodes.$nextAddNodes;
currentAddNodes.$nextAddNodes = null;
currentAddNodes = nextAddNodes;
}
}
private processAttachedCallbacks(): void {
let currentAttached = this.attachedHead;
let nextAttached;
while (currentAttached) {
currentAttached.attached();
nextAttached = currentAttached.$nextAttached;
currentAttached.$nextAttached = null;
currentAttached = nextAttached;
}
}
}
const dummyNodeSequence = { remove() {} };
/*@internal*/
export class DetachLifecycleController implements IDetachLifecycle, IDetachLifecycleController {
/*@internal*/
public $nextRemoveNodes: LifecycleNodeRemovable;
/*@internal*/
public $nextDetached: LifecycleDetachable;
export class DetachLifecycle {
private detachedHead = null; //LOL
private detachedTail = null;
private viewRemoveHead = null;
private viewRemoveTail = null;
private $nextDetached = null;
private $nextRemoveView = null;
private $nodes = dummyNodeSequence;
private detachedHead: LifecycleDetachable; //LOL
private detachedTail: LifecycleDetachable;
private removeNodesHead: LifecycleNodeRemovable;
private removeNodesTail: LifecycleNodeRemovable;
private task: AggregateLifecycleTask = null;
private allowNodeRemoves: boolean = true;
private constructor(private owner) {
constructor(
public readonly flags: LifecycleFlags,
private parent: DetachLifecycleController = null
) {
this.detachedTail = this.detachedHead = this;
this.viewRemoveTail = this.viewRemoveHead = this;
this.removeNodesTail = this.removeNodesHead = this;
}
public static start(owner: any, existingLifecycle?: DetachLifecycle) {
return existingLifecycle || new DetachLifecycle(owner);
public detach(requestor: IAttach): IDetachLifecycleController {
this.allowNodeRemoves = true;
if (requestor.$isAttached) {
requestor.$detach(this);
} else if (isNodeRemovable(requestor)) {
this.queueRemoveNodes(requestor);
}
return this;
}
public queueViewRemoval(requestor: IRenderable) {
this.viewRemoveTail.$nextRemoveView = requestor;
this.viewRemoveTail = requestor;
public queueRemoveNodes(requestor: LifecycleNodeRemovable): void {
if (this.allowNodeRemoves) {
this.removeNodesTail.$nextRemoveNodes = requestor;
this.removeNodesTail = requestor;
this.allowNodeRemoves = false; // only remove roots
}
}
public queueDetachedCallback(requestor: IAttach) {
public queueDetachedCallback(requestor: LifecycleDetachable): void {
this.detachedTail.$nextDetached = requestor;

@@ -70,39 +302,125 @@ this.detachedTail = requestor;

public end(owner: any) {
if (owner == this.owner) {
let current = this.detachedHead;
let next;
public registerTask(task: ILifecycleTask): void {
if (this.parent !== null) {
this.parent.registerTask(task);
} else {
let task = this.task;
while (current) {
current.detached();
next = current.$nextDetached;
current.$nextDetached = null;
current = next;
if (task === null) {
this.task = task = new AggregateLifecycleTask();
}
let current2 = this.viewRemoveHead;
let next2;
task.addTask(task);
}
}
while (current2) {
current2.$nodes.remove();
next2 = current2.$nextRemoveView;
current2.$nextRemoveView = null;
current2 = next2;
public createChild(): IDetachLifecycle {
const lifecycle = new DetachLifecycleController(this.flags, this);
this.queueRemoveNodes(lifecycle);
this.queueDetachedCallback(lifecycle);
return lifecycle;
}
public end(): ILifecycleTask {
if (this.task !== null && !this.task.done) {
this.task.owner = this;
return this.task;
}
this.processAll();
return Lifecycle.done;
}
/*@internal*/
public $removeNodes(): void {
if (this.parent !== null) {
this.processRemoveNodes();
}
}
/*@internal*/
public detached(): void {
if (this.parent !== null) {
this.processDetachedCallbacks();
}
}
/*@internal*/
public processAll(): void {
this.processRemoveNodes();
this.processDetachedCallbacks();
}
private processRemoveNodes(): void {
let currentRemoveNodes = this.removeNodesHead;
if (this.flags & LifecycleFlags.unbindAfterDetached) {
while (currentRemoveNodes) {
currentRemoveNodes.$removeNodes();
currentRemoveNodes = currentRemoveNodes.$nextRemoveNodes;
}
} else {
let nextRemoveNodes;
while (currentRemoveNodes) {
currentRemoveNodes.$removeNodes();
nextRemoveNodes = currentRemoveNodes.$nextRemoveNodes;
currentRemoveNodes.$nextRemoveNodes = null;
currentRemoveNodes = nextRemoveNodes;
}
}
}
private detached() {}
private processDetachedCallbacks(): void {
let currentDetached = this.detachedHead;
let nextDetached;
while (currentDetached) {
currentDetached.detached();
nextDetached = currentDetached.$nextDetached;
currentDetached.$nextDetached = null;
currentDetached = nextDetached;
}
if (this.flags & LifecycleFlags.unbindAfterDetached) {
let currentRemoveNodes = this.removeNodesHead;
let nextRemoveNodes;
while (currentRemoveNodes) {
if (isUnbindable(currentRemoveNodes)) {
currentRemoveNodes.$unbind(BindingFlags.fromUnbind);
}
nextRemoveNodes = currentRemoveNodes.$nextRemoveNodes;
currentRemoveNodes.$nextRemoveNodes = null;
currentRemoveNodes = nextRemoveNodes;
}
}
}
}
export interface IAttach {
readonly $isAttached: boolean;
$attach(encapsulationSource: INode, lifecycle?: AttachLifecycle): void;
$detach(lifecycle?: DetachLifecycle): void;
function isNodeRemovable(requestor: object): requestor is LifecycleNodeRemovable {
return '$removeNodes' in requestor;
}
export interface IBindSelf {
readonly $isBound: boolean;
$bind(flags: BindingFlags): void;
$unbind(flags: BindingFlags): void;
function isUnbindable(requestor: object): requestor is IBindScope {
return '$unbind' in requestor;
}
export const Lifecycle = {
beginAttach(encapsulationSource: INode, flags: LifecycleFlags): IAttachLifecycleController {
return new AttachLifecycleController(flags, null, encapsulationSource);
},
beginDetach(flags: LifecycleFlags): IDetachLifecycleController {
return new DetachLifecycleController(flags);
},
done: {
done: true,
canCancel(): boolean { return false; },
cancel(): void {},
wait(): Promise<void> { return Promise.resolve(); }
}
};
import { DI } from '@aurelia/kernel';
import { IScope } from '../binding/binding-context';
import { BindingFlags } from '../binding/binding-flags';
import { IBindScope } from '../binding/observation';

@@ -20,38 +19,4 @@ import { INodeSequence } from '../dom';

$addChild(child: IAttach | IBindScope, flags: BindingFlags): void;
$removeChild(child: IAttach | IBindScope): void;
$addNodes(): void;
$removeNodes(): void;
}
/*@internal*/
export function addRenderableChild(this: IRenderable, child: IAttach | IBindScope, flags: BindingFlags): void {
if ('$bind' in child) {
this.$bindables.push(child);
if (this.$isBound) {
child.$bind(flags, this.$scope);
}
}
if ('$attach' in child) {
this.$attachables.push(child);
if (this.$isAttached) {
child.$attach((this as any).$encapsulationSource);
}
}
}
/*@internal*/
export function removeRenderableChild(this: IRenderable, child: IAttach | IBindScope): void {
const attachableIndex = this.$attachables.indexOf(child as IAttach);
if (attachableIndex !== -1) {
this.$attachables.splice(attachableIndex, 1);
(child as IAttach).$detach();
}
const bindableIndex = this.$bindables.indexOf(child as IBindScope);
if (bindableIndex !== -1) {
this.$bindables.splice(bindableIndex, 1);
(child as IBindScope).$unbind(BindingFlags.fromUnbind);
}
}

@@ -1,3 +0,2 @@

import { Immutable } from '@aurelia/kernel';
import { Reporter } from '@aurelia/kernel';
import { Immutable, Reporter } from '@aurelia/kernel';
import { Binding } from '../binding/binding';

@@ -20,3 +19,2 @@ import { BindingMode } from '../binding/binding-mode';

IHydrateTemplateController,
ILetBindingInstruction,
ILetElementInstruction,

@@ -23,0 +21,0 @@ IListenerBindingInstruction,

@@ -8,3 +8,2 @@ import { all, DI, IContainer, Immutable, inject, PLATFORM, Reporter } from '@aurelia/kernel';

import { IResourceDescriptions, IResourceKind, IResourceType, ResourceDescription } from '../resource';
import { IAnimator } from './animator';
import { ICustomAttribute, ICustomAttributeType } from './custom-attribute';

@@ -45,3 +44,3 @@ import { ICustomElement, ICustomElementType } from './custom-element';

@inject(IContainer, IChangeSet, IObserverLocator, IEventManager, IExpressionParser, IAnimator, all(ITemplateCompiler))
@inject(IContainer, IChangeSet, IObserverLocator, IEventManager, IExpressionParser, all(ITemplateCompiler))
/*@internal*/

@@ -60,3 +59,2 @@ export class RenderingEngine implements IRenderingEngine {

private parser: IExpressionParser,
private animator: IAnimator,
templateCompilers: ITemplateCompiler[]

@@ -133,3 +131,3 @@ ) {

const template = this.templateFromSource(definition, parentContext);
const factory = new ViewFactory(definition.name, template, this.animator);
const factory = new ViewFactory(definition.name, template);
factory.setCacheSize(definition.cache, true);

@@ -136,0 +134,0 @@ return factory;

import { Constructable, Immutable, inject } from '@aurelia/kernel';
import { BindingFlags } from '../../binding/binding-flags';
import { INode } from '../../dom';
import { bindable } from '../bindable';

@@ -13,5 +14,7 @@ import { createElement, PotentialRenderable } from '../create-element';

} from '../instructions';
import { IAttachLifecycle, IDetachLifecycle } from '../lifecycle';
import { IRenderable } from '../renderable';
import { IRenderingEngine } from '../rendering-engine';
import { IView, IViewFactory } from '../view';
import { CompositionCoordinator } from './composition-coordinator';

@@ -31,8 +34,8 @@ const composeSource: ITemplateSource = {

export class Compose {
@bindable public subject: any = null;
@bindable public subject: Subject | Promise<Subject> = null;
@bindable public composing: boolean = false;
private task: CompositionTask = null;
private currentView: IView = null;
private properties: Record<string, TargetedInstruction> = null;
private coordinator: CompositionCoordinator;
private lastSubject: Subject | Promise<Subject> = null;

@@ -44,2 +47,7 @@ constructor(

) {
this.coordinator = new CompositionCoordinator();
this.coordinator.onSwapComplete = () => {
this.composing = false;
};
this.properties = instruction.instructions

@@ -56,27 +64,55 @@ .filter((x: any) => !composeProps.includes(x.dest))

/** @internal */
public binding(flags: BindingFlags): void {
this.startComposition(this.subject);
this.coordinator.binding(flags, this.$scope);
}
public attaching(encapsulationSource: INode, lifecycle: IAttachLifecycle): void {
this.coordinator.attaching(encapsulationSource, lifecycle);
}
public detaching(lifecycle: IDetachLifecycle): void {
this.coordinator.detaching(lifecycle);
}
public unbinding(flags: BindingFlags): void {
this.lastSubject = null;
this.coordinator.unbinding(flags);
}
public caching(): void {
this.coordinator.caching();
}
public subjectChanged(newValue: any): void {
this.startComposition(newValue, BindingFlags.fromBindableHandler);
this.startComposition(newValue);
}
/** @internal */
public bound(): void {
this.startComposition(this.subject, BindingFlags.fromBind);
private startComposition(subject: any): void {
if (this.lastSubject === subject) {
return;
}
this.lastSubject = subject;
if (subject instanceof Promise) {
subject = subject.then(x => this.resolveView(x));
} else {
subject = this.resolveView(subject);
}
this.composing = true;
this.coordinator.compose(subject);
}
/** @internal */
public endComposition(subject: Subject, flags: BindingFlags): void {
private resolveView(subject: Subject): IView {
const view = this.provideViewFor(subject);
this.clear();
if (view) {
view.onRender = () => view.$nodes.insertBefore(this.$projector.host);
view.mount(this.$projector.host);
view.lockScope(this.renderable.$scope);
this.currentView = view;
this.$addChild(view, flags);
return view;
}
this.composing = false;
return null;
}

@@ -121,51 +157,2 @@

}
private startComposition(subject: any, flags: BindingFlags): void {
if (this.task) {
this.task.cancel();
}
this.task = new CompositionTask(this, flags);
this.task.start(subject);
}
private clear(): void {
if (this.currentView) {
this.$removeChild(this.currentView);
this.currentView = null;
}
}
}
class CompositionTask {
private isCancelled: boolean = false;
constructor(private compose: Compose, private flags: BindingFlags) {}
public start(subject: any): void {
if (this.isCancelled) {
return;
}
this.compose.composing = true;
if (subject instanceof Promise) {
subject.then(x => this.complete(x));
} else {
this.complete(subject);
}
}
public cancel(): void {
this.isCancelled = true;
this.compose.composing = false;
}
private complete(subject: any): void {
if (this.isCancelled) {
return;
}
this.compose.endComposition(subject, this.flags);
}
}
import { inject } from '@aurelia/kernel';
import { BindingFlags } from '../../binding';
import { BindingFlags } from '../../binding/binding-flags';
import { DOM, INode, IRenderLocation } from '../../dom';
import { bindable } from '../bindable';
import { ICustomAttribute, templateController } from '../custom-attribute';
import { IAttachLifecycle, IDetachLifecycle } from '../lifecycle';
import { IView, IViewFactory } from '../view';
import { CompositionCoordinator } from './composition-coordinator';

@@ -13,77 +15,68 @@ export interface If extends ICustomAttribute {}

@bindable public value: boolean = false;
public elseFactory: IViewFactory;
private ifView: IView;
private elseView: IView;
public elseFactory: IViewFactory = null;
private $child: IView;
private encapsulationSource: INode;
private ifView: IView = null;
private elseView: IView = null;
private coordinator: CompositionCoordinator;
constructor(public ifFactory: IViewFactory, private location: IRenderLocation) {}
constructor(public ifFactory: IViewFactory, private location: IRenderLocation) {
this.coordinator = new CompositionCoordinator();
}
public bound(): void {
this.update(this.value, BindingFlags.fromBind);
public binding(flags: BindingFlags): void {
this.updateView();
this.coordinator.binding(flags, this.$scope);
}
public attaching(encapsulationSource: INode): void {
this.encapsulationSource = encapsulationSource;
public attaching(encapsulationSource: INode, lifecycle: IAttachLifecycle): void {
this.coordinator.attaching(encapsulationSource, lifecycle);
}
public unbound(): void {
if (this.$child) {
this.$child.$unbind(BindingFlags.fromUnbind);
this.$child = null;
}
public detaching(lifecycle: IDetachLifecycle): void {
this.coordinator.detaching(lifecycle);
}
public valueChanged(newValue: any): void {
this.update(newValue, BindingFlags.fromBindableHandler);
public unbinding(flags: BindingFlags): void {
this.coordinator.unbinding(flags);
}
private update(shouldRenderTrueBranch: boolean, flags: BindingFlags): void {
if (shouldRenderTrueBranch) {
this.activateBranch('if', flags);
} else if (this.elseFactory) {
this.activateBranch('else', flags);
} else if (this.$child) {
this.deactivateCurrentBranch(flags);
public caching(): void {
if (this.ifView !== null && this.ifView.release()) {
this.ifView = null;
}
}
private activateBranch(name: 'if' | 'else', flags: BindingFlags): void {
const branchView = this.ensureViewCreated(name);
if (this.$child) {
if (this.$child === branchView) {
return;
}
this.deactivateCurrentBranch(flags);
if (this.elseView !== null && this.elseView.release()) {
this.elseView = null;
}
this.$child = branchView;
branchView.$bind(flags, this.$scope);
this.coordinator.caching();
}
if (this.$isAttached) {
branchView.$attach(this.encapsulationSource);
}
public valueChanged(): void {
this.updateView();
}
private ensureViewCreated(name: 'if' | 'else'): IView {
const viewPropertyName = `${name}View`;
let branchView = this[viewPropertyName] as IView;
private updateView(): void {
let view: IView;
if (!branchView) {
this[viewPropertyName] = branchView
= (this[`${name}Factory`] as IViewFactory).create();
branchView.onRender = view => view.$nodes.insertBefore(this.location);
if (this.value) {
view = this.ifView = this.ensureView(this.ifView, this.ifFactory);
} else if (this.elseFactory !== null) {
view = this.elseView = this.ensureView(this.elseView, this.elseFactory);
} else {
view = null;
}
return branchView;
this.coordinator.compose(view);
}
private deactivateCurrentBranch(flags: BindingFlags): void {
this.$child.$detach();
this.$child.$unbind(flags);
this.$child = null;
private ensureView(view: IView, factory: IViewFactory): IView {
if (view === null) {
view = factory.create();
}
view.mount(this.location);
return view;
}

@@ -90,0 +83,0 @@ }

@@ -15,3 +15,3 @@ import { IContainer, Immutable, inject, PLATFORM, Registration } from '@aurelia/kernel';

import { CustomAttributeResource, ICustomAttribute, ICustomAttributeSource } from '../custom-attribute';
import { AttachLifecycle, DetachLifecycle } from '../lifecycle';
import { IAttachLifecycle, IDetachLifecycle, LifecycleFlags, Lifecycle } from '../lifecycle';
import { IRenderable } from '../renderable';

@@ -115,10 +115,13 @@ import { IRenderingEngine } from '../rendering-engine';

}
public $attach(encapsulationSource: INode, lifecycle: AttachLifecycle): void {
public $attach(encapsulationSource: INode, lifecycle: IAttachLifecycle): void {
this.encapsulationSource = encapsulationSource;
this.$isAttached = true;
}
public $detach(lifecycle: DetachLifecycle): void {
public $detach(lifecycle: IDetachLifecycle): void {
this.$isAttached = false;
this.encapsulationSource = null;
}
public $unbind(flags: BindingFlags): void {

@@ -139,2 +142,4 @@ if (this.$isBound) {

public $cache(): void { }
public flushChanges(): void {

@@ -188,3 +193,3 @@ this.handleBatchedChange();

let flags = BindingFlags.none;
const flags = BindingFlags.none;
const isAttached = this.$isAttached;

@@ -201,11 +206,11 @@ const scope = this.$scope;

i = newLength;
const lifecycle = DetachLifecycle.start(this);
const lifecycle = Lifecycle.beginDetach(LifecycleFlags.none);
while (i < oldLength) {
const view = views[i++];
if (isAttached) {
view.$detach(lifecycle);
}
view.tryReturnToCache();
view.release();
lifecycle.detach(view);
}
lifecycle.end(this);
lifecycle.end();
views.length = newLength;

@@ -220,3 +225,3 @@ }

const encapsulationSource = this.encapsulationSource;
const lifecycle = AttachLifecycle.start(this);
const lifecycle = Lifecycle.beginAttach(encapsulationSource, LifecycleFlags.none);
i = 0;

@@ -229,7 +234,6 @@ sourceExpression.iterate(items, (arr, i, item) => {

view.$bind(flags, createChildScope(overrideContext, { [local]: item }));
view.onRender = () => {
view.$nodes.insertBefore(location);
};
view.mount(location);
if (isAttached) {
view.$attach(encapsulationSource, lifecycle);
lifecycle.attach(view);
}

@@ -241,3 +245,4 @@ } else {

});
lifecycle.end(this);
lifecycle.end();
}

@@ -250,12 +255,11 @@

let i = 0;
const isAttached = this.$isAttached;
const lifecycle = DetachLifecycle.start(this);
const lifecycle = Lifecycle.beginDetach(LifecycleFlags.none);
while (i < len) {
const view = views[i++];
if (isAttached) {
view.$detach(lifecycle);
}
view.tryReturnToCache();
view.release();
lifecycle.detach(view);
}
lifecycle.end(this);
lifecycle.end();
}

@@ -262,0 +266,0 @@ }

@@ -6,2 +6,3 @@ import { inject } from '@aurelia/kernel';

import { ICustomAttribute, templateController } from '../custom-attribute';
import { IAttachLifecycle, IDetachLifecycle } from '../lifecycle';
import { IView, IViewFactory } from '../view';

@@ -13,16 +14,24 @@

export class Replaceable {
private $child: IView;
private currentView: IView;
constructor(private factory: IViewFactory, location: IRenderLocation) {
this.$child = this.factory.create();
this.$child.onRender = view => view.$nodes.insertBefore(location);
this.currentView = this.factory.create();
this.currentView.mount(location);
}
public bound(flags: BindingFlags, scope: IScope): void {
this.$child.$bind(flags, scope);
public binding(flags: BindingFlags): void {
this.currentView.$bind(flags, this.$scope);
}
public unbound(flags: BindingFlags,): void {
this.$child.$unbind(flags);
public attaching(encapsulationSource: any, lifecycle: IAttachLifecycle): void {
this.currentView.$attach(encapsulationSource, lifecycle);
}
public detaching(lifecycle: IDetachLifecycle): void {
this.currentView.$detach(lifecycle);
}
public unbinding(flags: BindingFlags): void {
this.currentView.$unbind(flags);
}
}

@@ -7,2 +7,3 @@ import { inject } from '@aurelia/kernel';

import { ICustomAttribute, templateController } from '../custom-attribute';
import { IAttachLifecycle, IDetachLifecycle } from '../lifecycle';
import { IView, IViewFactory } from '../view';

@@ -16,7 +17,7 @@

private $child: IView = null;
private currentView: IView = null;
constructor(private factory: IViewFactory, location: IRenderLocation) {
this.$child = this.factory.create();
this.$child.onRender = view => view.$nodes.insertBefore(location);
this.currentView = this.factory.create();
this.currentView.mount(location);
}

@@ -28,12 +29,20 @@

public bound(flags: BindingFlags): void {
public binding(flags: BindingFlags): void {
this.bindChild(flags);
}
public unbound(flags: BindingFlags): void {
this.$child.$unbind(flags);
public attaching(encapsulationSource: any, lifecycle: IAttachLifecycle): void {
this.currentView.$attach(encapsulationSource, lifecycle);
}
public detaching(lifecycle: IDetachLifecycle): void {
this.currentView.$detach(lifecycle);
}
public unbinding(flags: BindingFlags): void {
this.currentView.$unbind(flags);
}
private bindChild(flags: BindingFlags): void {
this.$child.$bind(
this.currentView.$bind(
flags,

@@ -40,0 +49,0 @@ BindingContext.createScopeFromParent(this.$scope, this.value)

@@ -17,2 +17,3 @@ import { BindingFlags } from '../binding/binding-flags';

readonly hasCreated: boolean;
readonly hasBinding: boolean;
readonly hasBound: boolean;

@@ -23,4 +24,6 @@ readonly hasAttaching: boolean;

readonly hasDetached: boolean;
readonly hasUnbinding: boolean;
readonly hasUnbound: boolean;
readonly hasRender: boolean;
readonly hasCaching: boolean;
}

@@ -33,2 +36,3 @@

public hasCreated: boolean = false;
public hasBinding: boolean = false;
public hasBound: boolean = false;

@@ -39,4 +43,6 @@ public hasAttaching: boolean = false;

public hasDetached: boolean = false;
public hasUnbinding: boolean = false;
public hasUnbound: boolean = false;
public hasRender: boolean = false;
public hasCaching: boolean = false;

@@ -50,2 +56,3 @@ private constructor() {}

behavior.hasCreated = 'created' in instance;
behavior.hasBinding = 'binding' in instance;
behavior.hasBound = 'bound' in instance;

@@ -56,4 +63,6 @@ behavior.hasAttaching = 'attaching' in instance;

behavior.hasDetached = 'detached' in instance;
behavior.hasUnbinding = 'unbinding' in instance;
behavior.hasUnbound = 'unbound' in instance;
behavior.hasRender = 'render' in instance;
behavior.hasCaching = 'caching' in instance;

@@ -138,3 +147,3 @@ return behavior;

this.observing = true;
this.customElement.$projector.onChildrenChanged(() => this.onChildrenChanged());
this.customElement.$projector.subscribeToChildrenChange(() => this.onChildrenChanged());
this.children = findElements(this.customElement.$projector.children);

@@ -141,0 +150,0 @@ }

@@ -5,7 +5,6 @@ import { DI } from '@aurelia/kernel';

import { IBindScope } from '../binding/observation';
import { INode, INodeSequence } from '../dom';
import { IAnimator } from './animator';
import { AttachLifecycle, DetachLifecycle, IAttach } from './lifecycle';
import { INode, INodeSequence, IRenderLocation } from '../dom';
import { IAttach, IAttachLifecycle, IDetachLifecycle } from './lifecycle';
import { IRenderContext } from './render-context';
import { addRenderableChild, IRenderable, removeRenderableChild } from './renderable';
import { IRenderable } from './renderable';
import { ITemplate } from './template';

@@ -18,7 +17,6 @@

onRender: RenderCallback;
renderState: any;
mount(location: IRenderLocation): void;
release(): boolean;
lockScope(scope: IScope): void;
tryReturnToCache(): boolean;
}

@@ -47,13 +45,17 @@

public $context: IRenderContext;
public onRender: RenderCallback;
public renderState: any;
public inCache: boolean = false;
private $encapsulationSource: INode;
private location: IRenderLocation;
private requiresNodeAdd: boolean = false;
private isFree: boolean = false;
constructor(public factory: ViewFactory, private template: ITemplate, private animator: IAnimator) {
this.$nodes = this.createNodes();
constructor(public factory: ViewFactory, private template: ITemplate) {
this.$nodes = this.template.createFor(this);
}
public createNodes(): INodeSequence {
return this.template.createFor(this);
public mount(location: IRenderLocation): void {
this.location = location;
if (this.$nodes.lastChild.previousSibling !== location) {
this.requiresNodeAdd = true;
}
}

@@ -66,2 +68,12 @@

public release(): boolean {
this.isFree = true;
if (this.$isAttached) {
return this.factory.canReturnToCache(this);
} else {
return this.$removeNodes();
}
}
public $bind(flags: BindingFlags, scope: IScope): void {

@@ -86,3 +98,20 @@ if (this.$isBound) {

public $attach(encapsulationSource: INode, lifecycle?: AttachLifecycle): void {
public $addNodes(): void {
this.requiresNodeAdd = false;
this.$nodes.insertBefore(this.location);
}
public $removeNodes(): boolean {
this.requiresNodeAdd = true;
this.$nodes.remove();
if (this.isFree) {
this.isFree = false;
return this.factory.tryReturnToCache(this);
}
return false;
}
public $attach(encapsulationSource: INode, lifecycle: IAttachLifecycle): void {
if (this.$isAttached) {

@@ -93,3 +122,2 @@ return;

this.$encapsulationSource = encapsulationSource;
lifecycle = AttachLifecycle.start(this, lifecycle);

@@ -102,11 +130,12 @@ const attachables = this.$attachables;

this.onRender(this);
if (this.requiresNodeAdd) {
lifecycle.queueAddNodes(this);
}
this.$isAttached = true;
lifecycle.end(this);
}
public $detach(lifecycle?: DetachLifecycle): void {
public $detach(lifecycle: IDetachLifecycle): void {
if (this.$isAttached) {
lifecycle = DetachLifecycle.start(this, lifecycle);
lifecycle.queueViewRemoval(this);
lifecycle.queueRemoveNodes(this);

@@ -121,3 +150,2 @@ const attachables = this.$attachables;

this.$isAttached = false;
lifecycle.end(this);
}

@@ -140,10 +168,11 @@ }

public tryReturnToCache(): boolean {
return this.factory.tryReturnToCache(this);
public $cache(): void {
const attachables = this.$attachables;
for (let i = 0, ii = attachables.length; i < ii; ++i) {
attachables[i].$cache();
}
}
}
View.prototype.$addChild = addRenderableChild;
View.prototype.$removeChild = removeRenderableChild;
/*@internal*/

@@ -156,3 +185,3 @@ export class ViewFactory implements IViewFactory {

constructor(public name: string, private template: ITemplate, private animator: IAnimator) {}
constructor(public name: string, private template: ITemplate) {}

@@ -181,5 +210,9 @@ public setCacheSize(size: number | '*', doNotOverrideIfAlreadySet: boolean): void {

public canReturnToCache(view: IView): boolean {
return this.cache !== null && this.cache.length < this.cacheSize;
}
public tryReturnToCache(view: View): boolean {
if (this.cache !== null && this.cache.length < this.cacheSize) {
view.inCache = true;
if (this.canReturnToCache(view)) {
view.$cache();
this.cache.push(view);

@@ -196,8 +229,6 @@ return true;

if (cache !== null && cache.length > 0) {
const view = cache.pop();
view.inCache = false;
return view;
return cache.pop();
}
return new View(this, this.template, this.animator);
return new View(this, this.template);
}

@@ -204,0 +235,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc