mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Added support for range looping
This commit is contained in:
parent
c80b8feda3
commit
04e2f168b1
32
README.md
32
README.md
@ -35,6 +35,7 @@ Raptor Templates is an extensible, streaming, asynchronous, [high performance](h
|
||||
- [for](#for)
|
||||
- [Loop Status Variable](#loop-status-variable)
|
||||
- [Loop Separator](#loop-separator)
|
||||
- [Range Looping](#range-looping)
|
||||
- [Property Looping](#property-looping)
|
||||
- [Macros](#macros)
|
||||
- [def](#def)
|
||||
@ -752,6 +753,37 @@ The `c-for` directive also supports a loop status variable in case you need to k
|
||||
</div>
|
||||
```
|
||||
|
||||
#### Range Looping
|
||||
|
||||
A range can be provided in the following format; `<var-name> from <from> to <to>[ step <step>]`.
|
||||
|
||||
The `from`, `to` and `step` values must be numerical expressions. If not specified, step defaults to 1.
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li c-for="i from 0 to 10">
|
||||
$i
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li c-for="i from 0 to 10 step 2">
|
||||
$i
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li c-for="i from 0 to myArray.length-1">
|
||||
${myArray[i]}
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
|
||||
#### Property Looping
|
||||
|
||||
```html
|
||||
|
||||
@ -16,6 +16,25 @@
|
||||
'use strict';
|
||||
var forEachRegEx = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s+in\s+(.+)$/;
|
||||
var forEachPropRegEx = /^\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*,\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)\s+in\s+(.+)$/;
|
||||
var forRangeRegEx = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s+from\s+(.+)$/; // i from 0 to 10 or i from 0 to 10 step 5
|
||||
var forRangeKeywordsRegExp = /"(?:[^"]|\\")*"|'(?:[^']|\\')*'|\s+(to|step)\s+/g;
|
||||
var integerRegExp = /^-?\d+$/;
|
||||
var numberRegExp = /^-?(?:\d+|\d+\.\d*|\d*\.\d+|\d+\.\d+)$/;
|
||||
|
||||
function convertNumber(str) {
|
||||
if (!str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
if (integerRegExp.test(str)) {
|
||||
return parseInt(str, 10);
|
||||
} else if (numberRegExp.test(str)) {
|
||||
return parseFloat(str);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
var stringify = require('raptor-json/stringify').stringify;
|
||||
function parseForEach(value) {
|
||||
var match = value.match(forEachRegEx);
|
||||
@ -24,17 +43,79 @@ function parseForEach(value) {
|
||||
'var': match[1],
|
||||
'in': match[2]
|
||||
};
|
||||
} else {
|
||||
match = value.match(forEachPropRegEx);
|
||||
if (!match) {
|
||||
throw new Error('Invalid each attribute of "' + value + '"');
|
||||
}
|
||||
} else if ((match = value.match(forEachPropRegEx))) {
|
||||
|
||||
|
||||
return {
|
||||
'nameVar': match[1],
|
||||
'valueVar': match[2],
|
||||
'in': match[3]
|
||||
};
|
||||
} else if ((match = value.match(forRangeRegEx))) {
|
||||
var nameVar = match[1];
|
||||
|
||||
|
||||
var remainder = match[2];
|
||||
var rangeMatches;
|
||||
|
||||
var fromStart = 0;
|
||||
var fromEnd = -1;
|
||||
|
||||
var toStart = -1;
|
||||
var toEnd = remainder.length;
|
||||
|
||||
var stepStart = -1;
|
||||
var stepEnd = -1;
|
||||
|
||||
while ((rangeMatches = forRangeKeywordsRegExp.exec(remainder))) {
|
||||
if (rangeMatches[1] === 'to') {
|
||||
fromEnd = rangeMatches.index;
|
||||
toStart = forRangeKeywordsRegExp.lastIndex;
|
||||
} else if (rangeMatches[1] === 'step') {
|
||||
if (toStart === -1) {
|
||||
continue;
|
||||
}
|
||||
toEnd = rangeMatches.index;
|
||||
stepStart = forRangeKeywordsRegExp.lastIndex;
|
||||
stepEnd = remainder.length;
|
||||
}
|
||||
}
|
||||
|
||||
if (toStart === -1 || fromEnd === -1) {
|
||||
throw new Error('Invalid each attribute of "' + value + '"');
|
||||
}
|
||||
|
||||
var from = remainder.substring(fromStart, fromEnd).trim();
|
||||
var to = remainder.substring(toStart, toEnd).trim();
|
||||
var step;
|
||||
|
||||
from = convertNumber(from);
|
||||
to = convertNumber(to);
|
||||
|
||||
if (stepStart !== -1) {
|
||||
step = remainder.substring(stepStart, stepEnd).trim();
|
||||
step = convertNumber(step);
|
||||
} else {
|
||||
if (typeof from === 'number' && typeof to === 'number') {
|
||||
if (from < to) {
|
||||
step = 1;
|
||||
} else {
|
||||
step = -1;
|
||||
}
|
||||
} else {
|
||||
step = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
'nameVar': nameVar,
|
||||
'from': from,
|
||||
'to': to,
|
||||
'step': step
|
||||
};
|
||||
} else {
|
||||
throw new Error('Invalid each attribute of "' + value + '"');
|
||||
}
|
||||
}
|
||||
function ForNode(props) {
|
||||
@ -62,6 +143,47 @@ ForNode.prototype = {
|
||||
this.generateCodeForChildren(template);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parts.hasOwnProperty('from')) {
|
||||
// This is a range loop
|
||||
|
||||
|
||||
var nameVar = parts.nameVar;
|
||||
var from = parts.from;
|
||||
var to = parts.to;
|
||||
var step = parts.step;
|
||||
var comparison = '<=';
|
||||
|
||||
console.log("STEP!!!: ", step, from, to);
|
||||
if (typeof step === 'number') {
|
||||
if (step < 0) {
|
||||
comparison = '>=';
|
||||
}
|
||||
|
||||
if (step === 1) {
|
||||
step = nameVar + '++';
|
||||
} else if (step === -1) {
|
||||
step = nameVar + '--';
|
||||
} else if (step > 0) {
|
||||
step = nameVar + '+=' + step;
|
||||
} else if (step === 0) {
|
||||
throw new Error('Invalid step of 0');
|
||||
} else if (step < 0) {
|
||||
step = 0-step; // Make the step positive and switch to -=
|
||||
step = nameVar + '-=' + step;
|
||||
}
|
||||
} else {
|
||||
step = nameVar + '+=' + step;
|
||||
}
|
||||
|
||||
template.statement('(function() {').indent(function () {
|
||||
template.statement('for (var ' + nameVar + '=' + from + '; ' + nameVar + comparison + to + '; ' + step + ') {').indent(function () {
|
||||
this.generateCodeForChildren(template);
|
||||
}, this).line('}');
|
||||
}, this).line('}());');
|
||||
return;
|
||||
}
|
||||
|
||||
var items = template.makeExpression(parts['in']);
|
||||
var varName = parts['var'];
|
||||
var nameVarName = parts.nameVar;
|
||||
@ -83,6 +205,7 @@ ForNode.prototype = {
|
||||
}
|
||||
var funcName;
|
||||
var forEachParams;
|
||||
|
||||
if (customIterator) {
|
||||
var statusVarFlag = '';
|
||||
if (statusVar) {
|
||||
|
||||
@ -157,6 +157,10 @@ describe('raptor-templates/rhtml' , function() {
|
||||
it("should allow for looping over properties", function(done) {
|
||||
testRender("test-project/rhtml-templates/looping-props.rhtml", {}, done);
|
||||
});
|
||||
|
||||
it.only("should allow for looping over ranges", function(done) {
|
||||
testRender("test-project/rhtml-templates/looping-range.rhtml", {}, done);
|
||||
});
|
||||
|
||||
it("should allow for dynamic attributes", function(done) {
|
||||
testRender("test-project/rhtml-templates/attrs.rhtml", {"myAttrs": {style: "background-color: #FF0000; <test>", "class": "my-div"}}, done);
|
||||
|
||||
27
test/test-project/rhtml-templates/looping-range.rhtml
Normal file
27
test/test-project/rhtml-templates/looping-range.rhtml
Normal file
@ -0,0 +1,27 @@
|
||||
<c-for each="i from 0 to 9">
|
||||
$i
|
||||
</c-for>
|
||||
-
|
||||
<c-for each="i from 9 to 0">
|
||||
$i
|
||||
</c-for>
|
||||
-
|
||||
<c-for each="i from 9 to 0 step -1">
|
||||
$i
|
||||
</c-for>
|
||||
-
|
||||
<c-for each="i from 0 to 9 step 2">
|
||||
$i
|
||||
</c-for>
|
||||
-
|
||||
<c-for each="i from 9 to 0 step -2">
|
||||
$i
|
||||
</c-for>
|
||||
-
|
||||
<c-for each="i from 0 to 'abc'.length">
|
||||
$i
|
||||
</c-for>
|
||||
-
|
||||
<c-for each="i from ''.length to 'abc'.length">
|
||||
$i
|
||||
</c-for>
|
||||
@ -0,0 +1 @@
|
||||
0123456789 - 9876543210 - 9876543210 - 02468 - 97531 - 0123 - 0123
|
||||
Loading…
x
Reference in New Issue
Block a user