Repository: shepherdwind/velocity.js
Pull request #81 (2017-04-07 04:11:28)

support foreach.hasnext when iterating objects

coveralls: 
[![Coverage Status](https://coveralls.io/builds/10975265/badge)](https://coveralls.io/builds/10975265)

Coverage decreased (-0.2%) to 99.184% when pulling **f149fbf02a30aa9c08b2d24886be1367967b4a29 on rschick:obj-hasnext** into **198c9b6ff1c5de29bfc5d27a302d0aaf9078e5d0 on shepherdwind:master**.


Patch:
diff --git a/src/compile/blocks.js b/src/compile/blocks.js
index 09ce589..14adc17 100644
--- a/src/compile/blocks.js
+++ b/src/compile/blocks.js
@@ -195,29 +195,42 @@ module.exports = function(Velocity, utils) {
         return '';
       }
 
-      var len = utils.isArray(_from) ? _from.length : utils.keys(_from).length;
-
-      utils.forEach(_from, function(val, i) {
+      if (utils.isArray(_from)) {
+        var len = _from.length;
+        utils.forEach(_from, function(val, i) {
+          if (this._state.break) {
+            return;
+          }
+          // 构造临时变量
+          local[_to] = val;
+          local.foreach = {
+            count: i + 1,
+            index: i,
+            hasNext: i + 1 < len
+          };
+          local.velocityCount = i + 1;
 
-        if (this._state.break) {
-          return;
-        }
-        // 构造临时变量
-        local[_to] = val;
-        // TODO: here, the foreach variable give to local, when _from is not an
-        // array, count and hasNext would be undefined, also i is not the
-        // index.
-        local.foreach = {
-          count: i + 1,
-          index: i,
-          hasNext: i + 1 < len
-        };
-        local.velocityCount = i + 1;
-
-        this.local[contextId] = local;
-        ret += this._render(_block, contextId);
+          this.local[contextId] = local;
+          ret += this._render(_block, contextId);
 
-      }, this);
+        }, this);
+      } else {
+        var len = utils.keys(_from).length;
+        utils.forEach(utils.keys(_from), function(key, i) {
+          if (this._state.break) {
+            return;
+          }
+          local[_to] = _from[key];
+          local.foreach = {
+            count: i + 1,
+            index: i,
+            hasNext: i + 1 < len
+          };
+          local.velocityCount = i + 1;
+          this.local[contextId] = local;
+          ret += this._render(_block, contextId);
+        }, this);
+      }
 
       // if foreach items be an empty array, then this code will shift current
       // conditions, but not this._render call, so this will shift parent context


Test patch:
diff --git a/tests/foreach.test.js b/tests/foreach.test.js
index acf22fc..2195240 100644
--- a/tests/foreach.test.js
+++ b/tests/foreach.test.js
@@ -18,6 +18,12 @@ describe('Loops', function() {
     assert.equal(' name => hanwen ', render(vm, data))
   })
 
+  it('#foreach with map hasNext', function() {
+    var vm   = '#foreach($product in $products)$product.name#if($foreach.hasNext),#end#end'
+    var data = {products: {product1: {name: "hanwen1"}, product2: {name: "hanwen2"}, product3: {name: "hanwen3"}}};
+    assert.equal('hanwen1,hanwen2,hanwen3', render(vm, data))
+  })
+
   it('#foreach with map keySet', function() {
     var vm = '#foreach($key in $products.keySet())' +
     ' $key => $products.get($key) #end'
@@ -91,6 +97,13 @@ describe('Loops', function() {
     assert.equal('  1   2   3     4 ', render(vm))
   })
 
+  it('#break for map', function() {
+    var vm = '#foreach($item in $map)' +
+    ' #if($foreach.count > 2) #break #end $item #end'
+    var data = {map: {item1: '1', item2: '2', item3: '3', item4: '4'}}
+    assert.equal('  1   2     3 ', render(vm, data))
+  })
+
   it('foreach for null', function() {
     var vm = '#foreach($num in $bar) #end';
     assert.equal('', render(vm))