Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

White space management - DO NOT MERGE #287

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/samples/simplelist/simplelist.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('simple list', function () {

it('should toggle message on list item click', function () {
h('li:eq(1)').click();
expect(h('li:eq(1)').text()).to.equal('Marge : 38 years old');
expect(h('li:eq(1)').text()).to.equal('Marge\n : 38 years old');
expect(h('li:eq(1)').hasClass('details')).to.be.ok();
h('li:eq(1)').click();
expect(h('li:eq(1)').text()).to.equal('Marge');
Expand Down
2 changes: 1 addition & 1 deletion hsp/compiler/jsgenerator/processors.js
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ function formatTextBlock (node, nextExprIndex, walker) {
// (=args)
for (var i = 0; i < content.length; i++) {
item = content[i];
if (item.type === "text") {
if (item.type === "text" || item.type === "eol") {
if (index % 2 === 0) {
// even index: arg must be a string
args[index] = '"' + escapeNewLines(item.value.replace(/"/g, "\\\"")) + '"';
Expand Down
44 changes: 21 additions & 23 deletions hsp/compiler/parser/hspblocks.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ TemplateEnd "template end statement"
= _ "</template" _ ">" _ (EOL / EOF)
{return {type:"/template",line:line,column:column}}

TemplateContent "template content"
= _ blocks:( TplTextBlock
TemplateContent "template content" // TODO: CSSClassExpression
= blocks:( EOLBlock / TplTextBlock
/ CommentBlock / HTMLCommentBlock
/ IfBlock / ElseIfBlock / ElseBlock / EndIfBlock
/ ForeachBlock / EndForeachBlock
Expand All @@ -89,41 +89,38 @@ TplTextBlock "text"
TplTextChar "text character"
= "\\{" {return "\u007B"} // { = \u007B
/ "\\}" {return "\u007D"} // } = \u007D
/ "\\n" {return "\n"}
/ EOL &TemplateEnd {return ""} // ignore last EOL
/ EOL _ {return " "}
/ "#" !(_ "\/template") {return "#"}
/ "\/" !"/" {return "/"}
/ "\\/" {return "/"}
/ "\\//" {return "//"}
/ "\\<" {return "<"}
/ [^{#/<]
/ [^{#/<\n\r\u2028\u2029]

InvalidBlock
= "{" chars:[^{}#]* "}"
{return {type:"invalidblock", code:chars.join(''), line:line, column:column}}

IfBlock "if statement"
= "{" _ "if " _ expr:(IfCondWithBrackets / CoreExpText) _ "}" EOS?
= "{" _ "if " _ expr:(IfCondWithBrackets / CoreExpText) _ "}"
{return {type:"if", condition:expr, line:line, column:column}}

IfCondWithBrackets
= "(" expr:CoreExpText ")" {return expr}

ElseIfBlock "elseif statement"
= "{" _ "else " _ "if" _ expr:(IfCondWithBrackets / CoreExpText) _ "}" EOS?
= "{" _ "else " _ "if" _ expr:(IfCondWithBrackets / CoreExpText) _ "}"
{return {type:"elseif", condition:expr, line:line, column:column}}

ElseBlock
= "{" _ "else" _ "}" EOS?
= "{" _ "else" _ "}"
{return {type:"else", line:line, column:column}}

EndIfBlock
= "{" _ "/if" _ "}" EOS?
= "{" _ "/if" _ "}"
{return {type:"endif", line:line, column:column}}

CommentBlock
= _ "\/\/" chars:[^\r\n]* &EOL
= _ "\/\/" chars:[^\r\n]*
{return {type:"comment", value:chars.join('')}}

HTMLCommentBlock
Expand All @@ -137,7 +134,7 @@ HTMLCommentChar
/ [^>\-]

ForeachBlock
= "{" _ "foreach " _ args:( ForeachArgs / ("(" _ a:ForeachArgs _ ")") {return a}) _ "}" EOS?
= "{" _ "foreach " _ args:( ForeachArgs / ("(" _ a:ForeachArgs _ ")") {return a}) _ "}"
{return {type:"foreach", item:args.item, key:args.key, colref:args.colref, line:line, column:column}}

ForeachArgs
Expand All @@ -156,30 +153,30 @@ EndForeachBlock
{return {type:"endforeach", line:line, column:column}}

HTMLElement
= "<" !(_ "template") name:HTMLName atts:HTMLElementAttributes? S? end:"/"? ">" EOS?
= "<" !(_ "template") name:HTMLName atts:HTMLElementAttributes? S? end:"/"? ">"
{return {type:"element", name:name, closed:(end!==""), attributes:atts, line:line, column:column}}

HTMLElementAttributes
= atts:((S att:(HTMLAttribute)) {return att})*

EndHTMLElement // TODO support comments inside Element
= "</" !(_ "template") name:HTMLName S? ">" EOS?
= "</" !(_ "template") name:HTMLName S? ">"
{return {type:"endelement", name:name, line:line, column:column}}

HspComponent
= "<#" ref:JSObjectRef atts:HTMLElementAttributes? S? end:"/"? ">" EOS?
= "<#" ref:JSObjectRef atts:HTMLElementAttributes? S? end:"/"? ">"
{return {type:"component", ref:ref, closed:(end!==""), attributes:atts, line:line, column:column}}

EndHspComponent
= "</#" ref:JSObjectRef S? ">" EOS?
= "</#" ref:JSObjectRef S? ">"
{return {type:"endcomponent", ref:ref, line:line, column:column}}

HspCptAttribute
= "<@" ref:VarIdentifier atts:HTMLElementAttributes? S? end:"/"? ">" EOS?
= "<@" ref:VarIdentifier atts:HTMLElementAttributes? S? end:"/"? ">"
{return {type:"cptattribute", name:ref, closed:(end!==""), attributes:atts, line:line, column:column}}

EndHspCptAttribute
= "</@" ref:VarIdentifier S? ">" EOS?
= "</@" ref:VarIdentifier S? ">"
{return {type:"endcptattribute", name:ref, line:line, column:column}}

InvalidHTMLElement
Expand Down Expand Up @@ -215,7 +212,7 @@ HTMLAttributeChar // TODO look at W3C specs
/ [^{\"]

LogBlock
= "{" _ "log " _ first:CoreExpText _ next:("," _ CoreExpText)* _"}" EOS?
= "{" _ "log " _ first:CoreExpText _ next:("," _ CoreExpText)* _"}"
{
var exprs=[first];
if (next) {
Expand All @@ -227,7 +224,7 @@ LogBlock
}

LetBlock
= "{" _ "let " _ first:CoreExpText __ next:("," __ CoreExpText)* "}" EOS?
= "{" _ "let " _ first:CoreExpText __ next:("," __ CoreExpText)* "}"
{
var asn=[first];
if (next) {
Expand Down Expand Up @@ -282,6 +279,10 @@ InvalidExpressionValue
= !("/template" _) chars:[^}]+
{return {type:"invalidexpression", code:chars.join(''), line:line, column:column}}

EOLBlock "End of line block"
= eol:EOL
{return {type:"eol", value:eol, line:line, column:column};}

// White spaces
// mandatory padding including line breaks
S "white space"
Expand All @@ -300,9 +301,6 @@ EOL "end of line"
/ "\u2028" // line separator
/ "\u2029" // paragraph separator

EOS "end of statement" //
= empty:(_ EOL _)

EOF "end of file"
= !.

Expand Down
58 changes: 52 additions & 6 deletions hsp/compiler/treebuilder/syntaxTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,43 @@ var SyntaxTree = klass({
return index;
},

/**
* Manages a End Of Line block
* @param {Array} blocks the full list of blocks.
* @param {Integer} index the index of the block to manage.
* @param {Array} out the output as an array of Node.
* @return {Integer} the index of the block where the function stopped or -1 if all blocks have been handled.
*/
__eol : function(index, blocks, out) {
return this.__text(index, blocks, out);
},

_skipWhitespaces: function(index, blocks, out) {
//Skips opening whitespace block and ending EOL block if the line is only made of blocks which don't generate DOM element or text
var toBeSkipped = true;
var nextIndex = index + 1;
while (nextIndex < blocks.length) {
var nextBlock = blocks[nextIndex];
if (!(nextBlock.type === "text" && nextBlock.value.match(/^(\s)+$/) ||
["if", "elseif", "else", "endif", "comment", "foreach", "endforeach", "eol", "log", "let"].indexOf(nextBlock.type) > -1)) {
toBeSkipped = false;
break;
}
if (nextBlock.type === "eol") {
break;
}
nextIndex++;
}
if (index + 1 < blocks.length && toBeSkipped) {
if (blocks[index + 1].type === "text") {
blocks[index + 1].toBeSkipped = true;
}
if (blocks[nextIndex].type === "eol") {
blocks[nextIndex].toBeSkipped = true;
}
}
},

/**
* Manages a text block: regroups adjacent text and expression blocks
* @param {Array} blocks the full list of blocks.
Expand All @@ -306,19 +343,28 @@ var SyntaxTree = klass({
__text : function (index, blocks, out) {
var length = blocks.length, buffer = [];

if (index === 0) {
this._skipWhitespaces(-1, blocks, out);
}

//Regroups adjacent text and expression blocks by looking at the next ones
var nextIndex = index, goAhead = (length > nextIndex), block;
while (goAhead) {
block = blocks[nextIndex];
if (block.type === "text") {
if (block.type === "text" || block.type === "eol") {
if (block.value !== "") {
try {
block.value = htmlEntitiesToUtf8(block.value);
buffer.push(block);
block.value = htmlEntitiesToUtf8(block.value);
if (typeof block.toBeSkipped === "undefined") {
buffer.push(block);
}
} catch (e) {
this._logError(e.message, block);
this._logError(e.message, block);
}
}
if (block.type === "eol") {
this._skipWhitespaces(nextIndex, blocks, out);
}
} else if (block.type === "expression") {
//parse the expression to detect errors
if (this._validateExpressionBlock(block)){
Expand All @@ -338,15 +384,15 @@ var SyntaxTree = klass({

//Manages the adjacent text and expression blocks found
var node = null;
if (buffer.length === 1 && buffer[0].type === "text") {
if (buffer.length === 1 && (buffer[0].type === "text" || buffer[0].type === "eol")) {
// only one text block
node = new Node("text");
node.value = buffer[0].value;
} else if (buffer.length > 0) {
// if buffer is composed of only text expressions we concatenate them
var onlyText=true;
for (var i = 0; i < buffer.length; i++) {
if (buffer[i].type !== "text") {
if (buffer[i].type !== "text" && buffer[i].type !== "eol") {
onlyText = false;
break;
}
Expand Down
7 changes: 7 additions & 0 deletions hsp/utils/hashtester.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,10 @@ module.exports.newTestContext = function() {
};
return h;
};

//Polyfill to perform tests in IE8
if (typeof String.prototype.trim !== 'function') {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
};
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"grunt-verifylowercase": "~0.2.0",
"grunt-leading-indent": "~0.1.0",
"grunt-mocha-test": "~0.7.0",
"grunt-browserify": "~2.0.0",
"grunt-browserify": "~3.0.1",
"grunt-peg": "~1.0.0",
"grunt-karma": "~0.8.0",
"grunt-jscs-checker": "~0.4.0",
Expand Down
30 changes: 17 additions & 13 deletions test/gestures/doubleTap.spec.hsp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ describe("DoubleTap gesture", function () {
}
};
var n = test1(ctl);
fireEvent(touchEventMap.touchstart, n.node.firstChild, {
var target = n.node.querySelector("div");
fireEvent(touchEventMap.touchstart, target, {
isPrimary : true,
touches : [{
clientX : 0,
Expand All @@ -65,7 +66,7 @@ describe("DoubleTap gesture", function () {
clientY : 0
}]
});
fireEvent(touchEventMap.touchmove, n.node.firstChild, {
fireEvent(touchEventMap.touchmove, target, {
isPrimary : false,
touches : [{
clientX : 0,
Expand All @@ -92,11 +93,12 @@ describe("DoubleTap gesture", function () {
}
};
var n = test1(ctl);
fireEvent(touchEventMap.touchstart, n.node.firstChild, {
var target = n.node.querySelector("div");
fireEvent(touchEventMap.touchstart, target, {
clientX : 0,
clientY : 0
});
fireEvent(touchEventMap.touchmove, n.node.firstChild, {
fireEvent(touchEventMap.touchmove, target, {
clientX : 100,
clientY : 100
});
Expand All @@ -113,15 +115,16 @@ describe("DoubleTap gesture", function () {
}
};
var n = test1(ctl);
fireEvent(touchEventMap.touchstart, n.node.firstChild, {
var target = n.node.querySelector("div");
fireEvent(touchEventMap.touchstart, target, {
clientX : 0,
clientY : 0
});
fireEvent(touchEventMap.touchmove, n.node.firstChild, {
fireEvent(touchEventMap.touchmove, target, {
clientX : 5,
clientY : 5
});
fireEvent(touchEventMap.touchend, n.node.firstChild, {
fireEvent(touchEventMap.touchend, target, {
clientX : 5,
clientY : 5
});
Expand All @@ -139,27 +142,28 @@ describe("DoubleTap gesture", function () {
}
};
var n = test1(ctl);
fireEvent(touchEventMap.touchstart, n.node.firstChild, {
var target = n.node.querySelector("div");
fireEvent(touchEventMap.touchstart, target, {
clientX : 0,
clientY : 0
});
fireEvent(touchEventMap.touchmove, n.node.firstChild, {
fireEvent(touchEventMap.touchmove, target, {
clientX : 5,
clientY : 5
});
fireEvent(touchEventMap.touchend, n.node.firstChild, {
fireEvent(touchEventMap.touchend, target, {
clientX : 5,
clientY : 5
});
fireEvent(touchEventMap.touchstart, n.node.firstChild, {
fireEvent(touchEventMap.touchstart, target, {
clientX : 0,
clientY : 0
});
fireEvent(touchEventMap.touchmove, n.node.firstChild, {
fireEvent(touchEventMap.touchmove, target, {
clientX : 5,
clientY : 5
});
fireEvent(touchEventMap.touchend, n.node.firstChild, {
fireEvent(touchEventMap.touchend, target, {
clientX : 5,
clientY : 5
});
Expand Down
Loading