ソースを参照

array filters

Evan You 11 年 前
コミット
b768d0c1f3

+ 2 - 1
src/api/data.js

@@ -105,7 +105,8 @@ exports.$eval = function (text) {
     return dir.filters
       ? _.applyFilters(
           this.$get(dir.expression),
-          _.resolveFilters(this, dir.filters).read
+          _.resolveFilters(this, dir.filters).read,
+          this
         )
       : this.$get(dir.expression)
   } else {

+ 17 - 16
src/directives/index.js

@@ -1,23 +1,24 @@
 var directives = module.exports = Object.create(null)
 
 // manipulation directives
-directives.text      = require('./text')
-directives.html      = require('./html')
-directives.attr      = require('./attr')
-directives.show      = require('./show')
-directives['class']  = require('./class')
-directives.ref       = require('./ref')
-directives.cloak     = require('./cloak')
-directives.style     = require('./style')
-directives.partial   = require('./partial')
+directives.text       = require('./text')
+directives.html       = require('./html')
+directives.attr       = require('./attr')
+directives.show       = require('./show')
+directives['class']   = require('./class')
+directives.ref        = require('./ref')
+directives.cloak      = require('./cloak')
+directives.style      = require('./style')
+directives.partial    = require('./partial')
+directives.transition = require('./transition')
 
 // event listener directives
-directives.on        = require('./on')
-directives.model     = require('./model')
+directives.on         = require('./on')
+directives.model      = require('./model')
 
 // child vm directives
-directives.view      = require('./view')
-directives.component = require('./component')
-directives.repeat    = require('./repeat')
-directives['if']     = require('./if')
-directives['with']   = require('./with')
+directives.view       = require('./view')
+directives.component  = require('./component')
+directives.repeat     = require('./repeat')
+directives['if']      = require('./if')
+directives['with']    = require('./with')

+ 17 - 0
src/directives/model.js

@@ -0,0 +1,17 @@
+module.exports = {
+
+  priority: 800,
+
+  bind: function () {
+    
+  },
+
+  update: function () {
+    
+  },
+
+  unbind: function () {
+    
+  }
+
+}

+ 2 - 0
src/directives/on.js

@@ -4,6 +4,8 @@ module.exports = {
 
   isFn: true,
 
+  priority: 700,
+
   bind: function () {
     // deal with iframes
     if (

+ 9 - 0
src/directives/transition.js

@@ -0,0 +1,9 @@
+module.exports = {
+
+  priority: 1000,
+
+  bind: function () {
+    this.el.__vueTransition = this.expression
+  }
+
+}

+ 2 - 0
src/directives/with.js

@@ -1,5 +1,7 @@
 module.exports = {
 
+  priority: 900,
+
   bind: function () {
     if (this.arg) {
       var self = this

+ 121 - 0
src/filters/array-filters.js

@@ -0,0 +1,121 @@
+var _ = require('../util')
+var Path = require('../parse/path')
+
+/**
+ * Attempt to convert non-Array objects to array.
+ * This is the default filter installed to every v-repeat
+ * directive.
+ *
+ * @param {*} obj
+ * @return {Array}
+ * @private
+ */
+
+exports._objToArray = function (obj) {
+  if (_.isArray(obj)) {
+    return obj
+  }
+  if (!_.isObject(obj)) {
+    _.warn(
+      'Invalid value for v-repeat: ' + obj +
+      '\nOnly Arrays and Objects are allowed.'
+    )
+    return
+  }
+  var res = []
+  var val, data
+  for (var key in obj) {
+    res.push({
+      key: key,
+      value: obj[key]
+    })
+  }
+  res._converted = true
+  return res
+}
+
+/**
+ * Filter filter for v-repeat
+ *
+ * @param {String} searchKey
+ * @param {String} [delimiter]
+ * @param {String} dataKey
+ */
+
+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) ||
+    this.$get(searchKey)
+  if (!search) {
+    return arr
+  }
+  search = search.toLowerCase()
+  // get the optional dataKey
+  dataKey =
+    dataKey &&
+    (stripQuotes(dataKey) || this.$get(dataKey))
+  return arr.filter(function (item) {
+    return dataKey
+      ? contains(Path.get(item, dataKey), search)
+      : contains(item, search)
+  })
+}
+
+/**
+ * Filter filter for v-repeat
+ *
+ * @param {String} sortKey
+ * @param {String} reverseKey
+ */
+
+exports.orderBy = function (arr, sortKey, reverseKey) {
+  var key =
+    _.stripQuotes(sortKey) ||
+    this.$get(sortKey)
+  if (!key) {
+    return arr
+  }
+  var order = 1
+  if (reverseKey) {
+    if (reverseKey === '-1') {
+      order = -1
+    } else if (reverseKey.charCodeAt(0) === 0x21) { // !
+      reverseKey = reverseKey.slice(1)
+      order = this.$get(reverseKey) ? 1 : -1
+    } else {
+      order = this.$get(reverseKey) ? -1 : 1
+    }
+  }
+  // sort on a copy to avoid mutating original array
+  return arr.slice().sort(function (a, b) {
+    a = Path.get(a, key)
+    b = Path.get(b, key)
+    return a === b ? 0 : a > b ? order : -order
+  })
+}
+
+/**
+ * String contain helper
+ *
+ * @param {*} val
+ * @param {String} search
+ */
+
+function contains (val, search) {
+  /* jshint eqeqeq: false */
+  if (_.isObject(val)) {
+    for (var key in val) {
+      if (contains(val[key], search)) {
+        return true
+      }
+    }
+  } else if (val != null) {
+    return val.toString().toLowerCase().indexOf(search) > -1
+  }
+}

+ 111 - 1
src/filters/index.js

@@ -1 +1,111 @@
-module.exports = Object.create(null)
+var _ = require('../util')
+var filters = module.exports = Object.create(null)
+
+/**
+ * 'abc' => 'Abc'
+ */
+
+filters.capitalize = function (value) {
+  if (!value && value !== 0) return ''
+  value = value.toString()
+  return value.charAt(0).toUpperCase() + value.slice(1)
+}
+
+/**
+ * 'abc' => 'ABC'
+ */
+
+filters.uppercase = function (value) {
+  return (value || value === 0)
+    ? value.toString().toUpperCase()
+    : ''
+}
+
+/**
+ * 'AbC' => 'abc'
+ */
+
+filters.lowercase = function (value) {
+  return (value || value === 0)
+    ? value.toString().toLowerCase()
+    : ''
+}
+
+/**
+ * 12345 => $12,345.00
+ *
+ * @param {String} sign
+ */
+
+var digitsRE = /(\d{3})(?=\d)/g
+
+filters.currency = function (value, sign) {
+  value = parseFloat(value)
+  if (!value && value !== 0) return ''
+  sign = sign || '$'
+  var s = Math.floor(value).toString(),
+    i = s.length % 3,
+    h = i > 0
+      ? (s.slice(0, i) + (s.length > 3 ? ',' : ''))
+      : '',
+    f = '.' + value.toFixed(2).slice(-2)
+  return sign + h + s.slice(i).replace(digitsRE, '$1,') + f
+}
+
+/**
+ * 'item' => 'items'
+ *
+ * @params
+ *  an array of strings corresponding to
+ *  the single, double, triple ... forms of the word to
+ *  be pluralized. When the number to be pluralized
+ *  exceeds the length of the args, it will use the last
+ *  entry in the array.
+ *
+ *  e.g. ['single', 'double', 'triple', 'multiple']
+ */
+
+filters.pluralize = function (value) {
+  var args = slice.call(arguments, 1)
+  return args.length > 1
+    ? (args[value - 1] || args[args.length - 1])
+    : (args[value - 1] || args[0] + 's')
+}
+
+/**
+ * A special filter that takes a handler function,
+ * wraps it so it only gets triggered on specific
+ * keypresses. v-on only.
+ *
+ * @param {String} key
+ */
+
+var keyCodes = {
+  enter    : 13,
+  tab      : 9,
+  'delete' : 46,
+  up       : 38,
+  left     : 37,
+  right    : 39,
+  down     : 40,
+  esc      : 27
+}
+
+filters.key = function (handler, key) {
+  if (!handler) return
+  var code = keyCodes[key]
+  if (!code) {
+    code = parseInt(key, 10)
+  }
+  return function (e) {
+    if (e.keyCode === code) {
+      return handler.call(this, e)
+    }
+  }
+}
+
+/**
+ * Install special array filters
+ */
+
+_.extend(filters, require('./array-filters'))

+ 3 - 2
src/util/filter.js

@@ -61,15 +61,16 @@ exports.resolveFilters = function (vm, filters, target) {
  *
  * @param {*} value
  * @param {Array} filters
+ * @param {Vue} vm
  * @return {*}
  */
 
-exports.applyFilters = function (value, filters) {
+exports.applyFilters = function (value, filters, vm) {
   if (!filters) {
     return value
   }
   for (var i = 0, l = filters.length; i < l; i++) {
-    value = filters[i](value)
+    value = filters[i].call(vm, value)
   }
   return value
 }

+ 2 - 0
src/util/lang.js

@@ -49,6 +49,7 @@ exports.guardNumber = function (value) {
  *
  * @param {Function} fn
  * @param {Object} ctx
+ * @return {Function}
  */
 
 exports.bind = function (fn, ctx) {
@@ -62,6 +63,7 @@ exports.bind = function (fn, ctx) {
  *
  * @param {Array-like} list
  * @param {Number} [i] - start index
+ * @return {Array}
  */
 
 var slice = [].slice

+ 1 - 1
src/vue.js

@@ -38,7 +38,7 @@ Vue.options = {
   directives    : require('./directives'),
   filters       : require('./filters'),
   partials      : {},
-  effects       : {},
+  transitions   : {},
   components    : {},
   inheritScope  : true
 }

+ 2 - 2
src/watcher.js

@@ -97,7 +97,7 @@ p.addDep = function (path) {
 p.get = function () {
   this.beforeGet()
   var value = this.getter.call(this.vm, this.vm.$scope)
-  value = _.applyFilters(value, this.readFilters)
+  value = _.applyFilters(value, this.readFilters, this.vm)
   this.afterGet()
   return value
 }
@@ -109,7 +109,7 @@ p.get = function () {
  */
 
 p.set = function (value) {
-  value = _.applyFilters(value, this.writeFilters)
+  value = _.applyFilters(value, this.writeFilters, this.vm)
   this.setter.call(this.vm, this.vm.$scope, value)
 }