Skip to content

Commit

Permalink
Allows having surfaces with templates from other components
Browse files Browse the repository at this point in the history
  • Loading branch information
mairatma committed Jul 3, 2015
1 parent 67cd77e commit 5262f32
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 15 deletions.
50 changes: 35 additions & 15 deletions src/soy/SoyComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import core from '../core';
import Component from '../component/Component';
import ComponentRegistry from '../component/ComponentRegistry';

/**
* We need to listen to calls to soy deltemplates so we can use them to
Expand Down Expand Up @@ -70,6 +71,7 @@ class SoyComponent extends Component {
if (!surface) {
this.addSurface(templateName, {
renderAttrs: templates[templateName].params,
templateComponentName: this.constructor.NAME,
templateName: templateName
});
}
Expand Down Expand Up @@ -105,7 +107,9 @@ class SoyComponent extends Component {
buildPlaceholderSurfaceData_(type, extra) {
var data = super.buildPlaceholderSurfaceData_(type, extra);
if (type === Component.SurfaceType.NORMAL) {
data.templateName = extra;
var split = extra.split('.');
data.templateComponentName = split[0];
data.templateName = split[1];
}
return data;
}
Expand Down Expand Up @@ -138,6 +142,7 @@ class SoyComponent extends Component {
static createComponentFromTemplate(templateFn, opt_element, opt_data) {
class TemplateComponent extends SoyComponent {
}
TemplateComponent.NAME = 'TemplateComponent';
TemplateComponent.TEMPLATES = {
content: function(opt_attrs, opt_ignored, opt_ijData) {
return templateFn(opt_data || {}, opt_ignored, opt_ijData);
Expand Down Expand Up @@ -165,11 +170,14 @@ class SoyComponent extends Component {

/**
* Generates the id for a surface that was found by a soy template call.
* @param {string} templateComponentName
* @param {string} templateName
* @return {string}
*/
generateSoySurfaceId_(templateName) {
if (!this.surfaceBeingRendered_ && !this.firstSurfaceFound_[templateName]) {
generateSoySurfaceId_(templateComponentName, templateName) {
if (!this.surfaceBeingRendered_ &&
!this.firstSurfaceFound_[templateName] &&
templateComponentName === this.constructor.NAME) {
this.firstSurfaceFound_[templateName] = true;
return templateName;
} else {
Expand All @@ -196,7 +204,7 @@ class SoyComponent extends Component {
*/
getElementContent() {
this.surfaceBeingRendered_ = null;
return this.renderTemplateByName_('content');
return this.renderTemplateByName_(this.constructor.NAME, 'content');
}

/**
Expand All @@ -222,7 +230,7 @@ class SoyComponent extends Component {
var data = this.nextSurfaceCallData_[surfaceId];
this.nextSurfaceCallData_[surfaceId] = null;
this.surfaceBeingRendered_ = surfaceId;
return this.renderTemplateByName_(surface.templateName, data);
return this.renderTemplateByName_(surface.templateComponentName, surface.templateName, data);
}

/**
Expand All @@ -232,29 +240,30 @@ class SoyComponent extends Component {
* @protected
*/
handleGetDelegateFnCall_(delTemplateId) {
var index = delTemplateId.indexOf('.');
if (index === -1) {
if (delTemplateId.indexOf('.') === -1) {
return this.handleTemplateCall_.bind(this, delTemplateId);
} else {
return this.handleSurfaceCall_.bind(this, delTemplateId.substr(index + 1));
var split = delTemplateId.split('.');
return this.handleSurfaceCall_.bind(this, split[0], split[1]);
}
}

/**
* Handles a call to the SoyComponent surface template.
* @param {string} surfaceName The surface's name.
* @param {string} templateComponentName The name of the component that this template was belongs to.
* @param {string} templateName The name of this template.
* @param {!Object} data The data the template was called with.
* @return {string} A placeholder to be rendered instead of the content the template
* function would have returned.
* @protected
*/
handleSurfaceCall_(surfaceName, data) {
handleSurfaceCall_(templateComponentName, templateName, data) {
var surfaceId = data.surfaceId;
if (!core.isDefAndNotNull(surfaceId)) {
surfaceId = this.generateSoySurfaceId_(surfaceName);
surfaceId = this.generateSoySurfaceId_(templateComponentName, templateName);
}
this.nextSurfaceCallData_[surfaceId] = data;
return '%%%%~s-' + surfaceId + ':' + surfaceName + '~%%%%';
return '%%%%~s-' + surfaceId + ':' + templateComponentName + '.' + templateName + '~%%%%';
}

/**
Expand All @@ -280,7 +289,8 @@ class SoyComponent extends Component {
renderElementDelTemplate_(content, opt_surfaceId) {
var templateName = this.constructor.NAME;
if (opt_surfaceId) {
templateName += '.' + this.getSurface(opt_surfaceId).templateName;
var surface = this.getSurface(opt_surfaceId);
templateName = surface.templateComponentName + '.' + surface.templateName;
}
var templateFn = soy.$$getDelegateFn(templateName, 'element', true);
var data = {
Expand Down Expand Up @@ -321,12 +331,22 @@ class SoyComponent extends Component {

/**
* Renders the template with the specified name.
* @param {string} templateComponentName
* @param {string} templateName
* @param {Object=} opt_data
* @return {string} The template's result content.
*/
renderTemplateByName_(templateName, opt_data) {
var elementTemplate = this.constructor.TEMPLATES_MERGED[templateName];
renderTemplateByName_(templateComponentName, templateName, opt_data) {
var elementTemplate;
if (templateComponentName === this.constructor.NAME) {
elementTemplate = this.constructor.TEMPLATES_MERGED[templateName];
} else {
var componentTemplates = ComponentRegistry.Templates[templateComponentName];
if (componentTemplates) {
elementTemplate = componentTemplates[templateName];
}
}

if (core.isFunction(elementTemplate)) {
return this.renderTemplate_(elementTemplate, opt_data);
}
Expand Down
17 changes: 17 additions & 0 deletions test/src/soy/SoyComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import './assets/ChildrenTestComponent.soy.js';
import './assets/CustomTestComponent.soy.js';
import './assets/DeeplyNestedTestComponent.soy.js';
import './assets/EventsTestComponent.soy.js';
import './assets/ExternalTemplateTestComponent.soy.js';
import './assets/NestedNoIdTestComponent.soy.js';
import './assets/NestedSurfacesTestComponent.soy.js';
import './assets/NestedTestComponent.soy.js';
Expand Down Expand Up @@ -337,6 +338,22 @@ describe('SoyComponent', function() {
dom.triggerEvent(parentButton, 'click');
assert.strictEqual(1, component.handleClick.callCount);
});

it('should render templates from other components', function() {
createNestedTestComponentClass();
var ExternalTemplateTestComponent = createCustomTestComponentClass('ExternalTemplateTestComponent');
ExternalTemplateTestComponent.ATTRS = {
count: {
value: 2
}
};
var component = new ExternalTemplateTestComponent({
id: 'nested'
}).render();

assert.ok(component.components.nestedMyChild0);
assert.ok(component.components.nestedMyChild1);
});
});

describe('createComponentFromTemplate', function() {
Expand Down
7 changes: 7 additions & 0 deletions test/src/soy/assets/ExternalTemplateTestComponent.soy
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{namespace Templates.ExternalTemplateTestComponent}

/**
*/
{template .content}
{delcall NestedTestComponent.components data="all" /}
{/template}

0 comments on commit 5262f32

Please sign in to comment.