Skip to content

Commit

Permalink
Merge pull request #780 from bitovi/nested-component-error
Browse files Browse the repository at this point in the history
Nested component tags of same type throws an error
  • Loading branch information
daffl committed Mar 12, 2014
2 parents 11ab1aa + e7ad4c8 commit c140d9f
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 15 deletions.
20 changes: 20 additions & 0 deletions component/component_test.js
Expand Up @@ -751,4 +751,24 @@ steal("can/component", function () {
equal(called, false);
});

test('Same component tag nested', function () {
can.Component({
'tag': 'my-tag',
template: '<p><content/></p>'
});
//simplest case
var template = can.view.mustache('<my-tag>Outter<my-tag>Inner</my-tag></my-tag>');
//complex case
var template2 = can.view.mustache('<my-tag>3<my-tag>2<my-tag>1<my-tag>0</my-tag></my-tag></my-tag></my-tag>');
//edge case for new logic (same custom tag at same depth as one previously encountered)
var template3 = can.view.mustache('<my-tag>First</my-tag><my-tag>Second</my-tag>');
can.append(can.$('#qunit-test-area'), template({}));
equal(can.$('#qunit-test-area p').length, 2, 'proper number of p tags');
can.append(can.$('#qunit-test-area'), template2({}));
equal(can.$('#qunit-test-area p').length, 6, 'proper number of p tags');
can.append(can.$('#qunit-test-area'), template3({}));
equal(can.$('#qunit-test-area p').length, 8, 'proper number of p tags');

});

});
34 changes: 19 additions & 15 deletions view/scanner.js
Expand Up @@ -290,7 +290,7 @@ steal('can/view', './elements', function (can, elements) {
buff.push(put_cmd, '"', clean(content), '"' + (bonus || '') + ');');
},
// A stack used to keep track of how we should end a bracket
// `}`.
// `}`.
// Once we have a `<%= %>` with a `leftBracket`,
// we store how the file should end here (either `))` or `;`).
endStack = [],
Expand All @@ -304,7 +304,14 @@ steal('can/view', './elements', function (can, elements) {
specialStates = {
attributeHookups: [],
// a stack of tagHookups
tagHookups: []
tagHookups: [],
//last tag hooked up
lastTagHookup: ''
},
// Helper `function` for removing tagHookups from the hookup stack
popTagHookup = function() {
// The length of tagHookups is the nested depth which can be used to uniquely identify custom tags of the same type
specialStates.lastTagHookup = specialStates.tagHookups.pop() + specialStates.tagHookups.length;
},
// The current tag name.
tagName = '',
Expand All @@ -314,7 +321,6 @@ steal('can/view', './elements', function (can, elements) {
popTagName = false,
// Declared here.
bracketCount,

// in a special attr like src= or style=
specialAttribute = false,

Expand All @@ -325,7 +331,6 @@ steal('can/view', './elements', function (can, elements) {

// Reinitialize the tag state goodness.
htmlTag = quote = beforeQuote = null;

for (;
(token = tokens[i++]) !== undefined;) {
if (startTag === null) {
Expand All @@ -336,7 +341,7 @@ steal('can/view', './elements', function (can, elements) {
magicInTag = htmlTag && 1;
/* falls through */
case tmap.commentLeft:
// A new line -- just add whatever content within a clean.
// A new line -- just add whatever content within a clean.
// Reset everything.
startTag = token;
if (content.length) {
Expand Down Expand Up @@ -382,16 +387,17 @@ steal('can/view', './elements', function (can, elements) {
var emptyElement = content.substr(content.length - 1) === '/' || content.substr(content.length - 2) === '--',
attrs = '';
// if there was a magic tag
// or it's an element that has text content between its tags,
// or it's an element that has text content between its tags,
// but content is not other tags add a hookup
// TODO: we should only add `can.EJS.pending()` if there's a magic tag
// TODO: we should only add `can.EJS.pending()` if there's a magic tag
// within the html tags.
if (specialStates.attributeHookups.length) {
attrs = "attrs: ['" + specialStates.attributeHookups.join("','") + "'], ";
specialStates.attributeHookups = [];
}
// this is the > of a special tag
if (tagName === top(specialStates.tagHookups)) {
// comparison to lastTagHookup makes sure the same custom tags can be nested
if ((tagName + specialStates.tagHookups.length) !== specialStates.lastTagHookup && tagName === top(specialStates.tagHookups)) {
// If it's a self closing tag (like <content/>) make sure we put the / at the end.
if (emptyElement) {
content = content.substr(0, content.length - 1);
Expand All @@ -405,13 +411,13 @@ steal('can/view', './elements', function (can, elements) {
if (emptyElement) {
buff.push("}));");
content = "/>";
specialStates.tagHookups.pop();
popTagHookup();
}
// if it's an empty tag
else if (tokens[i] === "<" && tokens[i + 1] === "/" + tagName) {
buff.push("}));");
content = token;
specialStates.tagHookups.pop();
popTagHookup();
} else {
// it has content
buff.push(",subtemplate: function(" + this.text.argNames + "){\n" + startTxt + (this.text.start || ''));
Expand Down Expand Up @@ -517,18 +523,16 @@ steal('can/view', './elements', function (can, elements) {
tagName = cleanedTagName;
popTagName = true;
}

// if we are in a closing tag of a custom tag
if (top(specialStates.tagHookups) === cleanedTagName) {
// remove the last < from the content
put(content.substr(0, content.length - 1));

// finish the "section"
buff.push(finishTxt + "}}) );");

// the < belongs to the outside
content = "><";
specialStates.tagHookups.pop();
popTagHookup();
}

} else {
Expand Down Expand Up @@ -567,7 +571,7 @@ steal('can/view', './elements', function (can, elements) {

// We are ending a block.
if (bracketCount === 1) {
// We are starting on.
// We are starting on.
buff.push(insert_cmd, 'can.view.txt(0,\'' + getTag(tagName, tokens, i) + '\',' + status() + ',this,function(){', startTxt, content);
endStack.push({
before: '',
Expand All @@ -580,7 +584,7 @@ steal('can/view', './elements', function (can, elements) {
after: ';'
};

// If we are ending a returning block,
// If we are ending a returning block,
// add the finish text which returns the result of the
// block.
if (last.before) {
Expand Down

0 comments on commit c140d9f

Please sign in to comment.