aurelia-templating
Version:
An extensible HTML templating engine supporting databinding, custom elements, attached behaviors and more.
1,783 lines (1,458 loc) • 141 kB
JavaScript
var _class, _temp, _dec, _class2, _dec2, _class3, _dec3, _class4, _dec4, _class5, _dec5, _class6, _dec6, _class7, _class8, _temp2, _class9, _temp3, _class11, _dec7, _class13, _dec8, _class14, _class15, _temp4, _dec9, _class16, _dec10, _class17, _dec11, _class18;
import * as LogManager from 'aurelia-logging';
import { metadata, Origin, protocol } from 'aurelia-metadata';
import { DOM, PLATFORM, FEATURE } from 'aurelia-pal';
import { TemplateRegistryEntry, Loader } from 'aurelia-loader';
import { relativeToFile } from 'aurelia-path';
import { Scope, Expression, ValueConverterResource, BindingBehaviorResource, camelCase, Binding, createOverrideContext, subscriberCollection, bindingMode, ObserverLocator, EventManager } from 'aurelia-binding';
import { Container, resolver, inject } from 'aurelia-dependency-injection';
import { TaskQueue } from 'aurelia-task-queue';
export const animationEvent = {
enterBegin: 'animation:enter:begin',
enterActive: 'animation:enter:active',
enterDone: 'animation:enter:done',
enterTimeout: 'animation:enter:timeout',
leaveBegin: 'animation:leave:begin',
leaveActive: 'animation:leave:active',
leaveDone: 'animation:leave:done',
leaveTimeout: 'animation:leave:timeout',
staggerNext: 'animation:stagger:next',
removeClassBegin: 'animation:remove-class:begin',
removeClassActive: 'animation:remove-class:active',
removeClassDone: 'animation:remove-class:done',
removeClassTimeout: 'animation:remove-class:timeout',
addClassBegin: 'animation:add-class:begin',
addClassActive: 'animation:add-class:active',
addClassDone: 'animation:add-class:done',
addClassTimeout: 'animation:add-class:timeout',
animateBegin: 'animation:animate:begin',
animateActive: 'animation:animate:active',
animateDone: 'animation:animate:done',
animateTimeout: 'animation:animate:timeout',
sequenceBegin: 'animation:sequence:begin',
sequenceDone: 'animation:sequence:done'
};
export let Animator = 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) {}
registerEffect(effectName, properties) {}
unregisterEffect(effectName) {}
};
export let CompositionTransactionNotifier = class CompositionTransactionNotifier {
constructor(owner) {
this.owner = owner;
this.owner._compositionCount++;
}
done() {
this.owner._compositionCount--;
this.owner._tryCompleteTransaction();
}
};
export let CompositionTransactionOwnershipToken = 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();
}
_createThenable() {
return new Promise((resolve, reject) => {
this._resolveCallback = resolve;
});
}
};
export let CompositionTransaction = 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();
}
}
}
};
const capitalMatcher = /([A-Z])/g;
function addHyphenAndLower(char) {
return '-' + char.toLowerCase();
}
export function _hyphenate(name) {
return (name.charAt(0).toLowerCase() + name.slice(1)).replace(capitalMatcher, addHyphenAndLower);
}
export function _isAllWhitespace(node) {
return !(node.auInterpolationTarget || /[^\t\n\r ]/.test(node.textContent));
}
export let ViewEngineHooksResource = class ViewEngineHooksResource {
constructor() {}
initialize(container, target) {
this.instance = container.get(target);
}
register(registry, name) {
registry.registerViewEngineHooks(this.instance);
}
load(container, target) {}
static convention(name) {
if (name.endsWith('ViewEngineHooks')) {
return new ViewEngineHooksResource();
}
}
};
export function viewEngineHooks(target) {
let deco = function (t) {
metadata.define(metadata.resource, new ViewEngineHooksResource(), t);
};
return target ? deco(target) : deco;
}
export let ElementEvents = 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 = true) {
if (typeof handler === 'function') {
const eventHandler = new EventHandlerImpl(this, eventName, handler, captureOrOptions, false);
return eventHandler;
}
return undefined;
}
subscribeOnce(eventName, handler, captureOrOptions = true) {
if (typeof handler === 'function') {
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);
}
}
};
let EventHandlerImpl = 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;
}
};
export let ResourceLoadContext = class ResourceLoadContext {
constructor() {
this.dependencies = {};
}
addDependency(url) {
this.dependencies[url] = true;
}
hasDependency(url) {
return url in this.dependencies;
}
};
export let ViewCompileInstruction = class ViewCompileInstruction {
constructor(targetShadowDOM = false, compileSurrogate = false) {
this.targetShadowDOM = targetShadowDOM;
this.compileSurrogate = compileSurrogate;
this.associatedModuleId = null;
}
};
ViewCompileInstruction.normal = new ViewCompileInstruction();
export let BehaviorInstruction = 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;
}
};
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;
BehaviorInstruction.normal = new BehaviorInstruction();
export let TargetInstruction = (_temp = _class = 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;
}
}, _class.noExpressions = Object.freeze([]), _temp);
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;
export const viewStrategy = protocol.create('aurelia:view-strategy', {
validate(target) {
if (!(typeof target.loadViewFactory === 'function')) {
return 'View strategies must implement: loadViewFactory(viewEngine: ViewEngine, compileInstruction: ViewCompileInstruction, loadContext?: ResourceLoadContext): Promise<ViewFactory>';
}
return true;
},
compose(target) {
if (!(typeof target.makeRelativeTo === 'function')) {
target.makeRelativeTo = PLATFORM.noop;
}
}
});
export let RelativeViewStrategy = (_dec = viewStrategy(), _dec(_class2 = class RelativeViewStrategy {
constructor(path) {
this.path = path;
this.absolutePath = null;
}
loadViewFactory(viewEngine, compileInstruction, loadContext, target) {
if (this.absolutePath === null && this.moduleId) {
this.absolutePath = relativeToFile(this.path, this.moduleId);
}
compileInstruction.associatedModuleId = this.moduleId;
return viewEngine.loadViewFactory(this.absolutePath || this.path, compileInstruction, loadContext, target);
}
makeRelativeTo(file) {
if (this.absolutePath === null) {
this.absolutePath = relativeToFile(this.path, file);
}
}
}) || _class2);
export let ConventionalViewStrategy = (_dec2 = viewStrategy(), _dec2(_class3 = class ConventionalViewStrategy {
constructor(viewLocator, origin) {
this.moduleId = origin.moduleId;
this.viewUrl = viewLocator.convertOriginToViewUrl(origin);
}
loadViewFactory(viewEngine, compileInstruction, loadContext, target) {
compileInstruction.associatedModuleId = this.moduleId;
return viewEngine.loadViewFactory(this.viewUrl, compileInstruction, loadContext, target);
}
}) || _class3);
export let NoViewStrategy = (_dec3 = viewStrategy(), _dec3(_class4 = class NoViewStrategy {
constructor(dependencies, dependencyBaseUrl) {
this.dependencies = dependencies || null;
this.dependencyBaseUrl = dependencyBaseUrl || '';
}
loadViewFactory(viewEngine, compileInstruction, loadContext, target) {
let entry = this.entry;
let dependencies = this.dependencies;
if (entry && entry.factoryIsReady) {
return Promise.resolve(null);
}
this.entry = entry = new TemplateRegistryEntry(this.moduleId || this.dependencyBaseUrl);
entry.dependencies = [];
entry.templateIsLoaded = true;
if (dependencies !== null) {
for (let i = 0, ii = dependencies.length; i < ii; ++i) {
let current = dependencies[i];
if (typeof current === 'string' || typeof current === 'function') {
entry.addDependency(current);
} else {
entry.addDependency(current.from, current.as);
}
}
}
compileInstruction.associatedModuleId = this.moduleId;
return viewEngine.loadViewFactory(entry, compileInstruction, loadContext, target);
}
}) || _class4);
export let TemplateRegistryViewStrategy = (_dec4 = viewStrategy(), _dec4(_class5 = class TemplateRegistryViewStrategy {
constructor(moduleId, entry) {
this.moduleId = moduleId;
this.entry = entry;
}
loadViewFactory(viewEngine, compileInstruction, loadContext, target) {
let entry = this.entry;
if (entry.factoryIsReady) {
return Promise.resolve(entry.factory);
}
compileInstruction.associatedModuleId = this.moduleId;
return viewEngine.loadViewFactory(entry, compileInstruction, loadContext, target);
}
}) || _class5);
export let InlineViewStrategy = (_dec5 = viewStrategy(), _dec5(_class6 = class InlineViewStrategy {
constructor(markup, dependencies, dependencyBaseUrl) {
this.markup = markup;
this.dependencies = dependencies || null;
this.dependencyBaseUrl = dependencyBaseUrl || '';
}
loadViewFactory(viewEngine, compileInstruction, loadContext, target) {
let entry = this.entry;
let dependencies = this.dependencies;
if (entry && entry.factoryIsReady) {
return Promise.resolve(entry.factory);
}
this.entry = entry = new TemplateRegistryEntry(this.moduleId || this.dependencyBaseUrl);
entry.template = DOM.createTemplateFromMarkup(this.markup);
if (dependencies !== null) {
for (let i = 0, ii = dependencies.length; i < ii; ++i) {
let current = dependencies[i];
if (typeof current === 'string' || typeof current === 'function') {
entry.addDependency(current);
} else {
entry.addDependency(current.from, current.as);
}
}
}
compileInstruction.associatedModuleId = this.moduleId;
return viewEngine.loadViewFactory(entry, compileInstruction, loadContext, target);
}
}) || _class6);
export let StaticViewStrategy = (_dec6 = viewStrategy(), _dec6(_class7 = class StaticViewStrategy {
constructor(config) {
if (typeof config === 'string' || config instanceof DOM.Element && config.tagName === 'TEMPLATE') {
config = {
template: config
};
}
this.template = config.template;
this.dependencies = config.dependencies || [];
this.factoryIsReady = false;
this.onReady = null;
this.moduleId = 'undefined';
}
loadViewFactory(viewEngine, compileInstruction, loadContext, target) {
if (this.factoryIsReady) {
return Promise.resolve(this.factory);
}
let deps = this.dependencies;
deps = typeof deps === 'function' ? deps() : deps;
deps = deps ? deps : [];
deps = Array.isArray(deps) ? deps : [deps];
return Promise.all(deps).then(dependencies => {
const container = viewEngine.container;
const appResources = viewEngine.appResources;
const viewCompiler = viewEngine.viewCompiler;
const viewResources = new ViewResources(appResources);
let resource;
let elDeps = [];
if (target) {
viewResources.autoRegister(container, target);
}
for (let dep of dependencies) {
if (typeof dep === 'function') {
resource = viewResources.autoRegister(container, dep);
} else if (dep && typeof dep === 'object') {
for (let key in dep) {
let exported = dep[key];
if (typeof exported === 'function') {
resource = viewResources.autoRegister(container, exported);
}
}
} else {
throw new Error(`dependency neither function nor object. Received: "${typeof dep}"`);
}
if (resource.elementName !== null) {
elDeps.push(resource);
}
}
return Promise.all(elDeps.map(el => el.load(container, el.target))).then(() => {
const factory = this.template !== null ? viewCompiler.compile(this.template, viewResources, compileInstruction) : null;
this.factoryIsReady = true;
this.factory = factory;
return factory;
});
});
}
}) || _class7);
export let ViewLocator = (_temp2 = _class8 = 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.', 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';
}
}, _class8.viewStrategyMetadataKey = 'aurelia:view-strategy', _temp2);
function mi(name) {
throw new Error(`BindingLanguage must implement ${name}().`);
}
export let BindingLanguage = class BindingLanguage {
inspectAttribute(resources, elementName, attrName, attrValue) {
mi('inspectAttribute');
}
createAttributeInstruction(resources, element, info, existingInstruction) {
mi('createAttributeInstruction');
}
createLetExpressions(resources, element) {
mi('createLetExpressions');
}
inspectTextContent(resources, value) {
mi('inspectTextContent');
}
};
let noNodes = Object.freeze([]);
export let SlotCustomAttribute = class SlotCustomAttribute {
static inject() {
return [DOM.Element];
}
constructor(element) {
this.element = element;
this.element.auSlotAttribute = this;
}
valueChanged(newValue, oldValue) {}
};
export let PassThroughSlot = 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();
}
}
};
export let ShadowSlot = 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) {
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;
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--;
}
}
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;
for (let i = 0, ii = children.length; i < ii; ++i) {
let child = children[i];
child.auOwnerView.fragment.appendChild(child);
this.projections--;
}
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();
}
}
};
export let ShadowDOM = (_temp3 = _class9 = 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);
}
}
}
}, _class9.defaultSlotKey = '__au-default-slot-key__', _temp3);
function register(lookup, name, resource, type) {
if (!name) {
return;
}
let existing = lookup[name];
if (existing) {
if (existing !== resource) {
throw new Error(`Attempted to register ${type} when one with the same name already exists. Name: ${name}.`);
}
return;
}
lookup[name] = resource;
}
export function validateBehaviorName(name, type) {
if (/[A-Z]/.test(name)) {
let newName = _hyphenate(name);
LogManager.getLogger('templating').warn(`'${name}' is not a valid ${type} name and has been converted to '${newName}'. Upper-case letters are not allowed because the DOM is not case-sensitive.`);
return newName;
}
return name;
}
const conventionMark = '__au_resource__';
export let ViewResources = class ViewResources {
static convention(target, existing) {
let resource;
if (existing && conventionMark in existing) {
return existing;
}
if ('$resource' in target) {
let config = target.$resource;
if (typeof config === 'string') {
resource = existing || new HtmlBehaviorResource();
resource[conventionMark] = true;
if (!resource.elementName) {
resource.elementName = validateBehaviorName(config, 'custom element');
}
} else {
if (typeof config === 'function') {
config = config.call(target);
}
if (typeof config === 'string') {
config = { name: config };
}
config = Object.assign({}, config);
let resourceType = config.type || 'element';
let name = config.name;
switch (resourceType) {
case 'element':case 'attribute':
resource = existing || new HtmlBehaviorResource();
resource[conventionMark] = true;
if (resourceType === 'element') {
if (!resource.elementName) {
resource.elementName = name ? validateBehaviorName(name, 'custom element') : _hyphenate(target.name);
}
} else {
if (!resource.attributeName) {
resource.attributeName = name ? validateBehaviorName(name, 'custom attribute') : _hyphenate(target.name);
}
}
if ('templateController' in config) {
config.liftsContent = config.templateController;
delete config.templateController;
}
if ('defaultBindingMode' in config && resource.attributeDefaultBindingMode !== undefined) {
config.attributeDefaultBindingMode = config.defaultBindingMode;
delete config.defaultBindingMode;
}
delete config.name;
Object.assign(resource, config);
break;
case 'valueConverter':
resource = new ValueConverterResource(camelCase(name || target.name));
break;
case 'bindingBehavior':
resource = new BindingBehaviorResource(camelCase(name || target.name));
break;
case 'viewEngineHooks':
resource = new ViewEngineHooksResource();
break;
}
}
if (resource instanceof HtmlBehaviorResource) {
let bindables = typeof config === 'string' ? undefined : config.bindables;
let currentProps = resource.properties;
if (Array.isArray(bindables)) {
for (let i = 0, ii = bindables.length; ii > i; ++i) {
let prop = bindables[i];
if (!prop || typeof prop !== 'string' && !prop.name) {
throw new Error(`Invalid bindable property at "${i}" for class "${target.name}". Expected either a string or an object with "name" property.`);
}
let newProp = new BindableProperty(prop);
let existed = false;
for (let j = 0, jj = currentProps.length; jj > j; ++j) {
if (currentProps[j].name === newProp.name) {
existed = true;
break;
}
}
if (existed) {
continue;
}
newProp.registerWith(target, resource);
}
}
}
}
return resource;
}
constructor(parent, viewUrl) {
this.bindingLanguage = null;
this.parent = parent || null;
this.hasParent = this.parent !== null;
this.viewUrl = viewUrl || '';
this.lookupFunctions = {
valueConverters: this.getValueConverter.bind(this),
bindingBehaviors: this.getBindingBehavior.bind(this)
};
this.attributes = Object.create(null);
this.elements = Object.create(null);
this.valueConverters = Object.create(null);
this.bindingBehaviors = Object.create(null);
this.attributeMap = Object.create(null);
this.values = Object.create(null);
this.beforeCompile = this.afterCompile = this.beforeCreate = this.afterCreate = this.beforeBind = this.beforeUnbind = false;
}
_tryAddHook(obj, name) {
if (typeof obj[name] === 'function') {
let func = obj[name].bind(obj);
let counter = 1;
let callbackName;
while (this[callbackName = name + counter.toString()] !== undefined) {
counter++;
}
this[name] = true;
this[callbackName] = func;
}
}
_invokeHook(name, one, two, three, four) {
if (this.hasParent) {
this.parent._invokeHook(name, one, two, three, four);
}
if (this[name]) {
this[name + '1'](one, two, three, four);
let callbackName = name + '2';
if (this[callbackName]) {
this[callbackName](one, two, three, four);
callbackName = name + '3';
if (this[callbackName]) {
this[callbackName](one, two, three, four);
let counter = 4;
while (this[callbackName = name + counter.toString()] !== undefined) {
this[callbackName](one, two, three, four);
counter++;
}
}
}
}
}
registerViewEngineHooks(hooks) {
this._tryAddHook(hooks, 'beforeCompile');
this._tryAddHook(hooks, 'afterCompile');
this._tryAddHook(hooks, 'beforeCreate');
this._tryAddHook(hooks, 'afterCreate');
this._tryAddHook(hooks, 'beforeBind');
this._tryAddHook(hooks, 'beforeUnbind');
}
getBindingLanguage(bindingLanguageFallback) {
return this.bindingLanguage || (this.bindingLanguage = bindingLanguageFallback);
}
patchInParent(newParent) {
let originalParent = this.parent;
this.parent = newParent || null;
this.hasParent = this.parent !== null;
if (newParent.parent === null) {
newParent.parent = originalParent;
newParent.hasParent = originalParent !== null;
}
}
relativeToView(path) {
return relativeToFile(path, this.viewUrl);
}
registerElement(tagName, behavior) {
register(this.elements, tagName, behavior, 'an Element');
}
getElement(tagName) {
return this.elements[tagName] || (this.hasParent ? this.parent.getElement(tagName) : null);
}
mapAttribute(attribute) {
return this.attributeMap[attribute] || (this.hasParent ? this.parent.mapAttribute(attribute) : null);
}
registerAttribute(attribute, behavior, knownAttribute) {
this.attributeMap[attribute] = knownAttribute;
register(this.attributes, attribute, behavior, 'an Attribute');
}
getAttribute(attribute) {
return this.attributes[attribute] || (this.hasParent ? this.parent.getAttribute(attribute) : null);
}
registerValueConverter(name, valueConverter) {
register(this.valueConverters, name, valueConverter, 'a ValueConverter');
}
getValueConverter(name) {
return this.valueConverters[name] || (this.hasParent ? this.parent.getValueConverter(name) : null);
}
registerBindingBehavior(name, bindingBehavior) {
register(this.bindingBehaviors, name, bindingBehavior, 'a BindingBehavior');
}
getBindingBehavior(name) {
return this.bindingBehaviors[name] || (this.hasParent ? this.parent.getBindingBehavior(name) : null);
}
registerValue(name, value) {
register(this.values, name, value, 'a value');
}
getValue(name) {
return this.values[name] || (this.hasParent ? this.parent.getValue(name) : null);
}
autoRegister(container, impl) {
let resourceTypeMeta = metadata.getOwn(metadata.resource, impl);
if (resourceTypeMeta) {
if (resourceTypeMeta instanceof HtmlBehaviorResource) {
ViewResources.convention(impl, resourceTypeMeta);
if (resourceTypeMeta.attributeName === null && resourceTypeMeta.elementName === null) {
HtmlBehaviorResource.convention(impl.name, resourceTypeMeta);
}
if (resourceTypeMeta.attributeName === null && resourceTypeMeta.elementName === null) {
resourceTypeMeta.elementName = _hyphenate(impl.name);
}
}
} else {
resourceTypeMeta = ViewResources.convention(impl) || HtmlBehaviorResource.convention(impl.name) || ValueConverterResource.convention(impl.name) || BindingBehaviorResource.convention(impl.name) || ViewEngineHooksResource.convention(impl.name);
if (!resourceTypeMeta) {
resourceTypeMeta = new HtmlBehaviorResource();
resourceTypeMeta.elementName = _hyphenate(impl.name);
}
metadata.define(metadata.resource, resourceTypeMeta, impl);
}
resourceTypeMeta.initialize(container, impl);
resourceTypeMeta.register(this);
return resourceTypeMeta;
}
};
export let View = 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 key 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();
}
}
}
};
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;
}
export let ViewSlot = 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);
}