Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
bcc965b
custom elements off by default
yyx990803 Mar 3, 2014
8d65a07
make primitive arrays work with computed property
yyx990803 Mar 3, 2014
1d2c32d
copy attributes when replace:true
yyx990803 Mar 3, 2014
f98eb96
use `nodeValue` instead of `textContent` for textNodes
yyx990803 Mar 3, 2014
482a3ca
remove `customTags` option; custom tags only respected when containin…
Mar 5, 2014
3759313
strip log and warn in production build.
Mar 5, 2014
bedcb22
allow nested path for computed properties that return objects
yyx990803 Mar 6, 2014
ae2965c
eval
yyx990803 Mar 6, 2014
6f4c495
Compiler.prototype.eval
yyx990803 Mar 6, 2014
3ddf84e
rename test titles + compiler.eval test
yyx990803 Mar 6, 2014
d56feb0
enable interpolcation in literal directives except v-component
yyx990803 Mar 6, 2014
83def44
make dynamic resolving built-in for custom literal directives
yyx990803 Mar 6, 2014
f211326
simplify text regex
yyx990803 Mar 6, 2014
2fe832f
conditional components!
yyx990803 Mar 6, 2014
d06892b
component check fix
yyx990803 Mar 6, 2014
835dd0e
fix #161 event propagation control
Mar 7, 2014
cea54de
alias for v-repeat
Mar 7, 2014
656c015
simplify Compiler.eval
yyx990803 Mar 8, 2014
10a0cc1
v-view
yyx990803 Mar 9, 2014
09927a4
unit test for v-view
yyx990803 Mar 9, 2014
9a75612
slightly improve text parser perf (10%)
Mar 10, 2014
25344cf
Object.$add/$delete + renamed Array augmentation methods to prefix wi…
yyx990803 Mar 10, 2014
f1cd944
fix Array linking converting already converted objects, minor fix for…
Mar 10, 2014
e07f25d
change todomvc example to use computed property based implementation
Mar 10, 2014
4ebff99
computed filters first pass
Mar 11, 2014
607e197
computed filters + test
yyx990803 Mar 11, 2014
74590b2
custom filter API + exp parser unit test improvements
yyx990803 Mar 11, 2014
a8d5a35
also check for this[...] in computed filters
Mar 11, 2014
482fdc0
fix utils.warn not stripped in prod build
Mar 11, 2014
66abd23
fix meta property value checking
Mar 11, 2014
876f859
use gulp-component 0.1.6 with modified require header
Mar 11, 2014
e11f5fd
include src for bower
yyx990803 Mar 12, 2014
336d06d
filterBy & orderBy first pass
Mar 11, 2014
a249992
tests for array filters
yyx990803 Mar 12, 2014
5eddfd0
make array filters work with objects
Mar 12, 2014
2ddcae6
fix #172 `parent` option in Vue.extend
Mar 12, 2014
2059be5
bindable paramAttributes
Mar 12, 2014
665520f
v-component & v-with refactor
Mar 12, 2014
25be79c
clean up
Mar 12, 2014
c4897fa
remove duplicate array in compiler
Mar 12, 2014
775948d
refactor compile priority order
Mar 12, 2014
3df6343
v-if refactor + change to use childVM
Mar 13, 2014
f3af959
Collect dependencies on all types
yyx990803 Mar 13, 2014
984304c
allow config custom interpolation delimiters
Mar 13, 2014
5872bf3
fix #176 + node compiling perf improvements
Mar 13, 2014
55d8dbe
fix #176 again...
Mar 13, 2014
398bf7e
fix browserify can't deal with 'if' issue...
Mar 13, 2014
96541d5
add e.targetEl to account for e.currentTarget
Mar 14, 2014
dbe26cd
allow stop propagation if handler fn returns true
dyu Mar 15, 2014
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
filterBy & orderBy first pass
  • Loading branch information
Evan You authored and yyx990803 committed Mar 12, 2014
commit 336d06de1d0bddf7159d17db0cd218ca7a099358
1 change: 1 addition & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"node": true,
"laxbreak": true,
"evil": true,
"eqnull": true,
"globals": {
"console": true
}
Expand Down
5 changes: 1 addition & 4 deletions src/directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var utils = require('./utils'),

ARG_RE = /^([\w-$ ]+):(.+)$/,
FILTERS_RE = /\|[^\|]+/g,
FILTER_TOKEN_RE = /[^\s']+|'[^']+'/g,
FILTER_TOKEN_RE = /[^\s']+|'[^']+'|[^\s"]+|"[^"]+"/g,
NESTING_RE = /^\$(parent|root)\./,
SINGLE_VAR_RE = /^[\w\.$]+$/

Expand Down Expand Up @@ -110,9 +110,6 @@ function parseFilter (filter, compiler) {

var tokens = filter.slice(1).match(FILTER_TOKEN_RE)
if (!tokens) return
tokens = tokens.map(function (token) {
return token.replace(/'/g, '').trim()
})

var name = tokens[0],
apply = compiler.getOption('filters', name)
Expand Down
29 changes: 20 additions & 9 deletions src/exp-parser.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
var utils = require('./utils'),
stringSaveRE = /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,
stringRestoreRE = /"(\d+)"/g,
constructorRE = new RegExp('constructor'.split('').join('[\'"+, ]*')),
unicodeRE = /\\u\d\d\d\d/
STR_SAVE_RE = /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,
STR_RESTORE_RE = /"(\d+)"/g,
CTOR_RE = new RegExp('constructor'.split('').join('[\'"+, ]*')),
UNICODE_RE = /\\u\d\d\d\d/,
QUOTE_RE = /"/g

// Variable extraction scooped from https://github.com/RubyLouvre/avalon

Expand Down Expand Up @@ -94,7 +95,7 @@ function makeGetter (exp, raw) {
try {
fn = new Function(exp)
} catch (e) {
utils.warn('Invalid expression: ' + raw)
utils.warn('Error parsing expression: ' + raw)
}
return fn
}
Expand All @@ -108,14 +109,24 @@ function escapeDollar (v) {
: v
}

/**
* Convert double quotes to single quotes
* so they don't mess up the generated function body
*/
function escapeQuote (v) {
return v.indexOf('"') > -1
? v.replace(QUOTE_RE, '\'')
: v
}

/**
* Parse and return an anonymous computed property getter function
* from an arbitrary expression, together with a list of paths to be
* created as bindings.
*/
exports.parse = function (exp, compiler, data, filters) {
// unicode and 'constructor' are not allowed for XSS security.
if (unicodeRE.test(exp) || constructorRE.test(exp)) {
if (UNICODE_RE.test(exp) || CTOR_RE.test(exp)) {
utils.warn('Unsafe expression: ' + exp)
return
}
Expand All @@ -138,15 +149,15 @@ exports.parse = function (exp, compiler, data, filters) {
")[$\\w\\.]*\\b", 'g'
),
body = (' ' + exp)
.replace(stringSaveRE, saveStrings)
.replace(STR_SAVE_RE, saveStrings)
.replace(pathRE, replacePath)
.replace(stringRestoreRE, restoreStrings)
.replace(STR_RESTORE_RE, restoreStrings)

// wrap expression with computed filters
if (filters) {
filters.forEach(function (filter) {
var args = filter.args
? ',"' + filter.args.join('","') + '"'
? ',"' + filter.args.map(escapeQuote).join('","') + '"'
: ''
body =
'this.$compiler.getOption("filters", "' +
Expand Down
103 changes: 91 additions & 12 deletions src/filters.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,46 @@
var utils = require('./utils'),
get = utils.get,
slice = [].slice,
QUOTE_RE = /^'.*'$/

var keyCodes = {
enter : 13,
tab : 9,
'delete' : 46,
up : 38,
left : 37,
right : 39,
down : 40,
esc : 27
},
slice = [].slice
enter : 13,
tab : 9,
'delete' : 46,
up : 38,
left : 37,
right : 39,
down : 40,
esc : 27
}

/**
* String contain helper
*/
function contains (val, search) {
/* jshint eqeqeq: false */
if (utils.typeOf(val) === 'Object') {
for (var key in val) {
if (contains(val[key], search)) {
return true
}
}
} else if (val != null) {
return val.toString().toLowerCase().indexOf(search) > -1
}
}

module.exports = {
/**
* Test whether a string is in quotes,
* if yes return stripped string
*/
function stripQuotes (str) {
if (QUOTE_RE.test(str)) {
return str.slice(1, -1)
}
}

var filters = module.exports = {

/**
* 'abc' => 'Abc'
Expand Down Expand Up @@ -83,5 +113,54 @@ module.exports = {
handler.call(this, e)
}
}
},

filterBy: function (arr, searchKey, delimiter, dataKey) {

// get the search string
var search = stripQuotes(searchKey) || get(this, searchKey)
if (!search) return arr
search = search.toLowerCase()

// get the optional dataKey
dataKey = dataKey && (stripQuotes(dataKey) || get(this, dataKey))

return arr.filter(function (item) {
return dataKey
? contains(get(item, dataKey), search)
: contains(item, search)
})

},

orderBy: function (arr, sortKey, reverseKey) {

var key = stripQuotes(sortKey) || get(this, sortKey)
if (!key) return arr

var order = 1
if (reverseKey) {
if (reverseKey === '-1') {
order = -1
} else if (reverseKey.charAt(0) === '!') {
reverseKey = reverseKey.slice(1)
order = get(this, reverseKey) ? 1 : -1
} else {
order = get(this, reverseKey) ? -1 : 1
}
}

// sort on a copy to avoid mutating original array
return arr.slice().sort(function (a, b) {
a = a[key]
b = b[key]
return a === b ? 0 : a > b ? order : -order
})

}
}

}

// mark computed filters
filters.filterBy.computed = true
filters.orderBy.computed = true
7 changes: 7 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ var utils = module.exports = {
* get a value from an object keypath
*/
get: function (obj, key) {
if (key.indexOf('.') < 0) {
return obj[key]
}
var path = key.split('.'),
d = -1, l = path.length
while (++d < l && obj !== undefined) {
Expand All @@ -25,6 +28,10 @@ var utils = module.exports = {
* set a value to an object keypath
*/
set: function (obj, key, val) {
if (key.indexOf('.') < 0) {
obj[key] = val
return
}
var path = key.split('.'),
d = -1, l = path.length - 1
while (++d < l) {
Expand Down
63 changes: 63 additions & 0 deletions test/functional/fixtures/array-filters.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<!DOCTYPE html>
<script src="../../../dist/vue.js"></script>

<div id="test">
Sort by
<select v-model="sortKey">
<option>name</option>
<option>phone</option>
</select>
<br>
<input type="checkbox" v-model="reverse"> Reverse
<hr></hr>
Filter by <input 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">
<td>{{name}}</td>
<td>{{phone}}</td>
</tr>
</table>
<hr></hr>
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">
<td>{{name}}</td>
<td>{{phone}}</td>
</tr>
</table>
<hr></hr>
Filter by "Julie" in
<select v-model="filterKey">
<option>name</option>
<option>phone</option>
</select>
<table id="t3">
<tr><th>Name</th><th>Phone</th></tr>
<tr v-repeat="friends | filterBy 'Julie' in filterKey | orderBy sortKey -1">
<td>{{name}}</td>
<td>{{phone}}</td>
</tr>
</table>
</div>

<script>
new Vue({
el: '#test',
data: {
searchText: '',
filterKey: 'name',
sortKey: 'name',
reverse: false,
friends: [
{name:'John', phone:'555-1276', hidden: { id: 'hidden!' } },
{name:'Mary', phone:'800-BIG-MARY'},
{name:'Mike', phone:'555-4321'},
{name:'Adam', phone:'555-5678'},
{name:'Julie', phone:'555-8765'},
{name:'Juliette', phone:'555-5678'}
]
}
})
</script>
2 changes: 1 addition & 1 deletion test/unit/specs/directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ describe('Directive', function () {
assert.strictEqual(f.name, 'pluralize', 'name')
assert.strictEqual(f.args.length, 2, 'args length')
assert.strictEqual(f.args[0], 'item', 'args value 1')
assert.strictEqual(f.args[1], 'arg with spaces', 'args value 2')
assert.strictEqual(f.args[1], '\'arg with spaces\'', 'args value 2')
})

it('should extract correct filters (multiple filters)', function () {
Expand Down
24 changes: 24 additions & 0 deletions test/unit/specs/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,30 @@ describe('Filters', function () {

})

describe('filterBy', function () {

var filter = filters.filterBy

it('should be computed', function () {
assert.ok(filter.computed)
})

// TODO

})

describe('orderBy', function () {

var filter = filters.orderBy

it('should be computed', function () {
assert.ok(filter.computed)
})

// TODO

})

})

function assertNumberAndFalsy (filter) {
Expand Down