Permalink
Browse files

feat(all): support template part replacement

This closes #70. Now developers of custom elements can add a “part”
attribute to any of their internal template controller’s templates.
Then the consumer of their custom element can add a <template> tag in
the content with a “replace-part” attribute set to the same name and
the custom template will override the internal tempalte.
  • Loading branch information...
EisenbergEffect committed May 7, 2015
1 parent 7597653 commit 1d9ba1c06563a12505dd4033ff24932a9f88007e
Showing with 74 additions and 22 deletions.
  1. +46 −15 src/html-behavior.js
  2. +10 −2 src/view-compiler.js
  3. +18 −5 src/view-factory.js
View
@@ -135,7 +135,8 @@ export class HtmlBehaviorResource {
if(this.liftsContent){
if(!instruction.viewFactory){
var template = document.createElement('template'),
fragment = document.createDocumentFragment();
fragment = document.createDocumentFragment(),
part = node.getAttribute('part');
node.removeAttribute(instruction.originalAttrName);
@@ -151,30 +152,60 @@ export class HtmlBehaviorResource {
}
fragment.appendChild(node);
instruction.viewFactory = compiler.compile(fragment, resources);
if(part){
instruction.viewFactory.part = part;
node.removeAttribute('part');
}
node = template;
}
} else if(this.elementName !== null && !this.usesShadowDOM && !this.skipContentProcessing && node.hasChildNodes()){
//custom element
var fragment = document.createDocumentFragment(),
currentChild = node.firstChild,
nextSibling;
while (currentChild) {
nextSibling = currentChild.nextSibling;
fragment.appendChild(currentChild);
currentChild = nextSibling;
}
} else if(this.elementName !== null){ //custom element
var partReplacements = {};
if(!this.skipContentProcessing && node.hasChildNodes()){
if(!this.usesShadowDOM){
var fragment = document.createDocumentFragment(),
currentChild = node.firstChild,
nextSibling;
while (currentChild) {
nextSibling = currentChild.nextSibling;
if(currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))){
partReplacements[toReplace] = compiler.compile(currentChild, resources);
}else{
fragment.appendChild(currentChild);
}
currentChild = nextSibling;
}
instruction.contentFactory = compiler.compile(fragment, resources);
instruction.contentFactory = compiler.compile(fragment, resources);
}else{
var currentChild = node.firstChild,
nextSibling, toReplace;
while (currentChild) {
nextSibling = currentChild.nextSibling;
if(currentChild.tagName === 'TEMPLATE' && (toReplace = currentChild.getAttribute('replace-part'))){
partReplacements[toReplace] = compiler.compile(currentChild, resources);
}
currentChild = nextSibling;
}
}
}
}
instruction.partReplacements = partReplacements;
instruction.suppressBind = true;
return node;
}
create(container, instruction=defaultInstruction, element=null, bindings){
create(container, instruction=defaultInstruction, element=null, bindings=null){
var executionContext = instruction.executionContext || container.get(this.target),
behaviorInstance = new BehaviorInstance(this, executionContext, instruction),
viewFactory, host;
View
@@ -51,7 +51,7 @@ export class ViewCompiler {
compile(templateOrFragment, resources, options=defaultCompileOptions){
var instructions = [],
targetShadowDOM = options.targetShadowDOM,
content;
content, part, factory;
targetShadowDOM = targetShadowDOM && hasShadowDOM;
@@ -60,6 +60,7 @@ export class ViewCompiler {
}
if(templateOrFragment.content){
part = templateOrFragment.getAttribute('part');
content = document.adoptNode(templateOrFragment.content, true);
}else{
content = templateOrFragment;
@@ -70,7 +71,13 @@ export class ViewCompiler {
content.insertBefore(document.createComment('<view>'), content.firstChild);
content.appendChild(document.createComment('</view>'));
return new ViewFactory(content, instructions, resources);
var factory = new ViewFactory(content, instructions, resources);
if(part){
factory.part = part;
}
return factory;
}
compileNode(node, resources, instructions, parentNode, parentInjectorId, targetLightDOM){
@@ -122,6 +129,7 @@ export class ViewCompiler {
return node.nextSibling;
} else if(tagName === 'template'){
viewFactory = this.compile(node, resources);
viewFactory.part = node.getAttribute('part');
} else{
type = resources.getElement(tagName);
if(type){
View
@@ -10,7 +10,17 @@ function elementContainerGet(key){
}
if(key === BoundViewFactory){
return this.boundViewFactory || (this.boundViewFactory = new BoundViewFactory(this, this.instruction.viewFactory, this.executionContext));
if(this.boundViewFactory){
return this.boundViewFactory;
}
var factory;
if(this.partReplacements){
factory = this.partReplacements[this.instruction.viewFactory.part];
}
return this.boundViewFactory = new BoundViewFactory(this, factory || this.instruction.viewFactory, this.executionContext);
}
if(key === ViewSlot){
@@ -29,7 +39,7 @@ function elementContainerGet(key){
return this.superGet(key);
}
function createElementContainer(parent, element, instruction, executionContext, children, resources){
function createElementContainer(parent, element, instruction, executionContext, children, partReplacements, resources){
var container = parent.createChild(),
providers,
i;
@@ -39,6 +49,7 @@ function createElementContainer(parent, element, instruction, executionContext,
container.executionContext = executionContext;
container.children = children;
container.viewResources = resources;
container.partReplacements = partReplacements;
providers = instruction.providers;
i = providers.length;
@@ -54,7 +65,7 @@ function createElementContainer(parent, element, instruction, executionContext,
}
function applyInstructions(containers, executionContext, element, instruction,
behaviors, bindings, children, contentSelectors, resources){
behaviors, bindings, children, contentSelectors, partReplacements, resources){
var behaviorInstructions = instruction.behaviorInstructions,
expressions = instruction.expressions,
elementContainer, i, ii, current, instance;
@@ -78,12 +89,13 @@ function applyInstructions(containers, executionContext, element, instruction,
instruction,
executionContext,
children,
partReplacements,
resources
);
for(i = 0, ii = behaviorInstructions.length; i < ii; ++i){
current = behaviorInstructions[i];
instance = current.type.create(elementContainer, current, element, bindings);
instance = current.type.create(elementContainer, current, element, bindings, current.partReplacements);
if(instance.contentView){
children.push(instance.contentView);
@@ -138,11 +150,12 @@ export class ViewFactory{
children = [],
contentSelectors = [],
containers = { root:container },
partReplacements = options.partReplacements,
i, ii, view;
for(i = 0, ii = instructables.length; i < ii; ++i){
applyInstructions(containers, executionContext, instructables[i],
instructions[i], behaviors, bindings, children, contentSelectors, resources);
instructions[i], behaviors, bindings, children, contentSelectors, partReplacements, resources);
}
view = new View(fragment, behaviors, bindings, children, options.systemControlled, contentSelectors);

0 comments on commit 1d9ba1c

Please sign in to comment.