Skip to content

Commit

Permalink
make the closing "/" character optional for the void HTML elements
Browse files Browse the repository at this point in the history
Fixes #70
Closes #74
  • Loading branch information
PK1A committed Feb 25, 2014
1 parent 1f982c7 commit 917a580
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 6 deletions.
34 changes: 33 additions & 1 deletion hsp/compiler/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ var blockParser = PEG.buildParser(grammar, {
trackLineAndColumn : true
});

//http://www.w3.org/TR/html-markup/syntax.html#syntax-elements
var VOID_HTML_ELEMENTS = {
"area": true,
"base": true,
"br": true,
"col": true,
"command": true,
"embed": true,
"hr": true,
"img": true,
"input": true,
"keygen": true,
"link": true,
"meta": true,
"param": true,
"source": true,
"track": true,
"wbr": true
};

function isVoidElement(elName) {
return VOID_HTML_ELEMENTS.hasOwnProperty(elName.toLowerCase());
}

/**
* Return the list of instruction blocks that compose a template file at this stage the template AST is not complete -
* cf. parse() function to get the complete syntax tree Note: this function is exposed for unit test purposes and should
Expand Down Expand Up @@ -403,6 +427,10 @@ var SyntaxTree = klass({
* Element block management
*/
_element : function (idx, blocks, out) {
var b = blocks[idx];
if (isVoidElement(b.name)) {
b.closed=true;
}
return this._elementOrComponent("element", idx, blocks, out);
},

Expand Down Expand Up @@ -600,7 +628,11 @@ var SyntaxTree = klass({
_endelement : function (idx, blocks, out) {
// only called in case of error
var b = blocks[idx], nm = b.name;
this._logError("End element </" + nm + "> does not match any <" + nm + "> element", b);
if (isVoidElement(nm)) {
this._logError("The end element </" + nm + "> was rejected as <" + nm + "> is a void HTML element and can't have a closing element", b);
} else {
this._logError("End element </" + nm + "> does not match any <" + nm + "> element", b);
}
return idx;
},

Expand Down
13 changes: 13 additions & 0 deletions public/test/compiler/errsamples/voidelement.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
##### Template:
# template test
Hello<br>World</br>
# /template

##### Errors:
[
{
"description": "The end element </br> was rejected as <br> is a void HTML element and can't have a closing element",
"line": 2,
"column": 19
}
]
4 changes: 2 additions & 2 deletions public/test/compiler/errtests.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ describe('Template compilation errors: ', function () {
var samples = ["text1", "text2", "text3", "if1", "if2", "if3", "if4", "if5", "if6", "if7", "foreach1", "foreach2",
"foreach3", "element1", "element2", "element3", "element4", "element5", "element6", "element7", "element8",
"insert", "template1", "template2", "template3", "template4", "template5", "template6", "template7",
"jsexpression1", "jsexpression2", "component1", "component2"];
//samples=["component2"];
"jsexpression1", "jsexpression2", "component1", "component2", "voidelement"];
//samples=["voidelement"];
for (var i = 0, sz = samples.length; sz > i; i++) {
// create one test for each sample
it('tests error sample ('+samples[i]+')', testFn.bind({
Expand Down
75 changes: 75 additions & 0 deletions public/test/compiler/samples/voidelement.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
##### Template:
# template test
Hello<br>World
<area>
<base>
<col>
<command>
<embed>
<hr>
<img>
<input>
<keygen>
<meta>
<param>
<source>
<track>
<wbr>
# /template

##### Parsed Tree
[
{
"type": "template", "name": "test", "args": [], "content": [
{"type": "text", "value": "Hello"},
{"type": "element", "name": "br", "closed": false},
{"type": "text", "value": "World "},
{"type": "element", "name": "area", "closed": false},
{"type": "element", "name": "base", "closed": false},
{"type": "element", "name": "col", "closed": false},
{"type": "element", "name": "command", "closed": false},
{"type": "element", "name": "embed", "closed": false},
{"type": "element", "name": "hr", "closed": false},
{"type": "element", "name": "img", "closed": false},
{"type": "element", "name": "input", "closed": false},
{"type": "element", "name": "keygen", "closed": false},
{"type": "element", "name": "meta", "closed": false},
{"type": "element", "name": "param", "closed": false},
{"type": "element", "name": "source", "closed": false},
{"type": "element", "name": "track", "closed": false},
{"type": "element", "name": "wbr", "closed": false}
],
"closed": true,
}
]

##### Syntax Tree
[
{
"type": "template",
"name": "test",
"args": [],
"export": false,
"content": [
{"type": "text", "value": "Hello"},
{"type": "element", "name": "br", "closed": true},
{"type": "text", "value": "World "},
{"type": "element", "name": "area", "closed": true},
{"type": "element", "name": "base", "closed": true},
{"type": "element", "name": "col", "closed": true},
{"type": "element", "name": "command", "closed": true},
{"type": "element", "name": "embed", "closed": true},
{"type": "element", "name": "hr", "closed": true},
{"type": "element", "name": "img", "closed": true},
{"type": "element", "name": "input", "closed": true},
{"type": "element", "name": "keygen", "closed": true},
{"type": "element", "name": "meta", "closed": true},
{"type": "element", "name": "param", "closed": true},
{"type": "element", "name": "source", "closed": true},
{"type": "element", "name": "track", "closed": true},
{"type": "element", "name": "wbr", "closed": true}
]
}
]

##### Template Code
4 changes: 2 additions & 2 deletions public/test/compiler/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ describe('Block Parser: ', function () {
"comment", "foreach1", "foreach2", "foreach3", "element1", "element2", "element3", "element4", "element5",
"evthandler1", "evthandler2", "evthandler3", "component1", "component2", "component3", "component4",
"component5", "component6", "component7", "jsexpression1", "jsexpression2", "jsexpression3", "jsexpression4", "jsexpression5",
"class1", "class2", "class3", "class4", "class5", "insert1", "insert2", "log1", "log2"];
//samples=["class5"];
"class1", "class2", "class3", "class4", "insert1", "insert2", "log1", "log2", "voidelement"];
//samples=["voidelement"];

for (var i = 0, sz = samples.length; sz > i; i++) {
// create one test for each sample
Expand Down
2 changes: 1 addition & 1 deletion public/test/rt/foreach.spec.hsp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ var hsp=require("hsp/rt"),
# template test6(itemsList)
{foreach item in itemsList}
{if item.edit}
<input type="text" value="{item.value}"></input>
<input type="text" value="{item.value}">
{else}
<span>{item.value}</span>
{/if}
Expand Down

0 comments on commit 917a580

Please sign in to comment.