2
0
Evan You 12 жил өмнө
parent
commit
a2499921b8

+ 2 - 2
src/compiler.js

@@ -572,7 +572,7 @@ CompilerProto.createBinding = function (key, directive) {
             } else {
                 compiler.defineMeta(key, binding)
             }
-        } else if (computed && computed[key.split('.')[0]]) {
+        } else if (computed && computed[utils.baseKey(key)]) {
             // nested path on computed property
             compiler.defineExp(key, binding)
         } else {
@@ -725,7 +725,7 @@ CompilerProto.execHook = function (event) {
  *  Check if a compiler's data contains a keypath
  */
 CompilerProto.hasKey = function (key) {
-    var baseKey = key.split('.')[0]
+    var baseKey = utils.baseKey(key)
     return hasOwn.call(this.data, baseKey) ||
         hasOwn.call(this.vm, baseKey)
 }

+ 8 - 2
src/filters.js

@@ -117,6 +117,12 @@ var filters = module.exports = {
 
     filterBy: function (arr, searchKey, delimiter, dataKey) {
 
+        // allow optional `in` delimiter
+        // because why not
+        if (delimiter && delimiter !== 'in') {
+            dataKey = delimiter
+        }
+
         // get the search string
         var search = stripQuotes(searchKey) || get(this, searchKey)
         if (!search) return arr
@@ -152,8 +158,8 @@ var filters = module.exports = {
 
         // sort on a copy to avoid mutating original array
         return arr.slice().sort(function (a, b) {
-            a = a[key]
-            b = b[key]
+            a = get(a, key)
+            b = get(b, key)
             return a === b ? 0 : a > b ? order : -order
         })
 

+ 10 - 1
src/utils.js

@@ -3,7 +3,7 @@ var config    = require('./config'),
     win       = window,
     console   = win.console,
     timeout   = win.setTimeout,
-    THIS_RE   = /[^\w]this[\.\[]/,
+    THIS_RE   = /[^\w]this[^\w]/,
     hasClassList = 'classList' in document.documentElement,
     ViewModel // late def
 
@@ -43,6 +43,15 @@ var utils = module.exports = {
         obj[path[d]] = val
     },
 
+    /**
+     *  return the base segment of a keypath
+     */
+    baseKey: function (key) {
+        return key.indexOf('.') > 0
+            ? key.split('.')[0]
+            : key
+    },
+
     /**
      *  Create a prototype-less object
      *  which is a better hash/map

+ 8 - 7
test/functional/fixtures/array-filters.html

@@ -3,17 +3,17 @@
 
 <div id="test">
     Sort by
-    <select v-model="sortKey">
+    <select id="sortby" v-model="sortKey">
         <option>name</option>
         <option>phone</option>
     </select>
     <br>
-    <input type="checkbox" v-model="reverse"> Reverse
+    <input id="reverse" type="checkbox" v-model="reverse"> Reverse
     <hr></hr>
-    Filter by <input v-model="searchText"> in name only
+    Filter by <input id="search" name="search" v-model="searchText"> in name only
     <table id="t1">
         <tr><th>Name</th><th>Phone</th></tr>
-        <tr v-repeat="friends | filterBy searchText in 'name' | orderBy sortKey reverse">
+        <tr v-repeat="friends | filterBy searchText in 'name' | orderBy sortKey reverse" class="item">
             <td>{{name}}</td>
             <td>{{phone}}</td>
         </tr>
@@ -22,20 +22,21 @@
     Filter by input in all fields and reversed
     <table id="t2">
         <tr><th>Name</th><th>Phone</th></tr>
-        <tr v-repeat="friends | filterBy searchText | orderBy sortKey !reverse">
+        <tr v-repeat="friends | filterBy searchText | orderBy sortKey !reverse" class="item">
             <td>{{name}}</td>
             <td>{{phone}}</td>
         </tr>
     </table>
     <hr></hr>
     Filter by "Julie" in
-    <select v-model="filterKey">
+    <select id="filterby" v-model="filterKey">
         <option>name</option>
         <option>phone</option>
     </select>
+    and reversed with literal -1
     <table id="t3">
         <tr><th>Name</th><th>Phone</th></tr>
-        <tr v-repeat="friends | filterBy 'Julie' in filterKey | orderBy sortKey -1">
+        <tr v-repeat="friends | filterBy 'Julie' in filterKey | orderBy sortKey -1" class="item">
             <td>{{name}}</td>
             <td>{{phone}}</td>
         </tr>

+ 80 - 0
test/functional/specs/array-filters.js

@@ -0,0 +1,80 @@
+casper.test.begin('Array Filters', 53, function (test) {
+
+    var names = ['Adam', 'John', 'Julie', 'Juliette', 'Mary', 'Mike'],
+        namesReversed = names.slice().reverse(),
+        numbers = ['555-1276', '555-4321', '555-5678', '555-5678', '555-8765', '800-BIG-MARY'],
+        numbersReversed = numbers.slice().reverse(),
+        julie = ['Juliette', 'Julie'],
+        julieRevesed = julie.slice().reverse()
+    
+    casper
+    .start('./fixtures/array-filters.html')
+    .then(function () {
+        // count
+        test.assertElementCount('#t1 .item', 6)
+        test.assertElementCount('#t2 .item', 6)
+        test.assertElementCount('#t3 .item', 2)
+
+        assertOrder(names, 1)
+        assertOrder(namesReversed, 2)
+        assertOrder(julie, 3)
+    })
+    // reverse
+    .thenClick('#reverse', function () {
+        assertOrder(namesReversed, 1)
+        assertOrder(names, 2)
+    })
+    // change sort key
+    .thenEvaluate(function () {
+        var dropdown = document.getElementById('sortby')
+        dropdown.selectedIndex = 1
+        var e = document.createEvent('HTMLEvents')
+        e.initEvent('change', true, true)
+        dropdown.dispatchEvent(e)
+    })
+    .then(function () {
+        assertOrder(numbersReversed, 1)
+        assertOrder(numbers, 2)
+        assertOrder(julieRevesed, 3)
+    })
+    // enter search filter
+    .then(function () {
+        this.sendKeys('#search', 'julie')
+    })
+    .then(function () {
+        test.assertElementCount('#t1 .item', 2)
+        test.assertElementCount('#t2 .item', 2)
+        test.assertElementCount('#t3 .item', 2)
+        assertOrder(julieRevesed, 1)
+        assertOrder(julie, 2)
+    })
+    // enter search filter for numbers
+    .then(function () {
+        this.sendKeys('#search', '555', { reset: true })
+    })
+    .then(function () {
+        test.assertElementCount('#t1 .item', 0)
+        test.assertElementCount('#t2 .item', 5)
+    })
+    // change filterkey
+    .thenEvaluate(function () {
+        var dropdown = document.getElementById('filterby')
+        dropdown.selectedIndex = 1
+        var e = document.createEvent('HTMLEvents')
+        e.initEvent('change', true, true)
+        dropdown.dispatchEvent(e)
+    })
+    .then(function () {
+        test.assertElementCount('#t3 .item', 0)
+    })
+    .run(function () {
+        test.done()
+    })
+
+    function assertOrder (list, id) {
+        list.forEach(function (n, i) {
+            test.assertSelectorHasText('#t' + id + ' .item:nth-child('+ (i+2) + ')', n)
+        })
+    }
+
+})

+ 65 - 4
test/unit/specs/filters.js

@@ -130,25 +130,86 @@ describe('Filters', function () {
 
     describe('filterBy', function () {
         
-        var filter = filters.filterBy
+        var filter = filters.filterBy,
+            arr = [
+                { a: 1, b: { c: 'hello' }},
+                { a: 1, b: 'hello'},
+                { a: 1, b: 2 }
+            ],
+            vm = { search: { key: 'hello', datakey: 'b.c' }}
 
         it('should be computed', function () {
             assert.ok(filter.computed)
         })
 
-        // TODO
+        it('should recursively check for searchKey if no dataKey is provided', function () {
+            var res = filter.call(vm, arr, 'search.key')
+            assert.strictEqual(res.length, 2)
+            assert.deepEqual(res, arr.slice(0, 2))
+        })
+
+        it('should check for datakey only if provided', function () {
+            var res = filter.call(vm, arr, 'search.key', 'search.datakey')
+            assert.strictEqual(res.length, 1)
+            assert.strictEqual(res[0], arr[0])
+        })
+
+        it('should use literal searchKey if in single quotes', function () {
+            var res = filter.call(vm, arr, "'hello'", "'b.c'")
+            assert.strictEqual(res.length, 1)
+            assert.strictEqual(res[0], arr[0])
+        })
+
+        it('should accept optional delimiter', function () {
+            var res = filter.call(vm, arr, 'search.key', 'in', 'search.datakey')
+            assert.strictEqual(res.length, 1)
+            assert.strictEqual(res[0], arr[0])
+        })
 
     })
 
     describe('orderBy', function () {
 
-        var filter = filters.orderBy
+        var filter = filters.orderBy,
+            arr = [
+                { a: { b: 0 }, c: 'b'},
+                { a: { b: 2 }, c: 'c'},
+                { a: { b: 1 }, c: 'a'}
+            ]
         
         it('should be computed', function () {
             assert.ok(filter.computed)
         })
 
-        // TODO
+        it('should sort based on sortKey', function () {
+            var vm = { sortby: 'a.b' }
+            var res = filter.call(vm, arr, 'sortby')
+            assert.strictEqual(res[0].a.b, 0)
+            assert.strictEqual(res[1].a.b, 1)
+            assert.strictEqual(res[2].a.b, 2)
+        })
+
+        it('should sort based on sortKey and reverseKey', function () {
+            var vm = { sortby: 'a.b', reverse: true }
+            var res = filter.call(vm, arr, 'sortby', 'reverse')
+            assert.strictEqual(res[0].a.b, 2)
+            assert.strictEqual(res[1].a.b, 1)
+            assert.strictEqual(res[2].a.b, 0)
+        })
+
+        it('should sort with literal args and special -1 syntax', function () {
+            var res = filter.call({}, arr, "'c'", '-1')
+            assert.strictEqual(res[0].c, 'c')
+            assert.strictEqual(res[1].c, 'b')
+            assert.strictEqual(res[2].c, 'a')
+        })
+
+        it('should accept negate reverse key', function () {
+            var res = filter.call({ reverse: true }, arr, "'c'", '!reverse')
+            assert.strictEqual(res[0].c, 'a')
+            assert.strictEqual(res[1].c, 'b')
+            assert.strictEqual(res[2].c, 'c')
+        })
 
     })