Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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 1d9ba1c
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 22 deletions.
61 changes: 46 additions & 15 deletions src/html-behavior.js
Expand Up @@ -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);

Expand All @@ -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;
Expand Down
12 changes: 10 additions & 2 deletions src/view-compiler.js
Expand Up @@ -51,7 +51,7 @@ export class ViewCompiler {
compile(templateOrFragment, resources, options=defaultCompileOptions){
var instructions = [],
targetShadowDOM = options.targetShadowDOM,
content;
content, part, factory;

targetShadowDOM = targetShadowDOM && hasShadowDOM;

Expand All @@ -60,6 +60,7 @@ export class ViewCompiler {
}

if(templateOrFragment.content){
part = templateOrFragment.getAttribute('part');
content = document.adoptNode(templateOrFragment.content, true);
}else{
content = templateOrFragment;
Expand All @@ -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){
Expand Down Expand Up @@ -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){
Expand Down
23 changes: 18 additions & 5 deletions src/view-factory.js
Expand Up @@ -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){
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 1d9ba1c

Please sign in to comment.