aurelia-templating
Version:
An extensible HTML templating engine supporting databinding, custom elements, attached behaviors and more.
1,374 lines (1,357 loc) • 170 kB
JavaScript
import { DOM, FEATURE, PLATFORM } from 'aurelia-pal';
import { TemplateRegistryEntry, Loader } from 'aurelia-loader';
import { metadata, Origin, protocol } from 'aurelia-metadata';
import { relativeToFile } from 'aurelia-path';
import * as LogManager from 'aurelia-logging';
import { subscriberCollection, bindingMode, createOverrideContext, ValueConverterResource, BindingBehaviorResource, ObserverLocator, camelCase, EventManager } from 'aurelia-binding';
import { Container, resolver, inject } from 'aurelia-dependency-injection';
import { TaskQueue } from 'aurelia-task-queue';
class ElementEvents {
constructor(element) {
this.element = element;
this.subscriptions = {};
}
_enqueueHandler(handler) {
this.subscriptions[handler.eventName] = this.subscriptions[handler.eventName] || [];
this.subscriptions[handler.eventName].push(handler);
}
_dequeueHandler(handler) {
let index;
let subscriptions = this.subscriptions[handler.eventName];
if (subscriptions) {
index = subscriptions.indexOf(handler);
if (index > -1) {
subscriptions.splice(index, 1);
}
}
return handler;
}
publish(eventName, detail = {}, bubbles = true, cancelable = true) {
let event = DOM.createCustomEvent(eventName, { cancelable, bubbles, detail });
this.element.dispatchEvent(event);
}
subscribe(eventName, handler, captureOrOptions) {
if (typeof handler === 'function') {
if (captureOrOptions === undefined) {
captureOrOptions = ElementEvents.defaultListenerOptions;
}
const eventHandler = new EventHandlerImpl(this, eventName, handler, captureOrOptions, false);
return eventHandler;
}
return undefined;
}
subscribeOnce(eventName, handler, captureOrOptions) {
if (typeof handler === 'function') {
if (captureOrOptions === undefined) {
captureOrOptions = ElementEvents.defaultListenerOptions;
}
const eventHandler = new EventHandlerImpl(this, eventName, handler, captureOrOptions, true);
return eventHandler;
}
return undefined;
}
dispose(eventName) {
if (eventName && typeof eventName === 'string') {
let subscriptions = this.subscriptions[eventName];
if (subscriptions) {
while (subscriptions.length) {
let subscription = subscriptions.pop();
if (subscription) {
subscription.dispose();
}
}
}
}
else {
this.disposeAll();
}
}
disposeAll() {
for (let key in this.subscriptions) {
this.dispose(key);
}
}
}
ElementEvents.defaultListenerOptions = true;
class EventHandlerImpl {
constructor(owner, eventName, handler, captureOrOptions, once) {
this.owner = owner;
this.eventName = eventName;
this.handler = handler;
this.capture = typeof captureOrOptions === 'boolean' ? captureOrOptions : captureOrOptions.capture;
this.bubbles = !this.capture;
this.captureOrOptions = captureOrOptions;
this.once = once;
owner.element.addEventListener(eventName, this, captureOrOptions);
owner._enqueueHandler(this);
}
handleEvent(e) {
const fn = this.handler;
fn(e);
if (this.once) {
this.dispose();
}
}
dispose() {
this.owner.element.removeEventListener(this.eventName, this, this.captureOrOptions);
this.owner._dequeueHandler(this);
this.owner = this.handler = null;
}
}
class ResourceLoadContext {
constructor() {
this.dependencies = {};
}
addDependency(url) {
this.dependencies[url] = true;
}
hasDependency(url) {
return url in this.dependencies;
}
}
class ViewCompileInstruction {
constructor(targetShadowDOM = false, compileSurrogate = false) {
this.targetShadowDOM = targetShadowDOM;
this.compileSurrogate = compileSurrogate;
this.associatedModuleId = null;
}
}
ViewCompileInstruction.normal = new ViewCompileInstruction();
class BehaviorInstruction {
static enhance() {
let instruction = new BehaviorInstruction();
instruction.enhance = true;
return instruction;
}
static unitTest(type, attributes) {
let instruction = new BehaviorInstruction();
instruction.type = type;
instruction.attributes = attributes || {};
return instruction;
}
static element(node, type) {
let instruction = new BehaviorInstruction();
instruction.type = type;
instruction.attributes = {};
instruction.anchorIsContainer = !(node.hasAttribute('containerless') || type.containerless);
instruction.initiatedByBehavior = true;
return instruction;
}
static attribute(attrName, type) {
let instruction = new BehaviorInstruction();
instruction.attrName = attrName;
instruction.type = type || null;
instruction.attributes = {};
return instruction;
}
static dynamic(host, viewModel, viewFactory) {
let instruction = new BehaviorInstruction();
instruction.host = host;
instruction.viewModel = viewModel;
instruction.viewFactory = viewFactory;
instruction.inheritBindingContext = true;
return instruction;
}
}
BehaviorInstruction.normal = new BehaviorInstruction();
const biProto = BehaviorInstruction.prototype;
biProto.initiatedByBehavior = false;
biProto.enhance = false;
biProto.partReplacements = null;
biProto.viewFactory = null;
biProto.originalAttrName = null;
biProto.skipContentProcessing = false;
biProto.contentFactory = null;
biProto.viewModel = null;
biProto.anchorIsContainer = false;
biProto.host = null;
biProto.attributes = null;
biProto.type = null;
biProto.attrName = null;
biProto.inheritBindingContext = false;
class TargetInstruction {
static shadowSlot(parentInjectorId) {
let instruction = new TargetInstruction();
instruction.parentInjectorId = parentInjectorId;
instruction.shadowSlot = true;
return instruction;
}
static contentExpression(expression) {
let instruction = new TargetInstruction();
instruction.contentExpression = expression;
return instruction;
}
static letElement(expressions) {
let instruction = new TargetInstruction();
instruction.expressions = expressions;
instruction.letElement = true;
return instruction;
}
static lifting(parentInjectorId, liftingInstruction) {
let instruction = new TargetInstruction();
instruction.parentInjectorId = parentInjectorId;
instruction.expressions = TargetInstruction.noExpressions;
instruction.behaviorInstructions = [liftingInstruction];
instruction.viewFactory = liftingInstruction.viewFactory;
instruction.providers = [liftingInstruction.type.target];
instruction.lifting = true;
return instruction;
}
static normal(injectorId, parentInjectorId, providers, behaviorInstructions, expressions, elementInstruction) {
let instruction = new TargetInstruction();
instruction.injectorId = injectorId;
instruction.parentInjectorId = parentInjectorId;
instruction.providers = providers;
instruction.behaviorInstructions = behaviorInstructions;
instruction.expressions = expressions;
instruction.anchorIsContainer = elementInstruction ? elementInstruction.anchorIsContainer : true;
instruction.elementInstruction = elementInstruction;
return instruction;
}
static surrogate(providers, behaviorInstructions, expressions, values) {
let instruction = new TargetInstruction();
instruction.expressions = expressions;
instruction.behaviorInstructions = behaviorInstructions;
instruction.providers = providers;
instruction.values = values;
return instruction;
}
}
TargetInstruction.noExpressions = Object.freeze([]);
const tiProto = TargetInstruction.prototype;
tiProto.injectorId = null;
tiProto.parentInjectorId = null;
tiProto.shadowSlot = false;
tiProto.slotName = null;
tiProto.slotFallbackFactory = null;
tiProto.contentExpression = null;
tiProto.letElement = false;
tiProto.expressions = null;
tiProto.expressions = null;
tiProto.providers = null;
tiProto.viewFactory = null;
tiProto.anchorIsContainer = false;
tiProto.elementInstruction = null;
tiProto.lifting = false;
tiProto.values = null;
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __decorate(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
}
const capitalMatcher = /([A-Z])/g;
function addHyphenAndLower(char) {
return '-' + char.toLowerCase();
}
function _hyphenate(name) {
return (name.charAt(0).toLowerCase() + name.slice(1)).replace(capitalMatcher, addHyphenAndLower);
}
function _isAllWhitespace(node) {
return !(node.auInterpolationTarget || (/[^\t\n\r ]/.test(node.textContent)));
}
let BehaviorPropertyObserver = class BehaviorPropertyObserver {
constructor(taskQueue, obj, propertyName, selfSubscriber, initialValue) {
this.taskQueue = taskQueue;
this.obj = obj;
this.propertyName = propertyName;
this.notqueued = true;
this.publishing = false;
this.selfSubscriber = selfSubscriber;
this.currentValue = this.oldValue = initialValue;
}
getValue() {
return this.currentValue;
}
setValue(newValue) {
let oldValue = this.currentValue;
if (!Object.is(newValue, oldValue)) {
this.oldValue = oldValue;
this.currentValue = newValue;
if (this.publishing && this.notqueued) {
if (this.taskQueue.flushing) {
this.call();
}
else {
this.notqueued = false;
this.taskQueue.queueMicroTask(this);
}
}
}
}
call() {
let oldValue = this.oldValue;
let newValue = this.currentValue;
this.notqueued = true;
if (Object.is(newValue, oldValue)) {
return;
}
if (this.selfSubscriber) {
this.selfSubscriber(newValue, oldValue);
}
this.callSubscribers(newValue, oldValue);
this.oldValue = newValue;
}
callSubscribers(newValue, oldValue) {
throw new Error('Method not implemented.');
}
subscribe(context, callable) {
this.addSubscriber(context, callable);
}
addSubscriber(context, callable) {
throw new Error('Method not implemented.');
}
unsubscribe(context, callable) {
this.removeSubscriber(context, callable);
}
removeSubscriber(context, callable) {
throw new Error('Method not implemented.');
}
};
BehaviorPropertyObserver = __decorate([
subscriberCollection()
], BehaviorPropertyObserver);
function getObserver(instance, name) {
let lookup = instance.__observers__;
if (lookup === undefined) {
let ctor = Object.getPrototypeOf(instance).constructor;
let behavior = metadata.get(metadata.resource, ctor);
if (!behavior.isInitialized) {
behavior.initialize(Container.instance || new Container(), instance.constructor);
}
lookup = behavior.observerLocator.getOrCreateObserversLookup(instance);
behavior._ensurePropertiesDefined(instance, lookup);
}
return lookup[name];
}
class BindableProperty {
constructor(nameOrConfig) {
if (typeof nameOrConfig === 'string') {
this.name = nameOrConfig;
}
else {
Object.assign(this, nameOrConfig);
}
this.attribute = this.attribute || _hyphenate(this.name);
let defaultBindingMode = this.defaultBindingMode;
if (defaultBindingMode === null || defaultBindingMode === undefined) {
this.defaultBindingMode = bindingMode.oneWay;
}
else if (typeof defaultBindingMode === 'string') {
this.defaultBindingMode = bindingMode[defaultBindingMode] || bindingMode.oneWay;
}
this.changeHandler = this.changeHandler || null;
this.owner = null;
this.descriptor = null;
}
registerWith(target, behavior, descriptor) {
behavior.properties.push(this);
behavior.attributes[this.attribute] = this;
this.owner = behavior;
if (descriptor) {
this.descriptor = descriptor;
return this._configureDescriptor(descriptor);
}
return undefined;
}
_configureDescriptor(descriptor) {
let name = this.name;
descriptor.configurable = true;
descriptor.enumerable = true;
if ('initializer' in descriptor) {
this.defaultValue = descriptor.initializer;
delete descriptor.initializer;
delete descriptor.writable;
}
if ('value' in descriptor) {
this.defaultValue = descriptor.value;
delete descriptor.value;
delete descriptor.writable;
}
descriptor.get = function () {
return getObserver(this, name).getValue();
};
descriptor.set = function (value) {
getObserver(this, name).setValue(value);
};
descriptor.get.getObserver = function (obj) {
return getObserver(obj, name);
};
return descriptor;
}
defineOn(target, behavior) {
let name = this.name;
let handlerName;
if (this.changeHandler === null) {
handlerName = name + 'Changed';
if (handlerName in target.prototype) {
this.changeHandler = handlerName;
}
}
if (this.descriptor === null) {
Object.defineProperty(target.prototype, name, this._configureDescriptor({}));
}
}
createObserver(viewModel) {
let selfSubscriber = null;
let defaultValue = this.defaultValue;
let changeHandlerName = this.changeHandler;
let name = this.name;
let initialValue;
if (this.hasOptions) {
return undefined;
}
if (changeHandlerName in viewModel) {
if ('propertyChanged' in viewModel) {
selfSubscriber = (newValue, oldValue) => {
viewModel[changeHandlerName](newValue, oldValue);
viewModel.propertyChanged(name, newValue, oldValue);
};
}
else {
selfSubscriber = (newValue, oldValue) => viewModel[changeHandlerName](newValue, oldValue);
}
}
else if ('propertyChanged' in viewModel) {
selfSubscriber = (newValue, oldValue) => viewModel.propertyChanged(name, newValue, oldValue);
}
else if (changeHandlerName !== null) {
throw new Error(`Change handler ${changeHandlerName} was specified but not declared on the class.`);
}
if (defaultValue !== undefined) {
initialValue = typeof defaultValue === 'function' ? defaultValue.call(viewModel) : defaultValue;
}
return new BehaviorPropertyObserver(this.owner.taskQueue, viewModel, this.name, selfSubscriber, initialValue);
}
_initialize(viewModel, observerLookup, attributes, behaviorHandlesBind, boundProperties) {
let selfSubscriber;
let observer;
let attribute;
let defaultValue = this.defaultValue;
if (this.isDynamic) {
for (let key in attributes) {
this._createDynamicProperty(viewModel, observerLookup, behaviorHandlesBind, key, attributes[key], boundProperties);
}
}
else if (!this.hasOptions) {
observer = observerLookup[this.name];
if (attributes !== null) {
selfSubscriber = observer.selfSubscriber;
attribute = attributes[this.attribute];
if (behaviorHandlesBind) {
observer.selfSubscriber = null;
}
if (typeof attribute === 'string') {
viewModel[this.name] = attribute;
observer.call();
}
else if (attribute) {
boundProperties.push({ observer: observer, binding: attribute.createBinding(viewModel) });
}
else if (defaultValue !== undefined) {
observer.call();
}
observer.selfSubscriber = selfSubscriber;
}
observer.publishing = true;
}
}
_createDynamicProperty(viewModel, observerLookup, behaviorHandlesBind, name, attribute, boundProperties) {
let changeHandlerName = name + 'Changed';
let selfSubscriber = null;
let observer;
let info;
if (changeHandlerName in viewModel) {
if ('propertyChanged' in viewModel) {
selfSubscriber = (newValue, oldValue) => {
viewModel[changeHandlerName](newValue, oldValue);
viewModel.propertyChanged(name, newValue, oldValue);
};
}
else {
selfSubscriber = (newValue, oldValue) => viewModel[changeHandlerName](newValue, oldValue);
}
}
else if ('propertyChanged' in viewModel) {
selfSubscriber = (newValue, oldValue) => viewModel.propertyChanged(name, newValue, oldValue);
}
observer = observerLookup[name] = new BehaviorPropertyObserver(this.owner.taskQueue, viewModel, name, selfSubscriber);
Object.defineProperty(viewModel, name, {
configurable: true,
enumerable: true,
get: observer.getValue.bind(observer),
set: observer.setValue.bind(observer)
});
if (behaviorHandlesBind) {
observer.selfSubscriber = null;
}
if (typeof attribute === 'string') {
viewModel[name] = attribute;
observer.call();
}
else if (attribute) {
info = { observer: observer, binding: attribute.createBinding(viewModel) };
boundProperties.push(info);
}
observer.publishing = true;
observer.selfSubscriber = selfSubscriber;
}
}
class ViewLocator {
getViewStrategy(value) {
if (!value) {
return null;
}
if (typeof value === 'object' && 'getViewStrategy' in value) {
let origin = Origin.get(value.constructor);
value = value.getViewStrategy();
if (typeof value === 'string') {
value = new RelativeViewStrategy(value);
}
viewStrategy.assert(value);
if (origin.moduleId) {
value.makeRelativeTo(origin.moduleId);
}
return value;
}
if (typeof value === 'string') {
value = new RelativeViewStrategy(value);
}
if (viewStrategy.validate(value)) {
return value;
}
if (typeof value !== 'function') {
value = value.constructor;
}
if ('$view' in value) {
let c = value.$view;
let view;
c = typeof c === 'function' ? c.call(value) : c;
if (c === null) {
view = new NoViewStrategy();
}
else {
view = c instanceof StaticViewStrategy ? c : new StaticViewStrategy(c);
}
metadata.define(ViewLocator.viewStrategyMetadataKey, view, value);
return view;
}
let origin = Origin.get(value);
let strategy = metadata.get(ViewLocator.viewStrategyMetadataKey, value);
if (!strategy) {
if (!origin.moduleId) {
throw new Error('Cannot determine default view strategy for object.\n' + value);
}
strategy = this.createFallbackViewStrategy(origin);
}
else if (origin.moduleId) {
strategy.moduleId = origin.moduleId;
}
return strategy;
}
createFallbackViewStrategy(origin) {
return new ConventionalViewStrategy(this, origin);
}
convertOriginToViewUrl(origin) {
let moduleId = origin.moduleId;
let id = (moduleId.endsWith('.js') || moduleId.endsWith('.ts')) ? moduleId.substring(0, moduleId.length - 3) : moduleId;
return id + '.html';
}
}
ViewLocator.viewStrategyMetadataKey = 'aurelia:view-strategy';
function mi(name) {
throw new Error(`BindingLanguage must implement ${name}().`);
}
class BindingLanguage {
inspectAttribute(resources, elementName, attrName, attrValue) {
mi('inspectAttribute');
}
createAttributeInstruction(resources, element, info, existingInstruction, context) {
mi('createAttributeInstruction');
}
createLetExpressions(resources, element) {
mi('createLetExpressions');
}
inspectTextContent(resources, value) {
mi('inspectTextContent');
}
}
let noNodes = Object.freeze([]);
class SlotCustomAttribute {
constructor(element) {
this.element = element;
this.element.auSlotAttribute = this;
}
static inject() {
return [DOM.Element];
}
valueChanged(newValue, oldValue) { }
}
class PassThroughSlot {
constructor(anchor, name, destinationName, fallbackFactory) {
this.anchor = anchor;
this.anchor.viewSlot = this;
this.name = name;
this.destinationName = destinationName;
this.fallbackFactory = fallbackFactory;
this.destinationSlot = null;
this.projections = 0;
this.contentView = null;
let attr = new SlotCustomAttribute(this.anchor);
attr.value = this.destinationName;
}
get needsFallbackRendering() {
return this.fallbackFactory && this.projections === 0;
}
renderFallbackContent(view, nodes, projectionSource, index) {
if (this.contentView === null) {
this.contentView = this.fallbackFactory.create(this.ownerView.container);
this.contentView.bind(this.ownerView.bindingContext, this.ownerView.overrideContext);
let slots = Object.create(null);
slots[this.destinationSlot.name] = this.destinationSlot;
ShadowDOM.distributeView(this.contentView, slots, projectionSource, index, this.destinationSlot.name);
}
}
passThroughTo(destinationSlot) {
this.destinationSlot = destinationSlot;
}
addNode(view, node, projectionSource, index) {
if (this.contentView !== null) {
this.contentView.removeNodes();
this.contentView.detached();
this.contentView.unbind();
this.contentView = null;
}
if (node.viewSlot instanceof PassThroughSlot) {
node.viewSlot.passThroughTo(this);
return;
}
this.projections++;
this.destinationSlot.addNode(view, node, projectionSource, index);
}
removeView(view, projectionSource) {
this.projections--;
this.destinationSlot.removeView(view, projectionSource);
if (this.needsFallbackRendering) {
this.renderFallbackContent(null, noNodes, projectionSource);
}
}
removeAll(projectionSource) {
this.projections = 0;
this.destinationSlot.removeAll(projectionSource);
if (this.needsFallbackRendering) {
this.renderFallbackContent(null, noNodes, projectionSource);
}
}
projectFrom(view, projectionSource) {
this.destinationSlot.projectFrom(view, projectionSource);
}
created(ownerView) {
this.ownerView = ownerView;
}
bind(view) {
if (this.contentView) {
this.contentView.bind(view.bindingContext, view.overrideContext);
}
}
attached() {
if (this.contentView) {
this.contentView.attached();
}
}
detached() {
if (this.contentView) {
this.contentView.detached();
}
}
unbind() {
if (this.contentView) {
this.contentView.unbind();
}
}
}
class ShadowSlot {
constructor(anchor, name, fallbackFactory) {
this.anchor = anchor;
this.anchor.isContentProjectionSource = true;
this.anchor.viewSlot = this;
this.name = name;
this.fallbackFactory = fallbackFactory;
this.contentView = null;
this.projections = 0;
this.children = [];
this.projectFromAnchors = null;
this.destinationSlots = null;
}
get needsFallbackRendering() {
return this.fallbackFactory && this.projections === 0;
}
addNode(view, node, projectionSource, index, destination) {
let $node = node;
if (this.contentView !== null) {
this.contentView.removeNodes();
this.contentView.detached();
this.contentView.unbind();
this.contentView = null;
}
if ($node.viewSlot instanceof PassThroughSlot) {
$node.viewSlot.passThroughTo(this);
return;
}
if (this.destinationSlots !== null) {
ShadowDOM.distributeNodes(view, [$node], this.destinationSlots, this, index);
}
else {
$node.auOwnerView = view;
$node.auProjectionSource = projectionSource;
$node.auAssignedSlot = this;
let anchor = this._findAnchor(view, $node, projectionSource, index);
let parent = anchor.parentNode;
parent.insertBefore($node, anchor);
this.children.push($node);
this.projections++;
}
}
removeView(view, projectionSource) {
if (this.destinationSlots !== null) {
ShadowDOM.undistributeView(view, this.destinationSlots, this);
}
else if (this.contentView && this.contentView.hasSlots) {
ShadowDOM.undistributeView(view, this.contentView.slots, projectionSource);
}
else {
let found = this.children.find(x => x.auSlotProjectFrom === projectionSource);
if (found) {
let children = found.auProjectionChildren;
let ownChildren = this.children;
for (let i = 0, ii = children.length; i < ii; ++i) {
let child = children[i];
if (child.auOwnerView === view) {
children.splice(i, 1);
view.fragment.appendChild(child);
i--;
ii--;
this.projections--;
let idx = ownChildren.indexOf(child);
if (idx > -1) {
ownChildren.splice(idx, 1);
}
}
}
if (this.needsFallbackRendering) {
this.renderFallbackContent(view, noNodes, projectionSource);
}
}
}
}
removeAll(projectionSource) {
if (this.destinationSlots !== null) {
ShadowDOM.undistributeAll(this.destinationSlots, this);
}
else if (this.contentView && this.contentView.hasSlots) {
ShadowDOM.undistributeAll(this.contentView.slots, projectionSource);
}
else {
let found = this.children.find(x => x.auSlotProjectFrom === projectionSource);
if (found) {
let children = found.auProjectionChildren;
let ownChildren = this.children;
for (let i = 0, ii = children.length; i < ii; ++i) {
let child = children[i];
child.auOwnerView.fragment.appendChild(child);
this.projections--;
let idx = ownChildren.indexOf(child);
if (idx > -1) {
ownChildren.splice(idx, 1);
}
}
found.auProjectionChildren = [];
if (this.needsFallbackRendering) {
this.renderFallbackContent(null, noNodes, projectionSource);
}
}
}
}
_findAnchor(view, node, projectionSource, index) {
if (projectionSource) {
let found = this.children.find(x => x.auSlotProjectFrom === projectionSource);
if (found) {
if (index !== undefined) {
let children = found.auProjectionChildren;
let viewIndex = -1;
let lastView;
for (let i = 0, ii = children.length; i < ii; ++i) {
let current = children[i];
if (current.auOwnerView !== lastView) {
viewIndex++;
lastView = current.auOwnerView;
if (viewIndex >= index && lastView !== view) {
children.splice(i, 0, node);
return current;
}
}
}
}
found.auProjectionChildren.push(node);
return found;
}
}
return this.anchor;
}
projectTo(slots) {
this.destinationSlots = slots;
}
projectFrom(view, projectionSource) {
let anchor = DOM.createComment('anchor');
let parent = this.anchor.parentNode;
anchor.auSlotProjectFrom = projectionSource;
anchor.auOwnerView = view;
anchor.auProjectionChildren = [];
parent.insertBefore(anchor, this.anchor);
this.children.push(anchor);
if (this.projectFromAnchors === null) {
this.projectFromAnchors = [];
}
this.projectFromAnchors.push(anchor);
}
renderFallbackContent(view, nodes, projectionSource, index) {
if (this.contentView === null) {
this.contentView = this.fallbackFactory.create(this.ownerView.container);
this.contentView.bind(this.ownerView.bindingContext, this.ownerView.overrideContext);
this.contentView.insertNodesBefore(this.anchor);
}
if (this.contentView.hasSlots) {
let slots = this.contentView.slots;
let projectFromAnchors = this.projectFromAnchors;
if (projectFromAnchors !== null) {
for (let slotName in slots) {
let slot = slots[slotName];
for (let i = 0, ii = projectFromAnchors.length; i < ii; ++i) {
let anchor = projectFromAnchors[i];
slot.projectFrom(anchor.auOwnerView, anchor.auSlotProjectFrom);
}
}
}
this.fallbackSlots = slots;
ShadowDOM.distributeNodes(view, nodes, slots, projectionSource, index);
}
}
created(ownerView) {
this.ownerView = ownerView;
}
bind(view) {
if (this.contentView) {
this.contentView.bind(view.bindingContext, view.overrideContext);
}
}
attached() {
if (this.contentView) {
this.contentView.attached();
}
}
detached() {
if (this.contentView) {
this.contentView.detached();
}
}
unbind() {
if (this.contentView) {
this.contentView.unbind();
}
}
}
class ShadowDOM {
static getSlotName(node) {
if (node.auSlotAttribute === undefined) {
return ShadowDOM.defaultSlotKey;
}
return node.auSlotAttribute.value;
}
static distributeView(view, slots, projectionSource, index, destinationOverride) {
let nodes;
if (view === null) {
nodes = noNodes;
}
else {
let childNodes = view.fragment.childNodes;
let ii = childNodes.length;
nodes = new Array(ii);
for (let i = 0; i < ii; ++i) {
nodes[i] = childNodes[i];
}
}
ShadowDOM.distributeNodes(view, nodes, slots, projectionSource, index, destinationOverride);
}
static undistributeView(view, slots, projectionSource) {
for (let slotName in slots) {
slots[slotName].removeView(view, projectionSource);
}
}
static undistributeAll(slots, projectionSource) {
for (let slotName in slots) {
slots[slotName].removeAll(projectionSource);
}
}
static distributeNodes(view, nodes, slots, projectionSource, index, destinationOverride) {
for (let i = 0, ii = nodes.length; i < ii; ++i) {
let currentNode = nodes[i];
let nodeType = currentNode.nodeType;
if (currentNode.isContentProjectionSource) {
currentNode.viewSlot.projectTo(slots);
for (let slotName in slots) {
slots[slotName].projectFrom(view, currentNode.viewSlot);
}
nodes.splice(i, 1);
ii--;
i--;
}
else if (nodeType === 1 || nodeType === 3 || currentNode.viewSlot instanceof PassThroughSlot) {
if (nodeType === 3 && _isAllWhitespace(currentNode)) {
nodes.splice(i, 1);
ii--;
i--;
}
else {
let found = slots[destinationOverride || ShadowDOM.getSlotName(currentNode)];
if (found) {
found.addNode(view, currentNode, projectionSource, index);
nodes.splice(i, 1);
ii--;
i--;
}
}
}
else {
nodes.splice(i, 1);
ii--;
i--;
}
}
for (let slotName in slots) {
let slot = slots[slotName];
if (slot.needsFallbackRendering) {
slot.renderFallbackContent(view, nodes, projectionSource, index);
}
}
}
}
ShadowDOM.defaultSlotKey = '__au-default-slot-key__';
class CompositionTransactionNotifier {
constructor(owner) {
this.owner = owner;
this.owner._compositionCount++;
}
done() {
this.owner._compositionCount--;
this.owner._tryCompleteTransaction();
}
}
class CompositionTransactionOwnershipToken {
constructor(owner) {
this.owner = owner;
this.owner._ownershipToken = this;
this.thenable = this._createThenable();
}
waitForCompositionComplete() {
this.owner._tryCompleteTransaction();
return this.thenable;
}
resolve() {
this._resolveCallback();
}
_resolveCallback() {
throw new Error("Method not implemented.");
}
_createThenable() {
return new Promise((resolve) => {
this._resolveCallback = resolve;
});
}
}
class CompositionTransaction {
constructor() {
this._ownershipToken = null;
this._compositionCount = 0;
}
tryCapture() {
return this._ownershipToken === null
? new CompositionTransactionOwnershipToken(this)
: null;
}
enlist() {
return new CompositionTransactionNotifier(this);
}
_tryCompleteTransaction() {
if (this._compositionCount <= 0) {
this._compositionCount = 0;
if (this._ownershipToken !== null) {
let token = this._ownershipToken;
this._ownershipToken = null;
token.resolve();
}
}
}
}
class View {
constructor(container, viewFactory, fragment, controllers, bindings, children, slots) {
this.container = container;
this.viewFactory = viewFactory;
this.resources = viewFactory.resources;
this.fragment = fragment;
this.firstChild = fragment.firstChild;
this.lastChild = fragment.lastChild;
this.controllers = controllers;
this.bindings = bindings;
this.children = children;
this.slots = slots;
this.hasSlots = false;
this.fromCache = false;
this.isBound = false;
this.isAttached = false;
this.bindingContext = null;
this.overrideContext = null;
this.controller = null;
this.viewModelScope = null;
this.animatableElement = undefined;
this._isUserControlled = false;
this.contentView = null;
for (let _ in slots) {
this.hasSlots = true;
break;
}
}
returnToCache() {
this.viewFactory.returnViewToCache(this);
}
created() {
let i;
let ii;
let controllers = this.controllers;
for (i = 0, ii = controllers.length; i < ii; ++i) {
controllers[i].created(this);
}
}
bind(bindingContext, overrideContext, _systemUpdate) {
let controllers;
let bindings;
let children;
let i;
let ii;
if (_systemUpdate && this._isUserControlled) {
return;
}
if (this.isBound) {
if (this.bindingContext === bindingContext) {
return;
}
this.unbind();
}
this.isBound = true;
this.bindingContext = bindingContext;
this.overrideContext = overrideContext || createOverrideContext(bindingContext);
this.resources._invokeHook('beforeBind', this);
bindings = this.bindings;
for (i = 0, ii = bindings.length; i < ii; ++i) {
bindings[i].bind(this);
}
if (this.viewModelScope !== null) {
bindingContext.bind(this.viewModelScope.bindingContext, this.viewModelScope.overrideContext);
this.viewModelScope = null;
}
controllers = this.controllers;
for (i = 0, ii = controllers.length; i < ii; ++i) {
controllers[i].bind(this);
}
children = this.children;
for (i = 0, ii = children.length; i < ii; ++i) {
children[i].bind(bindingContext, overrideContext, true);
}
if (this.hasSlots) {
ShadowDOM.distributeView(this.contentView, this.slots);
}
}
addBinding(binding) {
this.bindings.push(binding);
if (this.isBound) {
binding.bind(this);
}
}
unbind() {
let controllers;
let bindings;
let children;
let i;
let ii;
if (this.isBound) {
this.isBound = false;
this.resources._invokeHook('beforeUnbind', this);
if (this.controller !== null) {
this.controller.unbind();
}
bindings = this.bindings;
for (i = 0, ii = bindings.length; i < ii; ++i) {
bindings[i].unbind();
}
controllers = this.controllers;
for (i = 0, ii = controllers.length; i < ii; ++i) {
controllers[i].unbind();
}
children = this.children;
for (i = 0, ii = children.length; i < ii; ++i) {
children[i].unbind();
}
this.bindingContext = null;
this.overrideContext = null;
}
}
insertNodesBefore(refNode) {
refNode.parentNode.insertBefore(this.fragment, refNode);
}
appendNodesTo(parent) {
parent.appendChild(this.fragment);
}
removeNodes() {
let fragment = this.fragment;
let current = this.firstChild;
let end = this.lastChild;
let next;
while (current) {
next = current.nextSibling;
fragment.appendChild(current);
if (current === end) {
break;
}
current = next;
}
}
attached() {
let controllers;
let children;
let i;
let ii;
if (this.isAttached) {
return;
}
this.isAttached = true;
if (this.controller !== null) {
this.controller.attached();
}
controllers = this.controllers;
for (i = 0, ii = controllers.length; i < ii; ++i) {
controllers[i].attached();
}
children = this.children;
for (i = 0, ii = children.length; i < ii; ++i) {
children[i].attached();
}
}
detached() {
let controllers;
let children;
let i;
let ii;
if (this.isAttached) {
this.isAttached = false;
if (this.controller !== null) {
this.controller.detached();
}
controllers = this.controllers;
for (i = 0, ii = controllers.length; i < ii; ++i) {
controllers[i].detached();
}
children = this.children;
for (i = 0, ii = children.length; i < ii; ++i) {
children[i].detached();
}
}
}
}
class Animator {
enter(element) {
return Promise.resolve(false);
}
leave(element) {
return Promise.resolve(false);
}
removeClass(element, className) {
element.classList.remove(className);
return Promise.resolve(false);
}
addClass(element, className) {
element.classList.add(className);
return Promise.resolve(false);
}
animate(element, className) {
return Promise.resolve(false);
}
runSequence(animations) {
return Promise.resolve(false);
}
registerEffect(effectName, properties) { }
unregisterEffect(effectName) { }
}
function getAnimatableElement(view) {
if (view.animatableElement !== undefined) {
return view.animatableElement;
}
let current = view.firstChild;
while (current && current.nodeType !== 1) {
current = current.nextSibling;
}
if (current && current.nodeType === 1) {
return (view.animatableElement = current.classList.contains('au-animate') ? current : null);
}
return (view.animatableElement = null);
}
class ViewSlot {
constructor(anchor, anchorIsContainer, animator = Animator.instance) {
this.anchor = anchor;
this.anchorIsContainer = anchorIsContainer;
this.bindingContext = null;
this.overrideContext = null;
this.animator = animator;
this.children = [];
this.isBound = false;
this.isAttached = false;
this.contentSelectors = null;
anchor.viewSlot = this;
anchor.isContentProjectionSource = false;
}
animateView(view, direction = 'enter') {
let animatableElement = getAnimatableElement(view);
if (animatableElement !== null) {
switch (direction) {
case 'enter':
return this.animator.enter(animatableElement);
case 'leave':
return this.animator.leave(animatableElement);
default:
throw new Error('Invalid animation direction: ' + direction);
}
}
}
transformChildNodesIntoView() {
let parent = this.anchor;
this.children.push({
fragment: parent,
firstChild: parent.firstChild,
lastChild: parent.lastChild,
returnToCache() { },
removeNodes() {
let last;
while (last = parent.lastChild) {
parent.removeChild(last);
}
},
created() { },
bind() { },
unbind() { },
attached() { },
detached() { }
});
}
bind(bindingContext, overrideContext) {
let i;
let ii;
let children;
if (this.isBound) {
if (this.bindingContext === bindingContext) {
return;
}
this.unbind();
}
this.isBound = true;
this.bindingContext = bindingContext = bindingContext || this.bindingContext;
this.overrideContext = overrideContext = overrideContext || this.overrideContext;
children = this.children;
for (i = 0, ii = children.length; i < ii; ++i) {
children[i].bind(bindingContext, overrideContext, true);
}
}
unbind() {
if (this.isBound) {
let i;
let ii;
let children = this.children;
this.isBound = false;
this.bindingContext = null;
this.overrideContext = null;
for (i = 0, ii = children.length; i < ii; ++i) {
children[i].unbind();
}
}
}
add(view) {
if (this.anchorIsContainer) {
view.appendNodesTo(this.anchor);
}
else {
view.insertNodesBefore(this.anchor);
}
this.children.push(view);
if (this.isAttached) {
view.attached();
return this.animateView(view, 'enter');
}
}
insert(index, view) {
let children = this.children;
let length = children.length;
if ((index === 0 && length === 0) || index >= length) {
return this.add(view);
}
view.insertNodesBefore(children[index].firstChild);
children.splice(index, 0, view);
if (this.isAttached) {
view.attached();
return this.animateView(view, 'enter');
}
}
move(sourceIndex, targetIndex) {
if (sourceIndex === targetIndex) {
return;
}
const children = this.children;
const view = children[sourceIndex];
view.removeNodes();
view.insertNodesBefore(children[targetIndex].firstChild);
children.splice(sourceIndex, 1);
children.splice(targetIndex, 0, view);
}
remove(view, returnToCache, skipAnimation) {
return this.removeAt(this.children.indexOf(view), returnToCache, skipAnimation);
}
removeMany(viewsToRemove, returnToCache, skipAnimation) {
const children = this.children;
let ii = viewsToRemove.length;
let i;
let rmPromises = [];
viewsToRemove.forEach(child => {
if (skipAnimation) {
child.removeNodes();
return;
}
let animation = this.animateView(child, 'leave');
if (animation) {
rmPromises.push(animation.then(() => child.removeNodes()));
}
else {
child.removeNodes();
}
});
let removeAction = () => {
if (this.isAttached) {
for (i = 0; i < ii; ++i) {
viewsToRemove[i].detached();