From 151bbc1a9222bd24d726350bfee71d8d85b67311 Mon Sep 17 00:00:00 2001 From: Rob Eisenberg Date: Wed, 29 Jul 2015 20:52:22 -0400 Subject: [PATCH] chore(build): improve output file name --- bower.json | 14 +- build/tasks/build.js | 14 +- config.js | 56 ++--- dist/amd/aurelia-templating.d.ts | 8 +- dist/amd/{index.js => aurelia-templating.js} | 187 ++++++++++------ dist/{index.d.ts => aurelia-templating.d.ts} | 8 +- dist/{es6/index.js => aurelia-templating.js} | 208 ++++++++++-------- dist/commonjs/aurelia-templating.d.ts | 8 +- .../{index.js => aurelia-templating.js} | 187 ++++++++++------ dist/es6/aurelia-templating.d.ts | 8 +- dist/{index.js => es6/aurelia-templating.js} | 208 ++++++++++-------- dist/system/aurelia-templating.d.ts | 8 +- .../{index.js => aurelia-templating.js} | 190 ++++++++++------ package.json | 18 +- 14 files changed, 688 insertions(+), 434 deletions(-) rename dist/amd/{index.js => aurelia-templating.js} (96%) rename dist/{index.d.ts => aurelia-templating.d.ts} (98%) rename dist/{es6/index.js => aurelia-templating.js} (95%) rename dist/commonjs/{index.js => aurelia-templating.js} (96%) rename dist/{index.js => es6/aurelia-templating.js} (95%) rename dist/system/{index.js => aurelia-templating.js} (95%) diff --git a/bower.json b/bower.json index caae8520..9fdadd20 100644 --- a/bower.json +++ b/bower.json @@ -19,14 +19,14 @@ "url": "http://github.com/aurelia/templating" }, "dependencies": { - "aurelia-binding": "^0.8.0", - "aurelia-dependency-injection": "^0.9.0", + "aurelia-binding": "^0.8.3", + "aurelia-dependency-injection": "^0.9.1", "aurelia-html-template-element": "^0.2.0", - "aurelia-loader": "^0.8.0", - "aurelia-logging": "^0.6.0", - "aurelia-metadata": "^0.7.0", - "aurelia-path": "^0.8.0", - "aurelia-task-queue": "^0.6.0", + "aurelia-loader": "^0.8.3", + "aurelia-logging": "^0.6.2", + "aurelia-metadata": "^0.7.1", + "aurelia-path": "^0.8.1", + "aurelia-task-queue": "^0.6.1", "core-js": "zloirock/core-js" } } diff --git a/build/tasks/build.js b/build/tasks/build.js index c3247df8..92abdb06 100644 --- a/build/tasks/build.js +++ b/build/tasks/build.js @@ -10,6 +10,8 @@ var insert = require('gulp-insert'); var rename = require('gulp-rename'); var tools = require('aurelia-tools'); +var jsName = paths.packageName + '.js'; + gulp.task('build-index', function(){ var importsToAdd = []; var files = [ @@ -44,7 +46,7 @@ gulp.task('build-index', function(){ this.push(file); return callback(); })) - .pipe(concat('index.js')) + .pipe(concat(jsName)) .pipe(insert.transform(function(contents) { return tools.createImportBlock(importsToAdd) + contents; })) @@ -52,30 +54,30 @@ gulp.task('build-index', function(){ }); gulp.task('build-es6', function () { - return gulp.src(paths.output + 'index.js') + return gulp.src(paths.output + jsName) .pipe(gulp.dest(paths.output + 'es6')); }); gulp.task('build-commonjs', function () { - return gulp.src(paths.output + 'index.js') + return gulp.src(paths.output + jsName) .pipe(to5(assign({}, compilerOptions, {modules:'common'}))) .pipe(gulp.dest(paths.output + 'commonjs')); }); gulp.task('build-amd', function () { - return gulp.src(paths.output + 'index.js') + return gulp.src(paths.output + jsName) .pipe(to5(assign({}, compilerOptions, {modules:'amd'}))) .pipe(gulp.dest(paths.output + 'amd')); }); gulp.task('build-system', function () { - return gulp.src(paths.output + 'index.js') + return gulp.src(paths.output + jsName) .pipe(to5(assign({}, compilerOptions, {modules:'system'}))) .pipe(gulp.dest(paths.output + 'system')); }); gulp.task('build-dts', function(){ - return gulp.src(paths.output + 'index.d.ts') + return gulp.src(paths.output + paths.packageName + '.d.ts') .pipe(rename(paths.packageName + '.d.ts')) .pipe(gulp.dest(paths.output + 'es6')) .pipe(gulp.dest(paths.output + 'commonjs')) diff --git a/config.js b/config.js index 410cf75b..a5566607 100644 --- a/config.js +++ b/config.js @@ -16,56 +16,36 @@ System.config({ System.config({ "map": { - "aurelia-binding": "github:aurelia/binding@0.8.0", - "aurelia-dependency-injection": "github:aurelia/dependency-injection@0.9.0", + "aurelia-binding": "github:aurelia/binding@0.8.3", + "aurelia-dependency-injection": "github:aurelia/dependency-injection@0.9.1", "aurelia-html-template-element": "github:aurelia/html-template-element@0.2.0", - "aurelia-loader": "github:aurelia/loader@0.8.2", - "aurelia-logging": "github:aurelia/logging@0.6.0", - "aurelia-metadata": "github:aurelia/metadata@0.7.0", - "aurelia-path": "github:aurelia/path@0.8.0", - "aurelia-task-queue": "github:aurelia/task-queue@0.6.0", + "aurelia-loader": "github:aurelia/loader@0.8.3", + "aurelia-logging": "github:aurelia/logging@0.6.2", + "aurelia-metadata": "github:aurelia/metadata@0.7.1", + "aurelia-path": "github:aurelia/path@0.8.1", + "aurelia-task-queue": "github:aurelia/task-queue@0.6.1", "babel": "npm:babel-core@5.2.2", "babel-runtime": "npm:babel-runtime@5.2.2", "core-js": "npm:core-js@0.9.18", - "github:aurelia/binding@0.8.0": { - "aurelia-dependency-injection": "github:aurelia/dependency-injection@0.9.0", - "aurelia-metadata": "github:aurelia/metadata@0.7.0", - "aurelia-task-queue": "github:aurelia/task-queue@0.6.0", + "github:aurelia/binding@0.8.3": { + "aurelia-dependency-injection": "github:aurelia/dependency-injection@0.9.1", + "aurelia-metadata": "github:aurelia/metadata@0.7.1", + "aurelia-task-queue": "github:aurelia/task-queue@0.6.1", "core-js": "npm:core-js@0.9.18" }, - "github:aurelia/dependency-injection@0.8.1": { - "aurelia-logging": "github:aurelia/logging@0.5.0", - "aurelia-metadata": "github:aurelia/metadata@0.6.0", + "github:aurelia/dependency-injection@0.9.1": { + "aurelia-logging": "github:aurelia/logging@0.6.2", + "aurelia-metadata": "github:aurelia/metadata@0.7.1", "core-js": "npm:core-js@0.9.18" }, - "github:aurelia/dependency-injection@0.9.0": { - "aurelia-logging": "github:aurelia/logging@0.6.0", - "aurelia-metadata": "github:aurelia/metadata@0.7.0", - "core-js": "npm:core-js@0.9.18" - }, - "github:aurelia/loader@0.7.0": { - "aurelia-html-template-element": "github:aurelia/html-template-element@0.2.0", - "aurelia-path": "github:aurelia/path@0.7.0", - "core-js": "npm:core-js@0.9.18", - "webcomponentsjs": "github:webcomponents/webcomponentsjs@0.6.3" - }, - "github:aurelia/loader@0.8.0": { + "github:aurelia/loader@0.8.3": { "aurelia-html-template-element": "github:aurelia/html-template-element@0.2.0", - "aurelia-path": "github:aurelia/path@0.8.0", + "aurelia-metadata": "github:aurelia/metadata@0.7.1", + "aurelia-path": "github:aurelia/path@0.8.1", "core-js": "npm:core-js@0.9.18", "webcomponentsjs": "github:webcomponents/webcomponentsjs@0.6.3" }, - "github:aurelia/loader@0.8.2": { - "aurelia-html-template-element": "github:aurelia/html-template-element@0.2.0", - "aurelia-metadata": "github:aurelia/metadata@0.7.0", - "aurelia-path": "github:aurelia/path@0.8.0", - "core-js": "npm:core-js@0.9.18", - "webcomponentsjs": "github:webcomponents/webcomponentsjs@0.6.3" - }, - "github:aurelia/metadata@0.6.0": { - "core-js": "npm:core-js@0.9.18" - }, - "github:aurelia/metadata@0.7.0": { + "github:aurelia/metadata@0.7.1": { "core-js": "npm:core-js@0.9.18" }, "github:jspm/nodelibs-process@0.1.1": { diff --git a/dist/amd/aurelia-templating.d.ts b/dist/amd/aurelia-templating.d.ts index e8da6371..f6dae63c 100644 --- a/dist/amd/aurelia-templating.d.ts +++ b/dist/amd/aurelia-templating.d.ts @@ -7,6 +7,7 @@ declare module 'aurelia-templating' { import { bindingMode, ObserverLocator, BindingExpression, Binding, ValueConverterResource, EventManager } from 'aurelia-binding'; import { TaskQueue } from 'aurelia-task-queue'; import * as LogManager from 'aurelia-logging'; + export let DOMBoundary: any; export function createTemplateFromMarkup(markup: any): any; export const animationEvent: any; export class Animator { @@ -186,7 +187,7 @@ declare module 'aurelia-templating' { contentSelectorRemoveAll(): any; } export class BoundViewFactory { - constructor(parentContainer: any, viewFactory: any, executionContext: any); + constructor(parentContainer: any, viewFactory: any, executionContext: any, partReplacements: any); create(executionContext: any): any; } export class ViewFactory { @@ -245,7 +246,7 @@ declare module 'aurelia-templating' { analyze(container: Container, target: Function): any; load(container: Container, target: Function, viewStrategy?: ViewStrategy, transientView?: boolean, loadContext?: string[]): Promise; register(registry: ResourceRegistry, name?: string): any; - compile(compiler: ViewCompiler, resources: ResourceRegistry, node?: Node, instruction?: Object, parentNode?: Node): Node; + compile(compiler: ViewCompiler, resources: ResourceRegistry, node: Node, instruction: Object, parentNode?: Node): Node; create(container: Container, instruction?: Object, element?: Element, bindings?: Binding[]): BehaviorInstance; ensurePropertiesDefined(instance: Object, lookup: Object): any; } @@ -301,7 +302,10 @@ declare module 'aurelia-templating' { export function dynamicOptions(target: any): any; export function sync(selectorOrConfig: any): any; export function useShadowDOM(target: any): any; + + // this is now deprecated in favor of the processContent decorator export function skipContentProcessing(target: any): any; + export function processContent(processor: any): any; export function containerless(target: any): any; export function viewStrategy(strategy: any): any; export function useView(path: any): any; diff --git a/dist/amd/index.js b/dist/amd/aurelia-templating.js similarity index 96% rename from dist/amd/index.js rename to dist/amd/aurelia-templating.js index ae7abb05..e328420a 100644 --- a/dist/amd/index.js +++ b/dist/amd/aurelia-templating.js @@ -17,6 +17,7 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade exports.sync = sync; exports.useShadowDOM = useShadowDOM; exports.skipContentProcessing = skipContentProcessing; + exports.processContent = processContent; exports.containerless = containerless; exports.viewStrategy = viewStrategy; exports.useView = useView; @@ -34,6 +35,10 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade var needsTemplateFixup = !('content' in document.createElement('template')); + var DOMBoundary = 'aurelia-dom-boundary'; + + exports.DOMBoundary = DOMBoundary; + function createTemplateFromMarkup(markup) { var temp = document.createElement('template'); temp.innerHTML = markup; @@ -759,6 +764,20 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade exports.ContentSelector = ContentSelector; + function getAnimatableElement(view) { + var firstChild = view.firstChild; + + if (firstChild !== null && firstChild !== undefined && firstChild.nodeType === 8) { + var element = nextElementSibling(firstChild); + + if (element !== null && element !== undefined && element.nodeType === 1 && element.classList.contains('au-animate')) { + return element; + } + } + + return null; + } + var ViewSlot = (function () { function ViewSlot(anchor, anchorIsContainer, executionContext) { var animator = arguments[3] === undefined ? Animator.instance : arguments[3]; @@ -835,34 +854,36 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade if (this.isAttached) { view.attached(); - var element = view.firstChild ? nextElementSibling(view.firstChild) : null; - if (view.firstChild && view.firstChild.nodeType === 8 && element && element.nodeType === 1 && element.classList.contains('au-animate')) { - this.animator.enter(element); + var animatableElement = getAnimatableElement(view); + if (animatableElement !== null) { + return this.animator.enter(animatableElement); } } }; ViewSlot.prototype.insert = function insert(index, view) { - if (index === 0 && !this.children.length || index >= this.children.length) { - this.add(view); + var children = this.children, + length = children.length; + + if (index === 0 && length === 0 || index >= length) { + return this.add(view); } else { - view.insertNodesBefore(this.children[index].firstChild); - this.children.splice(index, 0, view); + view.insertNodesBefore(children[index].firstChild); + children.splice(index, 0, view); if (this.isAttached) { view.attached(); + + var animatableElement = getAnimatableElement(view); + if (animatableElement !== null) { + return this.animator.enter(animatableElement); + } } } }; ViewSlot.prototype.remove = function remove(view) { - view.removeNodes(); - - this.children.splice(this.children.indexOf(view), 1); - - if (this.isAttached) { - view.detached(); - } + return this.removeAt(this.children.indexOf(view)); }; ViewSlot.prototype.removeAt = function removeAt(index) { @@ -881,14 +902,14 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade return view; }; - var element = view.firstChild ? nextElementSibling(view.firstChild) : null; - if (view.firstChild && view.firstChild.nodeType === 8 && element && element.nodeType === 1 && element.classList.contains('au-animate')) { - return this.animator.leave(element).then(function () { + var animatableElement = getAnimatableElement(view); + if (animatableElement !== null) { + return this.animator.leave(animatableElement).then(function () { return removeAction(); }); - } else { - return removeAction(); } + + return removeAction(); }; ViewSlot.prototype.removeAll = function removeAll() { @@ -901,10 +922,10 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade var rmPromises = []; children.forEach(function (child) { - var element = child.firstChild ? nextElementSibling(child.firstChild) : null; - if (child.firstChild && child.firstChild.nodeType === 8 && element && element.nodeType === 1 && element.classList.contains('au-animate')) { - rmPromises.push(_this2.animator.leave(element).then(function () { - child.removeNodes(); + var animatableElement = getAnimatableElement(child); + if (animatableElement !== null) { + rmPromises.push(_this2.animator.leave(animatableElement).then(function () { + return child.removeNodes(); })); } else { child.removeNodes(); @@ -923,7 +944,7 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade if (rmPromises.length > 0) { return Promise.all(rmPromises).then(function () { - removeAction(); + return removeAction(); }); } else { removeAction(); @@ -934,12 +955,13 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade var _this3 = this; var removeResponse = this.removeAll(); + if (removeResponse !== undefined) { - removeResponse.then(function () { - _this3.add(view); + return removeResponse.then(function () { + return _this3.add(view); }); } else { - this.add(view); + return this.add(view); } }; @@ -1097,8 +1119,7 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade factory = partReplacements[factory.part] || factory; } - factory.partReplacements = partReplacements; - return this.boundViewFactory = new BoundViewFactory(this, factory, this.executionContext); + return this.boundViewFactory = new BoundViewFactory(this, factory, this.executionContext, partReplacements); } if (key === ViewSlot) { @@ -1146,7 +1167,6 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade var anchor = document.createComment('anchor'); if (isCustomElement) { - anchor.attributes = element.attributes; anchor.hasAttribute = function (name) { return element.hasAttribute(name); }; @@ -1294,13 +1314,13 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade } var BoundViewFactory = (function () { - function BoundViewFactory(parentContainer, viewFactory, executionContext) { + function BoundViewFactory(parentContainer, viewFactory, executionContext, partReplacements) { _classCallCheck(this, BoundViewFactory); this.parentContainer = parentContainer; this.viewFactory = viewFactory; this.executionContext = executionContext; - this.factoryOptions = { behaviorInstance: false }; + this.factoryOptions = { behaviorInstance: false, partReplacements: partReplacements }; } BoundViewFactory.prototype.create = function create(executionContext) { @@ -1344,17 +1364,25 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade children = [], contentSelectors = [], containers = { root: container }, - partReplacements = options.partReplacements || this.partReplacements, + partReplacements = options.partReplacements, + domBoundary = container.get(DOMBoundary), i, ii, - view; + view, + instructable, + instruction; if (element !== null && this.surrogateInstruction !== null) { applySurrogateInstruction(container, element, this.surrogateInstruction, behaviors, bindings, children); } for (i = 0, ii = instructables.length; i < ii; ++i) { - applyInstructions(containers, executionContext, instructables[i], instructions[i], behaviors, bindings, children, contentSelectors, partReplacements, resources); + instructable = instructables[i]; + instruction = instructions[instructable.getAttribute('au-target-id')]; + + instructable.domBoundary = domBoundary; + + applyInstructions(containers, executionContext, instructable, instruction, behaviors, bindings, children, contentSelectors, partReplacements, resources); } view = new View(container, fragment, behaviors, bindings, children, options.systemControlled, contentSelectors); @@ -1409,9 +1437,19 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade } } + var lastAUTargetID = 0; + function getNextAUTargetID() { + return (++lastAUTargetID).toString(); + } + function makeIntoInstructionTarget(element) { - var value = element.getAttribute('class'); + var value = element.getAttribute('class'), + auTargetID = getNextAUTargetID(); + element.setAttribute('class', value ? value += ' au-target' : 'au-target'); + element.setAttribute('au-target-id', auTargetID); + + return auTargetID; } var ViewCompiler = (function () { @@ -1428,7 +1466,7 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade ViewCompiler.prototype.compile = function compile(templateOrFragment, resources) { var options = arguments[2] === undefined ? defaultCompileOptions : arguments[2]; - var instructions = [], + var instructions = {}, targetShadowDOM = options.targetShadowDOM, content, part, @@ -1473,11 +1511,11 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade case 3: var expression = this.bindingLanguage.parseText(resources, node.wholeText); if (expression) { - var marker = document.createElement('au-marker'); - marker.className = 'au-target'; + var marker = document.createElement('au-marker'), + auTargetID = makeIntoInstructionTarget(marker); (node.parentNode || parentNode).insertBefore(marker, node); node.textContent = ' '; - instructions.push({ contentExpression: expression }); + instructions[auTargetID] = { contentExpression: expression }; while (node.nextSibling && node.nextSibling.nodeType === 3) { (node.parentNode || parentNode).removeChild(node.nextSibling); @@ -1632,7 +1670,9 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade instruction, info, property, - knownAttribute; + knownAttribute, + auTargetID, + injectorId; if (tagName === 'content') { if (targetLightDOM) { @@ -1741,19 +1781,19 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade if (liftingInstruction) { liftingInstruction.viewFactory = viewFactory; node = liftingInstruction.type.compile(this, resources, node, liftingInstruction, parentNode); - makeIntoInstructionTarget(node); - instructions.push({ + auTargetID = makeIntoInstructionTarget(node); + instructions[auTargetID] = { anchorIsContainer: false, parentInjectorId: parentInjectorId, expressions: [], behaviorInstructions: [liftingInstruction], viewFactory: liftingInstruction.viewFactory, providers: [liftingInstruction.type.target] - }); + }; } else { - var injectorId = behaviorInstructions.length ? getNextInjectorId() : false; - if (expressions.length || behaviorInstructions.length) { + injectorId = behaviorInstructions.length ? getNextInjectorId() : false; + for (i = 0, ii = behaviorInstructions.length; i < ii; ++i) { instruction = behaviorInstructions[i]; instruction.type.compile(this, resources, node, instruction, parentNode); @@ -1767,9 +1807,8 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade } } - makeIntoInstructionTarget(node); - - instructions.push({ + auTargetID = makeIntoInstructionTarget(node); + instructions[auTargetID] = { anchorIsContainer: elementInstruction ? elementInstruction.anchorIsContainer : true, isCustomElement: !!elementInstruction, injectorId: injectorId, @@ -1777,7 +1816,7 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade expressions: expressions, behaviorInstructions: behaviorInstructions, providers: providers - }); + }; } if (elementInstruction && elementInstruction.type.skipContentProcessing) { @@ -2366,6 +2405,10 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade contentSelectorFactoryOptions = { suppressBind: true }, hasShadowDOM = !!HTMLElement.prototype.createShadowRoot; + function doProcessContent() { + return true; + } + var HtmlBehaviorResource = (function () { function HtmlBehaviorResource() { _classCallCheck(this, HtmlBehaviorResource); @@ -2375,7 +2418,7 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade this.attributeDefaultBindingMode = undefined; this.liftsContent = false; this.targetShadowDOM = false; - this.skipContentProcessing = false; + this.processContent = doProcessContent; this.usesShadowDOM = false; this.childBindings = null; this.hasDynamicOptions = false; @@ -2536,9 +2579,9 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade node = template; } } else if (this.elementName !== null) { - var partReplacements = {}; + var partReplacements = instruction.partReplacements = {}; - if (!this.skipContentProcessing && node.hasChildNodes()) { + if (this.processContent(compiler, resources, node, instruction) && node.hasChildNodes()) { if (!this.usesShadowDOM) { var fragment = document.createDocumentFragment(), currentChild = node.firstChild, @@ -2575,7 +2618,6 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade } } - instruction.partReplacements = partReplacements; instruction.suppressBind = true; return node; }; @@ -2585,11 +2627,22 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade var element = arguments[2] === undefined ? null : arguments[2]; var bindings = arguments[3] === undefined ? null : arguments[3]; + var host = undefined; + + if (this.elementName !== null && element) { + if (this.usesShadowDOM) { + host = element.createShadowRoot(); + } else { + host = element; + } + + container.registerInstance(DOMBoundary, host); + } + var executionContext = instruction.executionContext || container.get(this.target), behaviorInstance = new BehaviorInstance(this, executionContext, instruction), childBindings = this.childBindings, - viewFactory, - host; + viewFactory = undefined; if (this.liftsContent) { element.primaryBehavior = behaviorInstance; @@ -2603,12 +2656,6 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade if (element) { element.primaryBehavior = behaviorInstance; - if (this.usesShadowDOM) { - host = element.createShadowRoot(); - } else { - host = element; - } - if (behaviorInstance.view) { if (!this.usesShadowDOM) { if (instruction.contentFactory) { @@ -3356,10 +3403,15 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade _aureliaMetadata.Decorators.configure.simpleDecorator('useShadowDOM', useShadowDOM); + function doNotProcessContent() { + return false; + } + function skipContentProcessing(target) { var deco = function deco(target) { var resource = _aureliaMetadata.Metadata.getOrCreateOwn(_aureliaMetadata.Metadata.resource, HtmlBehaviorResource, target); - resource.skipContentProcessing = true; + resource.processContent = doNotProcessContent; + console.warn('The @skipContentProcessing decorator is deprecated and will be removed in a future release. Please use @processContent(false) instead.'); }; return target ? deco(target) : deco; @@ -3367,6 +3419,15 @@ define(['exports', 'core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loade _aureliaMetadata.Decorators.configure.simpleDecorator('skipContentProcessing', skipContentProcessing); + function processContent(processor) { + return function (target) { + var resource = _aureliaMetadata.Metadata.getOrCreateOwn(_aureliaMetadata.Metadata.resource, HtmlBehaviorResource, target); + resource.processContent = processor || doNotProcessContent; + }; + } + + _aureliaMetadata.Decorators.configure.parameterizedDecorator('processContent', processContent); + function containerless(target) { var deco = function deco(target) { var resource = _aureliaMetadata.Metadata.getOrCreateOwn(_aureliaMetadata.Metadata.resource, HtmlBehaviorResource, target); diff --git a/dist/index.d.ts b/dist/aurelia-templating.d.ts similarity index 98% rename from dist/index.d.ts rename to dist/aurelia-templating.d.ts index e8da6371..f6dae63c 100644 --- a/dist/index.d.ts +++ b/dist/aurelia-templating.d.ts @@ -7,6 +7,7 @@ declare module 'aurelia-templating' { import { bindingMode, ObserverLocator, BindingExpression, Binding, ValueConverterResource, EventManager } from 'aurelia-binding'; import { TaskQueue } from 'aurelia-task-queue'; import * as LogManager from 'aurelia-logging'; + export let DOMBoundary: any; export function createTemplateFromMarkup(markup: any): any; export const animationEvent: any; export class Animator { @@ -186,7 +187,7 @@ declare module 'aurelia-templating' { contentSelectorRemoveAll(): any; } export class BoundViewFactory { - constructor(parentContainer: any, viewFactory: any, executionContext: any); + constructor(parentContainer: any, viewFactory: any, executionContext: any, partReplacements: any); create(executionContext: any): any; } export class ViewFactory { @@ -245,7 +246,7 @@ declare module 'aurelia-templating' { analyze(container: Container, target: Function): any; load(container: Container, target: Function, viewStrategy?: ViewStrategy, transientView?: boolean, loadContext?: string[]): Promise; register(registry: ResourceRegistry, name?: string): any; - compile(compiler: ViewCompiler, resources: ResourceRegistry, node?: Node, instruction?: Object, parentNode?: Node): Node; + compile(compiler: ViewCompiler, resources: ResourceRegistry, node: Node, instruction: Object, parentNode?: Node): Node; create(container: Container, instruction?: Object, element?: Element, bindings?: Binding[]): BehaviorInstance; ensurePropertiesDefined(instance: Object, lookup: Object): any; } @@ -301,7 +302,10 @@ declare module 'aurelia-templating' { export function dynamicOptions(target: any): any; export function sync(selectorOrConfig: any): any; export function useShadowDOM(target: any): any; + + // this is now deprecated in favor of the processContent decorator export function skipContentProcessing(target: any): any; + export function processContent(processor: any): any; export function containerless(target: any): any; export function viewStrategy(strategy: any): any; export function useView(path: any): any; diff --git a/dist/es6/index.js b/dist/aurelia-templating.js similarity index 95% rename from dist/es6/index.js rename to dist/aurelia-templating.js index f8f11db2..002f8688 100644 --- a/dist/es6/index.js +++ b/dist/aurelia-templating.js @@ -8,6 +8,8 @@ import {TaskQueue} from 'aurelia-task-queue'; let needsTemplateFixup = !('content' in document.createElement('template')); +export let DOMBoundary = 'aurelia-dom-boundary'; + export function createTemplateFromMarkup(markup){ let temp = document.createElement('template'); temp.innerHTML = markup; @@ -686,6 +688,22 @@ export class ContentSelector { } } +function getAnimatableElement(view){ + let firstChild = view.firstChild; + + if(firstChild !== null && firstChild !== undefined && firstChild.nodeType === 8){ + let element = nextElementSibling(firstChild); + + if(element !== null && element !== undefined && + element.nodeType === 1 && + element.classList.contains('au-animate')) { + return element; + } + } + + return null; +} + export class ViewSlot { constructor(anchor, anchorIsContainer, executionContext, animator=Animator.instance){ this.anchor = anchor; @@ -755,39 +773,37 @@ export class ViewSlot { if(this.isAttached){ view.attached(); - // Animate page itself - var element = view.firstChild ? nextElementSibling(view.firstChild) : null; - if(view.firstChild && - view.firstChild.nodeType === 8 && - element && - element.nodeType === 1 && - element.classList.contains('au-animate')) { - this.animator.enter(element); + + let animatableElement = getAnimatableElement(view); + if(animatableElement !== null){ + return this.animator.enter(animatableElement); } } } insert(index, view){ - if((index === 0 && !this.children.length) || index >= this.children.length){ - this.add(view); + let children = this.children, + length = children.length; + + if((index === 0 && length === 0) || index >= length){ + return this.add(view); } else{ - view.insertNodesBefore(this.children[index].firstChild); - this.children.splice(index, 0, view); + view.insertNodesBefore(children[index].firstChild); + children.splice(index, 0, view); if(this.isAttached){ view.attached(); + + let animatableElement = getAnimatableElement(view); + if(animatableElement !== null){ + return this.animator.enter(animatableElement); + } } } } remove(view){ - view.removeNodes(); - - this.children.splice(this.children.indexOf(view), 1); - - if(this.isAttached){ - view.detached(); - } + return this.removeAt(this.children.indexOf(view)); } removeAt(index){ @@ -804,18 +820,12 @@ export class ViewSlot { return view; }; - var element = view.firstChild ? nextElementSibling(view.firstChild) : null; - if(view.firstChild && - view.firstChild.nodeType === 8 && - element && - element.nodeType === 1 && - element.classList.contains('au-animate')) { - return this.animator.leave(element).then( () => { - return removeAction(); - }) - } else { - return removeAction(); + let animatableElement = getAnimatableElement(view); + if(animatableElement !== null){ + return this.animator.leave(animatableElement).then(() => removeAction()); } + + return removeAction(); } removeAll(){ @@ -826,15 +836,9 @@ export class ViewSlot { var rmPromises = []; children.forEach(child => { - var element = child.firstChild ? nextElementSibling(child.firstChild) : null; - if(child.firstChild && - child.firstChild.nodeType === 8 && - element && - element.nodeType === 1 && - element.classList.contains('au-animate')) { - rmPromises.push(this.animator.leave(element).then(() => { - child.removeNodes(); - })); + let animatableElement = getAnimatableElement(child); + if(animatableElement !== null){ + rmPromises.push(this.animator.leave(animatableElement).then(() => child.removeNodes())); } else { child.removeNodes(); } @@ -851,9 +855,7 @@ export class ViewSlot { }; if(rmPromises.length > 0) { - return Promise.all(rmPromises).then(() => { - removeAction(); - }); + return Promise.all(rmPromises).then(() => removeAction()); } else { removeAction(); } @@ -861,12 +863,11 @@ export class ViewSlot { swap(view){ var removeResponse = this.removeAll(); + if(removeResponse !== undefined) { - removeResponse.then(() => { - this.add(view); - }); + return removeResponse.then(() => this.add(view)); } else { - this.add(view); + return this.add(view); } } @@ -1024,8 +1025,7 @@ function elementContainerGet(key){ factory = partReplacements[factory.part] || factory; } - factory.partReplacements = partReplacements; - return this.boundViewFactory = new BoundViewFactory(this, factory, this.executionContext); + return this.boundViewFactory = new BoundViewFactory(this, factory, this.executionContext, partReplacements); } if(key === ViewSlot){ @@ -1073,7 +1073,6 @@ function makeElementIntoAnchor(element, isCustomElement){ var anchor = document.createComment('anchor'); if(isCustomElement){ - anchor.attributes = element.attributes; anchor.hasAttribute = function(name) { return element.hasAttribute(name); }; anchor.getAttribute = function(name){ return element.getAttribute(name); }; anchor.setAttribute = function(name, value) { element.setAttribute(name, value); }; @@ -1220,11 +1219,11 @@ function applySurrogateInstruction(container, element, instruction, behaviors, b } export class BoundViewFactory { - constructor(parentContainer, viewFactory, executionContext){ + constructor(parentContainer, viewFactory, executionContext, partReplacements){ this.parentContainer = parentContainer; this.viewFactory = viewFactory; this.executionContext = executionContext; - this.factoryOptions = { behaviorInstance:false }; + this.factoryOptions = { behaviorInstance:false, partReplacements:partReplacements }; } create(executionContext){ @@ -1259,18 +1258,22 @@ export class ViewFactory{ children = [], contentSelectors = [], containers = { root:container }, - partReplacements = options.partReplacements || this.partReplacements, - i, ii, view; + partReplacements = options.partReplacements, + domBoundary = container.get(DOMBoundary), + i, ii, view, instructable, instruction; if(element !== null && this.surrogateInstruction !== null){ applySurrogateInstruction(container, element, this.surrogateInstruction, behaviors, bindings, children); } - //TODO: get DOMBoundary from container; attach to instructable to be picked up by delegated events - for(i = 0, ii = instructables.length; i < ii; ++i){ - applyInstructions(containers, executionContext, instructables[i], - instructions[i], behaviors, bindings, children, contentSelectors, partReplacements, resources); + instructable = instructables[i]; + instruction = instructions[instructable.getAttribute('au-target-id')]; + + instructable.domBoundary = domBoundary; + + applyInstructions(containers, executionContext, instructable, + instruction, behaviors, bindings, children, contentSelectors, partReplacements, resources); } view = new View(container, fragment, behaviors, bindings, children, options.systemControlled, contentSelectors); @@ -1319,9 +1322,19 @@ function configureProperties(instruction, resources){ } } +let lastAUTargetID = 0; +function getNextAUTargetID(){ + return (++lastAUTargetID).toString(); +} + function makeIntoInstructionTarget(element){ - var value = element.getAttribute('class'); + let value = element.getAttribute('class'), + auTargetID = getNextAUTargetID(); + element.setAttribute('class', (value ? value += ' au-target' : 'au-target')); + element.setAttribute('au-target-id', auTargetID); + + return auTargetID; } export class ViewCompiler { @@ -1331,7 +1344,7 @@ export class ViewCompiler { } compile(templateOrFragment, resources, options=defaultCompileOptions){ - var instructions = [], + var instructions = {}, targetShadowDOM = options.targetShadowDOM, content, part, factory; @@ -1375,11 +1388,11 @@ export class ViewCompiler { //use wholeText to retrieve the textContent of all adjacent text nodes. var expression = this.bindingLanguage.parseText(resources, node.wholeText); if(expression){ - var marker = document.createElement('au-marker'); - marker.className = 'au-target'; + let marker = document.createElement('au-marker'), + auTargetID = makeIntoInstructionTarget(marker); (node.parentNode || parentNode).insertBefore(marker, node); node.textContent = ' '; - instructions.push({ contentExpression:expression }); + instructions[auTargetID] = { contentExpression:expression }; //remove adjacent text nodes. while(node.nextSibling && node.nextSibling.nodeType === 3) { (node.parentNode || parentNode).removeChild(node.nextSibling); @@ -1513,7 +1526,7 @@ export class ViewCompiler { bindingLanguage = this.bindingLanguage, liftingInstruction, viewFactory, type, elementInstruction, elementProperty, i, ii, attr, attrName, attrValue, instruction, info, - property, knownAttribute; + property, knownAttribute, auTargetID, injectorId; if(tagName === 'content'){ if(targetLightDOM){ @@ -1624,19 +1637,19 @@ export class ViewCompiler { if(liftingInstruction){ liftingInstruction.viewFactory = viewFactory; node = liftingInstruction.type.compile(this, resources, node, liftingInstruction, parentNode); - makeIntoInstructionTarget(node); - instructions.push({ + auTargetID = makeIntoInstructionTarget(node); + instructions[auTargetID] = { anchorIsContainer: false, parentInjectorId: parentInjectorId, expressions: [], behaviorInstructions: [liftingInstruction], viewFactory: liftingInstruction.viewFactory, providers: [liftingInstruction.type.target] - }); + }; }else{ - var injectorId = behaviorInstructions.length ? getNextInjectorId() : false; - if(expressions.length || behaviorInstructions.length){ + injectorId = behaviorInstructions.length ? getNextInjectorId() : false; + for(i = 0, ii = behaviorInstructions.length; i < ii; ++i){ instruction = behaviorInstructions[i]; instruction.type.compile(this, resources, node, instruction, parentNode); @@ -1650,9 +1663,8 @@ export class ViewCompiler { } } - makeIntoInstructionTarget(node); - - instructions.push({ + auTargetID = makeIntoInstructionTarget(node); + instructions[auTargetID] = { anchorIsContainer: elementInstruction ? elementInstruction.anchorIsContainer : true, isCustomElement: !!elementInstruction, injectorId: injectorId, @@ -1660,7 +1672,7 @@ export class ViewCompiler { expressions: expressions, behaviorInstructions: behaviorInstructions, providers: providers - }); + }; } if(elementInstruction && elementInstruction.type.skipContentProcessing){ @@ -2186,6 +2198,10 @@ var defaultInstruction = { suppressBind:false }, contentSelectorFactoryOptions = { suppressBind:true }, hasShadowDOM = !!HTMLElement.prototype.createShadowRoot; +function doProcessContent(){ + return true; +} + export class HtmlBehaviorResource { constructor(){ this.elementName = null; @@ -2193,7 +2209,7 @@ export class HtmlBehaviorResource { this.attributeDefaultBindingMode = undefined; this.liftsContent = false; this.targetShadowDOM = false; - this.skipContentProcessing = false; + this.processContent = doProcessContent; this.usesShadowDOM = false; this.childBindings = null; this.hasDynamicOptions = false; @@ -2320,7 +2336,7 @@ export class HtmlBehaviorResource { } } - compile(compiler:ViewCompiler, resources:ResourceRegistry, node?:Node, instruction?:Object, parentNode?:Node):Node{ + compile(compiler:ViewCompiler, resources:ResourceRegistry, node:Node, instruction:Object, parentNode?:Node):Node{ if(this.liftsContent){ if(!instruction.viewFactory){ var template = document.createElement('template'), @@ -2351,9 +2367,9 @@ export class HtmlBehaviorResource { node = template; } } else if(this.elementName !== null){ //custom element - var partReplacements = {}; + var partReplacements = instruction.partReplacements = {}; - if(!this.skipContentProcessing && node.hasChildNodes()){ + if(this.processContent(compiler, resources, node, instruction) && node.hasChildNodes()){ if(!this.usesShadowDOM){ var fragment = document.createDocumentFragment(), currentChild = node.firstChild, @@ -2389,18 +2405,27 @@ export class HtmlBehaviorResource { } } - instruction.partReplacements = partReplacements; instruction.suppressBind = true; return node; } create(container:Container, instruction?:Object=defaultInstruction, element?:Element=null, bindings?:Binding[]=null):BehaviorInstance{ - //TODO: push host into container as DOMBoundary + let host; - var executionContext = instruction.executionContext || container.get(this.target), + if(this.elementName !== null && element){ + if(this.usesShadowDOM) { + host = element.createShadowRoot(); + }else{ + host = element; + } + + container.registerInstance(DOMBoundary, host); + } + + let executionContext = instruction.executionContext || container.get(this.target), behaviorInstance = new BehaviorInstance(this, executionContext, instruction), childBindings = this.childBindings, - viewFactory, host; + viewFactory; if(this.liftsContent){ //template controller @@ -2416,12 +2441,6 @@ export class HtmlBehaviorResource { if(element){ element.primaryBehavior = behaviorInstance; - if(this.usesShadowDOM) { - host = element.createShadowRoot(); - }else{ - host = element; - } - if(behaviorInstance.view){ if(!this.usesShadowDOM) { if(instruction.contentFactory){ @@ -3108,10 +3127,16 @@ export function useShadowDOM(target){ Decorators.configure.simpleDecorator('useShadowDOM', useShadowDOM); +function doNotProcessContent(){ + return false; +} + +//this is now deprecated in favor of the processContent decorator export function skipContentProcessing(target){ var deco = function(target){ var resource = Metadata.getOrCreateOwn(Metadata.resource, HtmlBehaviorResource, target); - resource.skipContentProcessing = true; + resource.processContent = doNotProcessContent; + console.warn('The @skipContentProcessing decorator is deprecated and will be removed in a future release. Please use @processContent(false) instead.'); }; return target ? deco(target) : deco; @@ -3119,6 +3144,15 @@ export function skipContentProcessing(target){ Decorators.configure.simpleDecorator('skipContentProcessing', skipContentProcessing); +export function processContent(processor){ + return function(target){ + var resource = Metadata.getOrCreateOwn(Metadata.resource, HtmlBehaviorResource, target); + resource.processContent = processor || doNotProcessContent; + } +} + +Decorators.configure.parameterizedDecorator('processContent', processContent); + export function containerless(target){ var deco = function(target){ var resource = Metadata.getOrCreateOwn(Metadata.resource, HtmlBehaviorResource, target); diff --git a/dist/commonjs/aurelia-templating.d.ts b/dist/commonjs/aurelia-templating.d.ts index e8da6371..f6dae63c 100644 --- a/dist/commonjs/aurelia-templating.d.ts +++ b/dist/commonjs/aurelia-templating.d.ts @@ -7,6 +7,7 @@ declare module 'aurelia-templating' { import { bindingMode, ObserverLocator, BindingExpression, Binding, ValueConverterResource, EventManager } from 'aurelia-binding'; import { TaskQueue } from 'aurelia-task-queue'; import * as LogManager from 'aurelia-logging'; + export let DOMBoundary: any; export function createTemplateFromMarkup(markup: any): any; export const animationEvent: any; export class Animator { @@ -186,7 +187,7 @@ declare module 'aurelia-templating' { contentSelectorRemoveAll(): any; } export class BoundViewFactory { - constructor(parentContainer: any, viewFactory: any, executionContext: any); + constructor(parentContainer: any, viewFactory: any, executionContext: any, partReplacements: any); create(executionContext: any): any; } export class ViewFactory { @@ -245,7 +246,7 @@ declare module 'aurelia-templating' { analyze(container: Container, target: Function): any; load(container: Container, target: Function, viewStrategy?: ViewStrategy, transientView?: boolean, loadContext?: string[]): Promise; register(registry: ResourceRegistry, name?: string): any; - compile(compiler: ViewCompiler, resources: ResourceRegistry, node?: Node, instruction?: Object, parentNode?: Node): Node; + compile(compiler: ViewCompiler, resources: ResourceRegistry, node: Node, instruction: Object, parentNode?: Node): Node; create(container: Container, instruction?: Object, element?: Element, bindings?: Binding[]): BehaviorInstance; ensurePropertiesDefined(instance: Object, lookup: Object): any; } @@ -301,7 +302,10 @@ declare module 'aurelia-templating' { export function dynamicOptions(target: any): any; export function sync(selectorOrConfig: any): any; export function useShadowDOM(target: any): any; + + // this is now deprecated in favor of the processContent decorator export function skipContentProcessing(target: any): any; + export function processContent(processor: any): any; export function containerless(target: any): any; export function viewStrategy(strategy: any): any; export function useView(path: any): any; diff --git a/dist/commonjs/index.js b/dist/commonjs/aurelia-templating.js similarity index 96% rename from dist/commonjs/index.js rename to dist/commonjs/aurelia-templating.js index 5dc6efcd..ddc1deb0 100644 --- a/dist/commonjs/index.js +++ b/dist/commonjs/aurelia-templating.js @@ -16,6 +16,7 @@ exports.dynamicOptions = dynamicOptions; exports.sync = sync; exports.useShadowDOM = useShadowDOM; exports.skipContentProcessing = skipContentProcessing; +exports.processContent = processContent; exports.containerless = containerless; exports.viewStrategy = viewStrategy; exports.useView = useView; @@ -53,6 +54,10 @@ var LogManager = _interopRequireWildcard(_aureliaLogging); var needsTemplateFixup = !('content' in document.createElement('template')); +var DOMBoundary = 'aurelia-dom-boundary'; + +exports.DOMBoundary = DOMBoundary; + function createTemplateFromMarkup(markup) { var temp = document.createElement('template'); temp.innerHTML = markup; @@ -778,6 +783,20 @@ var ContentSelector = (function () { exports.ContentSelector = ContentSelector; +function getAnimatableElement(view) { + var firstChild = view.firstChild; + + if (firstChild !== null && firstChild !== undefined && firstChild.nodeType === 8) { + var element = nextElementSibling(firstChild); + + if (element !== null && element !== undefined && element.nodeType === 1 && element.classList.contains('au-animate')) { + return element; + } + } + + return null; +} + var ViewSlot = (function () { function ViewSlot(anchor, anchorIsContainer, executionContext) { var animator = arguments[3] === undefined ? Animator.instance : arguments[3]; @@ -854,34 +873,36 @@ var ViewSlot = (function () { if (this.isAttached) { view.attached(); - var element = view.firstChild ? nextElementSibling(view.firstChild) : null; - if (view.firstChild && view.firstChild.nodeType === 8 && element && element.nodeType === 1 && element.classList.contains('au-animate')) { - this.animator.enter(element); + var animatableElement = getAnimatableElement(view); + if (animatableElement !== null) { + return this.animator.enter(animatableElement); } } }; ViewSlot.prototype.insert = function insert(index, view) { - if (index === 0 && !this.children.length || index >= this.children.length) { - this.add(view); + var children = this.children, + length = children.length; + + if (index === 0 && length === 0 || index >= length) { + return this.add(view); } else { - view.insertNodesBefore(this.children[index].firstChild); - this.children.splice(index, 0, view); + view.insertNodesBefore(children[index].firstChild); + children.splice(index, 0, view); if (this.isAttached) { view.attached(); + + var animatableElement = getAnimatableElement(view); + if (animatableElement !== null) { + return this.animator.enter(animatableElement); + } } } }; ViewSlot.prototype.remove = function remove(view) { - view.removeNodes(); - - this.children.splice(this.children.indexOf(view), 1); - - if (this.isAttached) { - view.detached(); - } + return this.removeAt(this.children.indexOf(view)); }; ViewSlot.prototype.removeAt = function removeAt(index) { @@ -900,14 +921,14 @@ var ViewSlot = (function () { return view; }; - var element = view.firstChild ? nextElementSibling(view.firstChild) : null; - if (view.firstChild && view.firstChild.nodeType === 8 && element && element.nodeType === 1 && element.classList.contains('au-animate')) { - return this.animator.leave(element).then(function () { + var animatableElement = getAnimatableElement(view); + if (animatableElement !== null) { + return this.animator.leave(animatableElement).then(function () { return removeAction(); }); - } else { - return removeAction(); } + + return removeAction(); }; ViewSlot.prototype.removeAll = function removeAll() { @@ -920,10 +941,10 @@ var ViewSlot = (function () { var rmPromises = []; children.forEach(function (child) { - var element = child.firstChild ? nextElementSibling(child.firstChild) : null; - if (child.firstChild && child.firstChild.nodeType === 8 && element && element.nodeType === 1 && element.classList.contains('au-animate')) { - rmPromises.push(_this2.animator.leave(element).then(function () { - child.removeNodes(); + var animatableElement = getAnimatableElement(child); + if (animatableElement !== null) { + rmPromises.push(_this2.animator.leave(animatableElement).then(function () { + return child.removeNodes(); })); } else { child.removeNodes(); @@ -942,7 +963,7 @@ var ViewSlot = (function () { if (rmPromises.length > 0) { return Promise.all(rmPromises).then(function () { - removeAction(); + return removeAction(); }); } else { removeAction(); @@ -953,12 +974,13 @@ var ViewSlot = (function () { var _this3 = this; var removeResponse = this.removeAll(); + if (removeResponse !== undefined) { - removeResponse.then(function () { - _this3.add(view); + return removeResponse.then(function () { + return _this3.add(view); }); } else { - this.add(view); + return this.add(view); } }; @@ -1116,8 +1138,7 @@ function elementContainerGet(key) { factory = partReplacements[factory.part] || factory; } - factory.partReplacements = partReplacements; - return this.boundViewFactory = new BoundViewFactory(this, factory, this.executionContext); + return this.boundViewFactory = new BoundViewFactory(this, factory, this.executionContext, partReplacements); } if (key === ViewSlot) { @@ -1165,7 +1186,6 @@ function makeElementIntoAnchor(element, isCustomElement) { var anchor = document.createComment('anchor'); if (isCustomElement) { - anchor.attributes = element.attributes; anchor.hasAttribute = function (name) { return element.hasAttribute(name); }; @@ -1313,13 +1333,13 @@ function applySurrogateInstruction(container, element, instruction, behaviors, b } var BoundViewFactory = (function () { - function BoundViewFactory(parentContainer, viewFactory, executionContext) { + function BoundViewFactory(parentContainer, viewFactory, executionContext, partReplacements) { _classCallCheck(this, BoundViewFactory); this.parentContainer = parentContainer; this.viewFactory = viewFactory; this.executionContext = executionContext; - this.factoryOptions = { behaviorInstance: false }; + this.factoryOptions = { behaviorInstance: false, partReplacements: partReplacements }; } BoundViewFactory.prototype.create = function create(executionContext) { @@ -1363,17 +1383,25 @@ var ViewFactory = (function () { children = [], contentSelectors = [], containers = { root: container }, - partReplacements = options.partReplacements || this.partReplacements, + partReplacements = options.partReplacements, + domBoundary = container.get(DOMBoundary), i, ii, - view; + view, + instructable, + instruction; if (element !== null && this.surrogateInstruction !== null) { applySurrogateInstruction(container, element, this.surrogateInstruction, behaviors, bindings, children); } for (i = 0, ii = instructables.length; i < ii; ++i) { - applyInstructions(containers, executionContext, instructables[i], instructions[i], behaviors, bindings, children, contentSelectors, partReplacements, resources); + instructable = instructables[i]; + instruction = instructions[instructable.getAttribute('au-target-id')]; + + instructable.domBoundary = domBoundary; + + applyInstructions(containers, executionContext, instructable, instruction, behaviors, bindings, children, contentSelectors, partReplacements, resources); } view = new View(container, fragment, behaviors, bindings, children, options.systemControlled, contentSelectors); @@ -1428,9 +1456,19 @@ function configureProperties(instruction, resources) { } } +var lastAUTargetID = 0; +function getNextAUTargetID() { + return (++lastAUTargetID).toString(); +} + function makeIntoInstructionTarget(element) { - var value = element.getAttribute('class'); + var value = element.getAttribute('class'), + auTargetID = getNextAUTargetID(); + element.setAttribute('class', value ? value += ' au-target' : 'au-target'); + element.setAttribute('au-target-id', auTargetID); + + return auTargetID; } var ViewCompiler = (function () { @@ -1447,7 +1485,7 @@ var ViewCompiler = (function () { ViewCompiler.prototype.compile = function compile(templateOrFragment, resources) { var options = arguments[2] === undefined ? defaultCompileOptions : arguments[2]; - var instructions = [], + var instructions = {}, targetShadowDOM = options.targetShadowDOM, content, part, @@ -1492,11 +1530,11 @@ var ViewCompiler = (function () { case 3: var expression = this.bindingLanguage.parseText(resources, node.wholeText); if (expression) { - var marker = document.createElement('au-marker'); - marker.className = 'au-target'; + var marker = document.createElement('au-marker'), + auTargetID = makeIntoInstructionTarget(marker); (node.parentNode || parentNode).insertBefore(marker, node); node.textContent = ' '; - instructions.push({ contentExpression: expression }); + instructions[auTargetID] = { contentExpression: expression }; while (node.nextSibling && node.nextSibling.nodeType === 3) { (node.parentNode || parentNode).removeChild(node.nextSibling); @@ -1651,7 +1689,9 @@ var ViewCompiler = (function () { instruction, info, property, - knownAttribute; + knownAttribute, + auTargetID, + injectorId; if (tagName === 'content') { if (targetLightDOM) { @@ -1760,19 +1800,19 @@ var ViewCompiler = (function () { if (liftingInstruction) { liftingInstruction.viewFactory = viewFactory; node = liftingInstruction.type.compile(this, resources, node, liftingInstruction, parentNode); - makeIntoInstructionTarget(node); - instructions.push({ + auTargetID = makeIntoInstructionTarget(node); + instructions[auTargetID] = { anchorIsContainer: false, parentInjectorId: parentInjectorId, expressions: [], behaviorInstructions: [liftingInstruction], viewFactory: liftingInstruction.viewFactory, providers: [liftingInstruction.type.target] - }); + }; } else { - var injectorId = behaviorInstructions.length ? getNextInjectorId() : false; - if (expressions.length || behaviorInstructions.length) { + injectorId = behaviorInstructions.length ? getNextInjectorId() : false; + for (i = 0, ii = behaviorInstructions.length; i < ii; ++i) { instruction = behaviorInstructions[i]; instruction.type.compile(this, resources, node, instruction, parentNode); @@ -1786,9 +1826,8 @@ var ViewCompiler = (function () { } } - makeIntoInstructionTarget(node); - - instructions.push({ + auTargetID = makeIntoInstructionTarget(node); + instructions[auTargetID] = { anchorIsContainer: elementInstruction ? elementInstruction.anchorIsContainer : true, isCustomElement: !!elementInstruction, injectorId: injectorId, @@ -1796,7 +1835,7 @@ var ViewCompiler = (function () { expressions: expressions, behaviorInstructions: behaviorInstructions, providers: providers - }); + }; } if (elementInstruction && elementInstruction.type.skipContentProcessing) { @@ -2385,6 +2424,10 @@ var defaultInstruction = { suppressBind: false }, contentSelectorFactoryOptions = { suppressBind: true }, hasShadowDOM = !!HTMLElement.prototype.createShadowRoot; +function doProcessContent() { + return true; +} + var HtmlBehaviorResource = (function () { function HtmlBehaviorResource() { _classCallCheck(this, HtmlBehaviorResource); @@ -2394,7 +2437,7 @@ var HtmlBehaviorResource = (function () { this.attributeDefaultBindingMode = undefined; this.liftsContent = false; this.targetShadowDOM = false; - this.skipContentProcessing = false; + this.processContent = doProcessContent; this.usesShadowDOM = false; this.childBindings = null; this.hasDynamicOptions = false; @@ -2555,9 +2598,9 @@ var HtmlBehaviorResource = (function () { node = template; } } else if (this.elementName !== null) { - var partReplacements = {}; + var partReplacements = instruction.partReplacements = {}; - if (!this.skipContentProcessing && node.hasChildNodes()) { + if (this.processContent(compiler, resources, node, instruction) && node.hasChildNodes()) { if (!this.usesShadowDOM) { var fragment = document.createDocumentFragment(), currentChild = node.firstChild, @@ -2594,7 +2637,6 @@ var HtmlBehaviorResource = (function () { } } - instruction.partReplacements = partReplacements; instruction.suppressBind = true; return node; }; @@ -2604,11 +2646,22 @@ var HtmlBehaviorResource = (function () { var element = arguments[2] === undefined ? null : arguments[2]; var bindings = arguments[3] === undefined ? null : arguments[3]; + var host = undefined; + + if (this.elementName !== null && element) { + if (this.usesShadowDOM) { + host = element.createShadowRoot(); + } else { + host = element; + } + + container.registerInstance(DOMBoundary, host); + } + var executionContext = instruction.executionContext || container.get(this.target), behaviorInstance = new BehaviorInstance(this, executionContext, instruction), childBindings = this.childBindings, - viewFactory, - host; + viewFactory = undefined; if (this.liftsContent) { element.primaryBehavior = behaviorInstance; @@ -2622,12 +2675,6 @@ var HtmlBehaviorResource = (function () { if (element) { element.primaryBehavior = behaviorInstance; - if (this.usesShadowDOM) { - host = element.createShadowRoot(); - } else { - host = element; - } - if (behaviorInstance.view) { if (!this.usesShadowDOM) { if (instruction.contentFactory) { @@ -3375,10 +3422,15 @@ function useShadowDOM(target) { _aureliaMetadata.Decorators.configure.simpleDecorator('useShadowDOM', useShadowDOM); +function doNotProcessContent() { + return false; +} + function skipContentProcessing(target) { var deco = function deco(target) { var resource = _aureliaMetadata.Metadata.getOrCreateOwn(_aureliaMetadata.Metadata.resource, HtmlBehaviorResource, target); - resource.skipContentProcessing = true; + resource.processContent = doNotProcessContent; + console.warn('The @skipContentProcessing decorator is deprecated and will be removed in a future release. Please use @processContent(false) instead.'); }; return target ? deco(target) : deco; @@ -3386,6 +3438,15 @@ function skipContentProcessing(target) { _aureliaMetadata.Decorators.configure.simpleDecorator('skipContentProcessing', skipContentProcessing); +function processContent(processor) { + return function (target) { + var resource = _aureliaMetadata.Metadata.getOrCreateOwn(_aureliaMetadata.Metadata.resource, HtmlBehaviorResource, target); + resource.processContent = processor || doNotProcessContent; + }; +} + +_aureliaMetadata.Decorators.configure.parameterizedDecorator('processContent', processContent); + function containerless(target) { var deco = function deco(target) { var resource = _aureliaMetadata.Metadata.getOrCreateOwn(_aureliaMetadata.Metadata.resource, HtmlBehaviorResource, target); diff --git a/dist/es6/aurelia-templating.d.ts b/dist/es6/aurelia-templating.d.ts index e8da6371..f6dae63c 100644 --- a/dist/es6/aurelia-templating.d.ts +++ b/dist/es6/aurelia-templating.d.ts @@ -7,6 +7,7 @@ declare module 'aurelia-templating' { import { bindingMode, ObserverLocator, BindingExpression, Binding, ValueConverterResource, EventManager } from 'aurelia-binding'; import { TaskQueue } from 'aurelia-task-queue'; import * as LogManager from 'aurelia-logging'; + export let DOMBoundary: any; export function createTemplateFromMarkup(markup: any): any; export const animationEvent: any; export class Animator { @@ -186,7 +187,7 @@ declare module 'aurelia-templating' { contentSelectorRemoveAll(): any; } export class BoundViewFactory { - constructor(parentContainer: any, viewFactory: any, executionContext: any); + constructor(parentContainer: any, viewFactory: any, executionContext: any, partReplacements: any); create(executionContext: any): any; } export class ViewFactory { @@ -245,7 +246,7 @@ declare module 'aurelia-templating' { analyze(container: Container, target: Function): any; load(container: Container, target: Function, viewStrategy?: ViewStrategy, transientView?: boolean, loadContext?: string[]): Promise; register(registry: ResourceRegistry, name?: string): any; - compile(compiler: ViewCompiler, resources: ResourceRegistry, node?: Node, instruction?: Object, parentNode?: Node): Node; + compile(compiler: ViewCompiler, resources: ResourceRegistry, node: Node, instruction: Object, parentNode?: Node): Node; create(container: Container, instruction?: Object, element?: Element, bindings?: Binding[]): BehaviorInstance; ensurePropertiesDefined(instance: Object, lookup: Object): any; } @@ -301,7 +302,10 @@ declare module 'aurelia-templating' { export function dynamicOptions(target: any): any; export function sync(selectorOrConfig: any): any; export function useShadowDOM(target: any): any; + + // this is now deprecated in favor of the processContent decorator export function skipContentProcessing(target: any): any; + export function processContent(processor: any): any; export function containerless(target: any): any; export function viewStrategy(strategy: any): any; export function useView(path: any): any; diff --git a/dist/index.js b/dist/es6/aurelia-templating.js similarity index 95% rename from dist/index.js rename to dist/es6/aurelia-templating.js index f8f11db2..002f8688 100644 --- a/dist/index.js +++ b/dist/es6/aurelia-templating.js @@ -8,6 +8,8 @@ import {TaskQueue} from 'aurelia-task-queue'; let needsTemplateFixup = !('content' in document.createElement('template')); +export let DOMBoundary = 'aurelia-dom-boundary'; + export function createTemplateFromMarkup(markup){ let temp = document.createElement('template'); temp.innerHTML = markup; @@ -686,6 +688,22 @@ export class ContentSelector { } } +function getAnimatableElement(view){ + let firstChild = view.firstChild; + + if(firstChild !== null && firstChild !== undefined && firstChild.nodeType === 8){ + let element = nextElementSibling(firstChild); + + if(element !== null && element !== undefined && + element.nodeType === 1 && + element.classList.contains('au-animate')) { + return element; + } + } + + return null; +} + export class ViewSlot { constructor(anchor, anchorIsContainer, executionContext, animator=Animator.instance){ this.anchor = anchor; @@ -755,39 +773,37 @@ export class ViewSlot { if(this.isAttached){ view.attached(); - // Animate page itself - var element = view.firstChild ? nextElementSibling(view.firstChild) : null; - if(view.firstChild && - view.firstChild.nodeType === 8 && - element && - element.nodeType === 1 && - element.classList.contains('au-animate')) { - this.animator.enter(element); + + let animatableElement = getAnimatableElement(view); + if(animatableElement !== null){ + return this.animator.enter(animatableElement); } } } insert(index, view){ - if((index === 0 && !this.children.length) || index >= this.children.length){ - this.add(view); + let children = this.children, + length = children.length; + + if((index === 0 && length === 0) || index >= length){ + return this.add(view); } else{ - view.insertNodesBefore(this.children[index].firstChild); - this.children.splice(index, 0, view); + view.insertNodesBefore(children[index].firstChild); + children.splice(index, 0, view); if(this.isAttached){ view.attached(); + + let animatableElement = getAnimatableElement(view); + if(animatableElement !== null){ + return this.animator.enter(animatableElement); + } } } } remove(view){ - view.removeNodes(); - - this.children.splice(this.children.indexOf(view), 1); - - if(this.isAttached){ - view.detached(); - } + return this.removeAt(this.children.indexOf(view)); } removeAt(index){ @@ -804,18 +820,12 @@ export class ViewSlot { return view; }; - var element = view.firstChild ? nextElementSibling(view.firstChild) : null; - if(view.firstChild && - view.firstChild.nodeType === 8 && - element && - element.nodeType === 1 && - element.classList.contains('au-animate')) { - return this.animator.leave(element).then( () => { - return removeAction(); - }) - } else { - return removeAction(); + let animatableElement = getAnimatableElement(view); + if(animatableElement !== null){ + return this.animator.leave(animatableElement).then(() => removeAction()); } + + return removeAction(); } removeAll(){ @@ -826,15 +836,9 @@ export class ViewSlot { var rmPromises = []; children.forEach(child => { - var element = child.firstChild ? nextElementSibling(child.firstChild) : null; - if(child.firstChild && - child.firstChild.nodeType === 8 && - element && - element.nodeType === 1 && - element.classList.contains('au-animate')) { - rmPromises.push(this.animator.leave(element).then(() => { - child.removeNodes(); - })); + let animatableElement = getAnimatableElement(child); + if(animatableElement !== null){ + rmPromises.push(this.animator.leave(animatableElement).then(() => child.removeNodes())); } else { child.removeNodes(); } @@ -851,9 +855,7 @@ export class ViewSlot { }; if(rmPromises.length > 0) { - return Promise.all(rmPromises).then(() => { - removeAction(); - }); + return Promise.all(rmPromises).then(() => removeAction()); } else { removeAction(); } @@ -861,12 +863,11 @@ export class ViewSlot { swap(view){ var removeResponse = this.removeAll(); + if(removeResponse !== undefined) { - removeResponse.then(() => { - this.add(view); - }); + return removeResponse.then(() => this.add(view)); } else { - this.add(view); + return this.add(view); } } @@ -1024,8 +1025,7 @@ function elementContainerGet(key){ factory = partReplacements[factory.part] || factory; } - factory.partReplacements = partReplacements; - return this.boundViewFactory = new BoundViewFactory(this, factory, this.executionContext); + return this.boundViewFactory = new BoundViewFactory(this, factory, this.executionContext, partReplacements); } if(key === ViewSlot){ @@ -1073,7 +1073,6 @@ function makeElementIntoAnchor(element, isCustomElement){ var anchor = document.createComment('anchor'); if(isCustomElement){ - anchor.attributes = element.attributes; anchor.hasAttribute = function(name) { return element.hasAttribute(name); }; anchor.getAttribute = function(name){ return element.getAttribute(name); }; anchor.setAttribute = function(name, value) { element.setAttribute(name, value); }; @@ -1220,11 +1219,11 @@ function applySurrogateInstruction(container, element, instruction, behaviors, b } export class BoundViewFactory { - constructor(parentContainer, viewFactory, executionContext){ + constructor(parentContainer, viewFactory, executionContext, partReplacements){ this.parentContainer = parentContainer; this.viewFactory = viewFactory; this.executionContext = executionContext; - this.factoryOptions = { behaviorInstance:false }; + this.factoryOptions = { behaviorInstance:false, partReplacements:partReplacements }; } create(executionContext){ @@ -1259,18 +1258,22 @@ export class ViewFactory{ children = [], contentSelectors = [], containers = { root:container }, - partReplacements = options.partReplacements || this.partReplacements, - i, ii, view; + partReplacements = options.partReplacements, + domBoundary = container.get(DOMBoundary), + i, ii, view, instructable, instruction; if(element !== null && this.surrogateInstruction !== null){ applySurrogateInstruction(container, element, this.surrogateInstruction, behaviors, bindings, children); } - //TODO: get DOMBoundary from container; attach to instructable to be picked up by delegated events - for(i = 0, ii = instructables.length; i < ii; ++i){ - applyInstructions(containers, executionContext, instructables[i], - instructions[i], behaviors, bindings, children, contentSelectors, partReplacements, resources); + instructable = instructables[i]; + instruction = instructions[instructable.getAttribute('au-target-id')]; + + instructable.domBoundary = domBoundary; + + applyInstructions(containers, executionContext, instructable, + instruction, behaviors, bindings, children, contentSelectors, partReplacements, resources); } view = new View(container, fragment, behaviors, bindings, children, options.systemControlled, contentSelectors); @@ -1319,9 +1322,19 @@ function configureProperties(instruction, resources){ } } +let lastAUTargetID = 0; +function getNextAUTargetID(){ + return (++lastAUTargetID).toString(); +} + function makeIntoInstructionTarget(element){ - var value = element.getAttribute('class'); + let value = element.getAttribute('class'), + auTargetID = getNextAUTargetID(); + element.setAttribute('class', (value ? value += ' au-target' : 'au-target')); + element.setAttribute('au-target-id', auTargetID); + + return auTargetID; } export class ViewCompiler { @@ -1331,7 +1344,7 @@ export class ViewCompiler { } compile(templateOrFragment, resources, options=defaultCompileOptions){ - var instructions = [], + var instructions = {}, targetShadowDOM = options.targetShadowDOM, content, part, factory; @@ -1375,11 +1388,11 @@ export class ViewCompiler { //use wholeText to retrieve the textContent of all adjacent text nodes. var expression = this.bindingLanguage.parseText(resources, node.wholeText); if(expression){ - var marker = document.createElement('au-marker'); - marker.className = 'au-target'; + let marker = document.createElement('au-marker'), + auTargetID = makeIntoInstructionTarget(marker); (node.parentNode || parentNode).insertBefore(marker, node); node.textContent = ' '; - instructions.push({ contentExpression:expression }); + instructions[auTargetID] = { contentExpression:expression }; //remove adjacent text nodes. while(node.nextSibling && node.nextSibling.nodeType === 3) { (node.parentNode || parentNode).removeChild(node.nextSibling); @@ -1513,7 +1526,7 @@ export class ViewCompiler { bindingLanguage = this.bindingLanguage, liftingInstruction, viewFactory, type, elementInstruction, elementProperty, i, ii, attr, attrName, attrValue, instruction, info, - property, knownAttribute; + property, knownAttribute, auTargetID, injectorId; if(tagName === 'content'){ if(targetLightDOM){ @@ -1624,19 +1637,19 @@ export class ViewCompiler { if(liftingInstruction){ liftingInstruction.viewFactory = viewFactory; node = liftingInstruction.type.compile(this, resources, node, liftingInstruction, parentNode); - makeIntoInstructionTarget(node); - instructions.push({ + auTargetID = makeIntoInstructionTarget(node); + instructions[auTargetID] = { anchorIsContainer: false, parentInjectorId: parentInjectorId, expressions: [], behaviorInstructions: [liftingInstruction], viewFactory: liftingInstruction.viewFactory, providers: [liftingInstruction.type.target] - }); + }; }else{ - var injectorId = behaviorInstructions.length ? getNextInjectorId() : false; - if(expressions.length || behaviorInstructions.length){ + injectorId = behaviorInstructions.length ? getNextInjectorId() : false; + for(i = 0, ii = behaviorInstructions.length; i < ii; ++i){ instruction = behaviorInstructions[i]; instruction.type.compile(this, resources, node, instruction, parentNode); @@ -1650,9 +1663,8 @@ export class ViewCompiler { } } - makeIntoInstructionTarget(node); - - instructions.push({ + auTargetID = makeIntoInstructionTarget(node); + instructions[auTargetID] = { anchorIsContainer: elementInstruction ? elementInstruction.anchorIsContainer : true, isCustomElement: !!elementInstruction, injectorId: injectorId, @@ -1660,7 +1672,7 @@ export class ViewCompiler { expressions: expressions, behaviorInstructions: behaviorInstructions, providers: providers - }); + }; } if(elementInstruction && elementInstruction.type.skipContentProcessing){ @@ -2186,6 +2198,10 @@ var defaultInstruction = { suppressBind:false }, contentSelectorFactoryOptions = { suppressBind:true }, hasShadowDOM = !!HTMLElement.prototype.createShadowRoot; +function doProcessContent(){ + return true; +} + export class HtmlBehaviorResource { constructor(){ this.elementName = null; @@ -2193,7 +2209,7 @@ export class HtmlBehaviorResource { this.attributeDefaultBindingMode = undefined; this.liftsContent = false; this.targetShadowDOM = false; - this.skipContentProcessing = false; + this.processContent = doProcessContent; this.usesShadowDOM = false; this.childBindings = null; this.hasDynamicOptions = false; @@ -2320,7 +2336,7 @@ export class HtmlBehaviorResource { } } - compile(compiler:ViewCompiler, resources:ResourceRegistry, node?:Node, instruction?:Object, parentNode?:Node):Node{ + compile(compiler:ViewCompiler, resources:ResourceRegistry, node:Node, instruction:Object, parentNode?:Node):Node{ if(this.liftsContent){ if(!instruction.viewFactory){ var template = document.createElement('template'), @@ -2351,9 +2367,9 @@ export class HtmlBehaviorResource { node = template; } } else if(this.elementName !== null){ //custom element - var partReplacements = {}; + var partReplacements = instruction.partReplacements = {}; - if(!this.skipContentProcessing && node.hasChildNodes()){ + if(this.processContent(compiler, resources, node, instruction) && node.hasChildNodes()){ if(!this.usesShadowDOM){ var fragment = document.createDocumentFragment(), currentChild = node.firstChild, @@ -2389,18 +2405,27 @@ export class HtmlBehaviorResource { } } - instruction.partReplacements = partReplacements; instruction.suppressBind = true; return node; } create(container:Container, instruction?:Object=defaultInstruction, element?:Element=null, bindings?:Binding[]=null):BehaviorInstance{ - //TODO: push host into container as DOMBoundary + let host; - var executionContext = instruction.executionContext || container.get(this.target), + if(this.elementName !== null && element){ + if(this.usesShadowDOM) { + host = element.createShadowRoot(); + }else{ + host = element; + } + + container.registerInstance(DOMBoundary, host); + } + + let executionContext = instruction.executionContext || container.get(this.target), behaviorInstance = new BehaviorInstance(this, executionContext, instruction), childBindings = this.childBindings, - viewFactory, host; + viewFactory; if(this.liftsContent){ //template controller @@ -2416,12 +2441,6 @@ export class HtmlBehaviorResource { if(element){ element.primaryBehavior = behaviorInstance; - if(this.usesShadowDOM) { - host = element.createShadowRoot(); - }else{ - host = element; - } - if(behaviorInstance.view){ if(!this.usesShadowDOM) { if(instruction.contentFactory){ @@ -3108,10 +3127,16 @@ export function useShadowDOM(target){ Decorators.configure.simpleDecorator('useShadowDOM', useShadowDOM); +function doNotProcessContent(){ + return false; +} + +//this is now deprecated in favor of the processContent decorator export function skipContentProcessing(target){ var deco = function(target){ var resource = Metadata.getOrCreateOwn(Metadata.resource, HtmlBehaviorResource, target); - resource.skipContentProcessing = true; + resource.processContent = doNotProcessContent; + console.warn('The @skipContentProcessing decorator is deprecated and will be removed in a future release. Please use @processContent(false) instead.'); }; return target ? deco(target) : deco; @@ -3119,6 +3144,15 @@ export function skipContentProcessing(target){ Decorators.configure.simpleDecorator('skipContentProcessing', skipContentProcessing); +export function processContent(processor){ + return function(target){ + var resource = Metadata.getOrCreateOwn(Metadata.resource, HtmlBehaviorResource, target); + resource.processContent = processor || doNotProcessContent; + } +} + +Decorators.configure.parameterizedDecorator('processContent', processContent); + export function containerless(target){ var deco = function(target){ var resource = Metadata.getOrCreateOwn(Metadata.resource, HtmlBehaviorResource, target); diff --git a/dist/system/aurelia-templating.d.ts b/dist/system/aurelia-templating.d.ts index e8da6371..f6dae63c 100644 --- a/dist/system/aurelia-templating.d.ts +++ b/dist/system/aurelia-templating.d.ts @@ -7,6 +7,7 @@ declare module 'aurelia-templating' { import { bindingMode, ObserverLocator, BindingExpression, Binding, ValueConverterResource, EventManager } from 'aurelia-binding'; import { TaskQueue } from 'aurelia-task-queue'; import * as LogManager from 'aurelia-logging'; + export let DOMBoundary: any; export function createTemplateFromMarkup(markup: any): any; export const animationEvent: any; export class Animator { @@ -186,7 +187,7 @@ declare module 'aurelia-templating' { contentSelectorRemoveAll(): any; } export class BoundViewFactory { - constructor(parentContainer: any, viewFactory: any, executionContext: any); + constructor(parentContainer: any, viewFactory: any, executionContext: any, partReplacements: any); create(executionContext: any): any; } export class ViewFactory { @@ -245,7 +246,7 @@ declare module 'aurelia-templating' { analyze(container: Container, target: Function): any; load(container: Container, target: Function, viewStrategy?: ViewStrategy, transientView?: boolean, loadContext?: string[]): Promise; register(registry: ResourceRegistry, name?: string): any; - compile(compiler: ViewCompiler, resources: ResourceRegistry, node?: Node, instruction?: Object, parentNode?: Node): Node; + compile(compiler: ViewCompiler, resources: ResourceRegistry, node: Node, instruction: Object, parentNode?: Node): Node; create(container: Container, instruction?: Object, element?: Element, bindings?: Binding[]): BehaviorInstance; ensurePropertiesDefined(instance: Object, lookup: Object): any; } @@ -301,7 +302,10 @@ declare module 'aurelia-templating' { export function dynamicOptions(target: any): any; export function sync(selectorOrConfig: any): any; export function useShadowDOM(target: any): any; + + // this is now deprecated in favor of the processContent decorator export function skipContentProcessing(target: any): any; + export function processContent(processor: any): any; export function containerless(target: any): any; export function viewStrategy(strategy: any): any; export function useView(path: any): any; diff --git a/dist/system/index.js b/dist/system/aurelia-templating.js similarity index 95% rename from dist/system/index.js rename to dist/system/aurelia-templating.js index ccd18c82..733bc89e 100644 --- a/dist/system/index.js +++ b/dist/system/aurelia-templating.js @@ -1,7 +1,7 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-task-queue', 'aurelia-logging'], function (_export) { 'use strict'; - var core, Metadata, Origin, Decorators, relativeToFile, TemplateRegistryEntry, Loader, Container, bindingMode, ObserverLocator, BindingExpression, Binding, ValueConverterResource, EventManager, TaskQueue, LogManager, needsTemplateFixup, animationEvent, Animator, capitalMatcher, ViewStrategy, UseViewStrategy, ConventionalViewStrategy, NoViewStrategy, TemplateRegistryViewStrategy, InlineViewStrategy, BindingLanguage, ResourceRegistry, ViewResources, View, proto, placeholder, ContentSelector, ViewSlot, BoundViewFactory, defaultFactoryOptions, ViewFactory, nextInjectorId, defaultCompileOptions, hasShadowDOM, ViewCompiler, logger, ProxyViewFactory, ViewEngine, BehaviorInstance, BindableProperty, BehaviorPropertyObserver, defaultInstruction, contentSelectorFactoryOptions, hasShadowDOM, HtmlBehaviorResource, ResourceModule, ResourceDescription, ModuleAnalyzer, noMutations, ChildObserver, ChildObserverBinder, CompositionEngine, ElementConfigResource; + var core, Metadata, Origin, Decorators, relativeToFile, TemplateRegistryEntry, Loader, Container, bindingMode, ObserverLocator, BindingExpression, Binding, ValueConverterResource, EventManager, TaskQueue, LogManager, needsTemplateFixup, DOMBoundary, animationEvent, Animator, capitalMatcher, ViewStrategy, UseViewStrategy, ConventionalViewStrategy, NoViewStrategy, TemplateRegistryViewStrategy, InlineViewStrategy, BindingLanguage, ResourceRegistry, ViewResources, View, proto, placeholder, ContentSelector, ViewSlot, BoundViewFactory, defaultFactoryOptions, ViewFactory, nextInjectorId, defaultCompileOptions, hasShadowDOM, lastAUTargetID, ViewCompiler, logger, ProxyViewFactory, ViewEngine, BehaviorInstance, BindableProperty, BehaviorPropertyObserver, defaultInstruction, contentSelectorFactoryOptions, hasShadowDOM, HtmlBehaviorResource, ResourceModule, ResourceDescription, ModuleAnalyzer, noMutations, ChildObserver, ChildObserverBinder, CompositionEngine, ElementConfigResource; var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); @@ -29,6 +29,8 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' _export('skipContentProcessing', skipContentProcessing); + _export('processContent', processContent); + _export('containerless', containerless); _export('viewStrategy', viewStrategy); @@ -105,6 +107,20 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' return insertionPoint; } + function getAnimatableElement(view) { + var firstChild = view.firstChild; + + if (firstChild !== null && firstChild !== undefined && firstChild.nodeType === 8) { + var element = nextElementSibling(firstChild); + + if (element !== null && element !== undefined && element.nodeType === 1 && element.classList.contains('au-animate')) { + return element; + } + } + + return null; + } + function elementContainerGet(key) { if (key === Element) { return this.element; @@ -122,8 +138,7 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' factory = partReplacements[factory.part] || factory; } - factory.partReplacements = partReplacements; - return this.boundViewFactory = new BoundViewFactory(this, factory, this.executionContext); + return this.boundViewFactory = new BoundViewFactory(this, factory, this.executionContext, partReplacements); } if (key === ViewSlot) { @@ -171,7 +186,6 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' var anchor = document.createComment('anchor'); if (isCustomElement) { - anchor.attributes = element.attributes; anchor.hasAttribute = function (name) { return element.hasAttribute(name); }; @@ -351,9 +365,18 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' } } + function getNextAUTargetID() { + return (++lastAUTargetID).toString(); + } + function makeIntoInstructionTarget(element) { - var value = element.getAttribute('class'); + var value = element.getAttribute('class'), + auTargetID = getNextAUTargetID(); + element.setAttribute('class', value ? value += ' au-target' : 'au-target'); + element.setAttribute('au-target-id', auTargetID); + + return auTargetID; } function ensureRegistryEntry(loader, urlOrRegistryEntry) { @@ -375,6 +398,10 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' return lookup[name]; } + function doProcessContent() { + return true; + } + function validateBehaviorName(name, type) { if (/[A-Z]/.test(name)) { throw new Error('\'' + name + '\' is not a valid ' + type + ' name. Upper-case letters are not allowed because the DOM is not case-sensitive.'); @@ -480,15 +507,27 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' return target ? deco(target) : deco; } + function doNotProcessContent() { + return false; + } + function skipContentProcessing(target) { var deco = function deco(target) { var resource = Metadata.getOrCreateOwn(Metadata.resource, HtmlBehaviorResource, target); - resource.skipContentProcessing = true; + resource.processContent = doNotProcessContent; + console.warn('The @skipContentProcessing decorator is deprecated and will be removed in a future release. Please use @processContent(false) instead.'); }; return target ? deco(target) : deco; } + function processContent(processor) { + return function (target) { + var resource = Metadata.getOrCreateOwn(Metadata.resource, HtmlBehaviorResource, target); + resource.processContent = processor || doNotProcessContent; + }; + } + function containerless(target) { var deco = function deco(target) { var resource = Metadata.getOrCreateOwn(Metadata.resource, HtmlBehaviorResource, target); @@ -556,6 +595,10 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' }], execute: function () { needsTemplateFixup = !('content' in document.createElement('template')); + DOMBoundary = 'aurelia-dom-boundary'; + + _export('DOMBoundary', DOMBoundary); + animationEvent = { enterBegin: 'animation:enter:begin', enterActive: 'animation:enter:active', @@ -1298,34 +1341,36 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' if (this.isAttached) { view.attached(); - var element = view.firstChild ? nextElementSibling(view.firstChild) : null; - if (view.firstChild && view.firstChild.nodeType === 8 && element && element.nodeType === 1 && element.classList.contains('au-animate')) { - this.animator.enter(element); + var animatableElement = getAnimatableElement(view); + if (animatableElement !== null) { + return this.animator.enter(animatableElement); } } }; ViewSlot.prototype.insert = function insert(index, view) { - if (index === 0 && !this.children.length || index >= this.children.length) { - this.add(view); + var children = this.children, + length = children.length; + + if (index === 0 && length === 0 || index >= length) { + return this.add(view); } else { - view.insertNodesBefore(this.children[index].firstChild); - this.children.splice(index, 0, view); + view.insertNodesBefore(children[index].firstChild); + children.splice(index, 0, view); if (this.isAttached) { view.attached(); + + var animatableElement = getAnimatableElement(view); + if (animatableElement !== null) { + return this.animator.enter(animatableElement); + } } } }; ViewSlot.prototype.remove = function remove(view) { - view.removeNodes(); - - this.children.splice(this.children.indexOf(view), 1); - - if (this.isAttached) { - view.detached(); - } + return this.removeAt(this.children.indexOf(view)); }; ViewSlot.prototype.removeAt = function removeAt(index) { @@ -1344,14 +1389,14 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' return view; }; - var element = view.firstChild ? nextElementSibling(view.firstChild) : null; - if (view.firstChild && view.firstChild.nodeType === 8 && element && element.nodeType === 1 && element.classList.contains('au-animate')) { - return this.animator.leave(element).then(function () { + var animatableElement = getAnimatableElement(view); + if (animatableElement !== null) { + return this.animator.leave(animatableElement).then(function () { return removeAction(); }); - } else { - return removeAction(); } + + return removeAction(); }; ViewSlot.prototype.removeAll = function removeAll() { @@ -1364,10 +1409,10 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' var rmPromises = []; children.forEach(function (child) { - var element = child.firstChild ? nextElementSibling(child.firstChild) : null; - if (child.firstChild && child.firstChild.nodeType === 8 && element && element.nodeType === 1 && element.classList.contains('au-animate')) { - rmPromises.push(_this2.animator.leave(element).then(function () { - child.removeNodes(); + var animatableElement = getAnimatableElement(child); + if (animatableElement !== null) { + rmPromises.push(_this2.animator.leave(animatableElement).then(function () { + return child.removeNodes(); })); } else { child.removeNodes(); @@ -1386,7 +1431,7 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' if (rmPromises.length > 0) { return Promise.all(rmPromises).then(function () { - removeAction(); + return removeAction(); }); } else { removeAction(); @@ -1397,12 +1442,13 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' var _this3 = this; var removeResponse = this.removeAll(); + if (removeResponse !== undefined) { - removeResponse.then(function () { - _this3.add(view); + return removeResponse.then(function () { + return _this3.add(view); }); } else { - this.add(view); + return this.add(view); } }; @@ -1544,13 +1590,13 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' _export('ViewSlot', ViewSlot); BoundViewFactory = (function () { - function BoundViewFactory(parentContainer, viewFactory, executionContext) { + function BoundViewFactory(parentContainer, viewFactory, executionContext, partReplacements) { _classCallCheck(this, BoundViewFactory); this.parentContainer = parentContainer; this.viewFactory = viewFactory; this.executionContext = executionContext; - this.factoryOptions = { behaviorInstance: false }; + this.factoryOptions = { behaviorInstance: false, partReplacements: partReplacements }; } BoundViewFactory.prototype.create = function create(executionContext) { @@ -1594,17 +1640,25 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' children = [], contentSelectors = [], containers = { root: container }, - partReplacements = options.partReplacements || this.partReplacements, + partReplacements = options.partReplacements, + domBoundary = container.get(DOMBoundary), i, ii, - view; + view, + instructable, + instruction; if (element !== null && this.surrogateInstruction !== null) { applySurrogateInstruction(container, element, this.surrogateInstruction, behaviors, bindings, children); } for (i = 0, ii = instructables.length; i < ii; ++i) { - applyInstructions(containers, executionContext, instructables[i], instructions[i], behaviors, bindings, children, contentSelectors, partReplacements, resources); + instructable = instructables[i]; + instruction = instructions[instructable.getAttribute('au-target-id')]; + + instructable.domBoundary = domBoundary; + + applyInstructions(containers, executionContext, instructable, instruction, behaviors, bindings, children, contentSelectors, partReplacements, resources); } view = new View(container, fragment, behaviors, bindings, children, options.systemControlled, contentSelectors); @@ -1625,6 +1679,7 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' nextInjectorId = 0; defaultCompileOptions = { targetShadowDOM: false }; hasShadowDOM = !!HTMLElement.prototype.createShadowRoot; + lastAUTargetID = 0; ViewCompiler = (function () { function ViewCompiler(bindingLanguage) { @@ -1640,7 +1695,7 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' ViewCompiler.prototype.compile = function compile(templateOrFragment, resources) { var options = arguments[2] === undefined ? defaultCompileOptions : arguments[2]; - var instructions = [], + var instructions = {}, targetShadowDOM = options.targetShadowDOM, content, part, @@ -1685,11 +1740,11 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' case 3: var expression = this.bindingLanguage.parseText(resources, node.wholeText); if (expression) { - var marker = document.createElement('au-marker'); - marker.className = 'au-target'; + var marker = document.createElement('au-marker'), + auTargetID = makeIntoInstructionTarget(marker); (node.parentNode || parentNode).insertBefore(marker, node); node.textContent = ' '; - instructions.push({ contentExpression: expression }); + instructions[auTargetID] = { contentExpression: expression }; while (node.nextSibling && node.nextSibling.nodeType === 3) { (node.parentNode || parentNode).removeChild(node.nextSibling); @@ -1844,7 +1899,9 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' instruction, info, property, - knownAttribute; + knownAttribute, + auTargetID, + injectorId; if (tagName === 'content') { if (targetLightDOM) { @@ -1953,19 +2010,19 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' if (liftingInstruction) { liftingInstruction.viewFactory = viewFactory; node = liftingInstruction.type.compile(this, resources, node, liftingInstruction, parentNode); - makeIntoInstructionTarget(node); - instructions.push({ + auTargetID = makeIntoInstructionTarget(node); + instructions[auTargetID] = { anchorIsContainer: false, parentInjectorId: parentInjectorId, expressions: [], behaviorInstructions: [liftingInstruction], viewFactory: liftingInstruction.viewFactory, providers: [liftingInstruction.type.target] - }); + }; } else { - var injectorId = behaviorInstructions.length ? getNextInjectorId() : false; - if (expressions.length || behaviorInstructions.length) { + injectorId = behaviorInstructions.length ? getNextInjectorId() : false; + for (i = 0, ii = behaviorInstructions.length; i < ii; ++i) { instruction = behaviorInstructions[i]; instruction.type.compile(this, resources, node, instruction, parentNode); @@ -1979,9 +2036,8 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' } } - makeIntoInstructionTarget(node); - - instructions.push({ + auTargetID = makeIntoInstructionTarget(node); + instructions[auTargetID] = { anchorIsContainer: elementInstruction ? elementInstruction.anchorIsContainer : true, isCustomElement: !!elementInstruction, injectorId: injectorId, @@ -1989,7 +2045,7 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' expressions: expressions, behaviorInstructions: behaviorInstructions, providers: providers - }); + }; } if (elementInstruction && elementInstruction.type.skipContentProcessing) { @@ -2568,7 +2624,7 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' this.attributeDefaultBindingMode = undefined; this.liftsContent = false; this.targetShadowDOM = false; - this.skipContentProcessing = false; + this.processContent = doProcessContent; this.usesShadowDOM = false; this.childBindings = null; this.hasDynamicOptions = false; @@ -2729,9 +2785,9 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' node = template; } } else if (this.elementName !== null) { - var partReplacements = {}; + var partReplacements = instruction.partReplacements = {}; - if (!this.skipContentProcessing && node.hasChildNodes()) { + if (this.processContent(compiler, resources, node, instruction) && node.hasChildNodes()) { if (!this.usesShadowDOM) { var fragment = document.createDocumentFragment(), currentChild = node.firstChild, @@ -2768,7 +2824,6 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' } } - instruction.partReplacements = partReplacements; instruction.suppressBind = true; return node; }; @@ -2778,11 +2833,22 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' var element = arguments[2] === undefined ? null : arguments[2]; var bindings = arguments[3] === undefined ? null : arguments[3]; + var host = undefined; + + if (this.elementName !== null && element) { + if (this.usesShadowDOM) { + host = element.createShadowRoot(); + } else { + host = element; + } + + container.registerInstance(DOMBoundary, host); + } + var executionContext = instruction.executionContext || container.get(this.target), behaviorInstance = new BehaviorInstance(this, executionContext, instruction), childBindings = this.childBindings, - viewFactory, - host; + viewFactory = undefined; if (this.liftsContent) { element.primaryBehavior = behaviorInstance; @@ -2796,12 +2862,6 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' if (element) { element.primaryBehavior = behaviorInstance; - if (this.usesShadowDOM) { - host = element.createShadowRoot(); - } else { - host = element; - } - if (behaviorInstance.view) { if (!this.usesShadowDOM) { if (instruction.contentFactory) { @@ -3446,6 +3506,8 @@ System.register(['core-js', 'aurelia-metadata', 'aurelia-path', 'aurelia-loader' Decorators.configure.simpleDecorator('skipContentProcessing', skipContentProcessing); + Decorators.configure.parameterizedDecorator('processContent', processContent); + Decorators.configure.simpleDecorator('containerless', containerless); Decorators.configure.parameterizedDecorator('viewStrategy', useView); diff --git a/package.json b/package.json index 322e9efe..a54e7672 100644 --- a/package.json +++ b/package.json @@ -15,26 +15,26 @@ }, "license": "MIT", "author": "Rob Eisenberg (http://robeisenberg.com/)", - "main": "dist/commonjs/index.js", + "main": "dist/commonjs/aurelia-templating.js", "repository": { "type": "git", "url": "http://github.com/aurelia/templating" }, "jspm": { - "main": "index", + "main": "aurelia-templating", "format": "amd", "directories": { "lib": "dist/amd" }, "dependencies": { - "aurelia-binding": "github:aurelia/binding@^0.8.0", - "aurelia-dependency-injection": "github:aurelia/dependency-injection@^0.9.0", + "aurelia-binding": "github:aurelia/binding@^0.8.3", + "aurelia-dependency-injection": "github:aurelia/dependency-injection@^0.9.1", "aurelia-html-template-element": "github:aurelia/html-template-element@^0.2.0", - "aurelia-loader": "github:aurelia/loader@^0.8.2", - "aurelia-logging": "github:aurelia/logging@^0.6.0", - "aurelia-metadata": "github:aurelia/metadata@^0.7.0", - "aurelia-path": "github:aurelia/path@^0.8.0", - "aurelia-task-queue": "github:aurelia/task-queue@^0.6.0", + "aurelia-loader": "github:aurelia/loader@^0.8.3", + "aurelia-logging": "github:aurelia/logging@^0.6.2", + "aurelia-metadata": "github:aurelia/metadata@^0.7.1", + "aurelia-path": "github:aurelia/path@^0.8.1", + "aurelia-task-queue": "github:aurelia/task-queue@^0.6.1", "core-js": "npm:core-js@^0.9.5" }, "devDependencies": {