2
0
Эх сурвалжийг харах

support filters inside text interpolations

Evan You 10 жил өмнө
parent
commit
9ff87a357e

+ 75 - 0
src/compiler/parser/filter-parser.js

@@ -0,0 +1,75 @@
+export function parseFilters (exp) {
+  let inSingle = false
+  let inDouble = false
+  let curly = 0
+  let square = 0
+  let paren = 0
+  let lastFilterIndex = 0
+  let c, prev, i, expression, filters
+
+  for (i = 0; i < exp.length; i++) {
+    prev = c
+    c = exp.charCodeAt(i)
+    if (inSingle) {
+      // check single quote
+      if (c === 0x27 && prev !== 0x5C) inSingle = !inSingle
+    } else if (inDouble) {
+      // check double quote
+      if (c === 0x22 && prev !== 0x5C) inDouble = !inDouble
+    } else if (
+      c === 0x7C && // pipe
+      exp.charCodeAt(i + 1) !== 0x7C &&
+      exp.charCodeAt(i - 1) !== 0x7C &&
+      !curly && !square && !paren
+    ) {
+      if (expression === undefined) {
+        // first filter, end of expression
+        lastFilterIndex = i + 1
+        expression = exp.slice(0, i).trim()
+      } else {
+        pushFilter()
+      }
+    } else {
+      switch (c) {
+        case 0x22: inDouble = true; break // "
+        case 0x27: inSingle = true; break // '
+        case 0x28: paren++; break         // (
+        case 0x29: paren--; break         // )
+        case 0x5B: square++; break        // [
+        case 0x5D: square--; break        // ]
+        case 0x7B: curly++; break         // {
+        case 0x7D: curly--; break         // }
+      }
+    }
+  }
+
+  if (expression === undefined) {
+    expression = exp.slice(0, i).trim()
+  } else if (lastFilterIndex !== 0) {
+    pushFilter()
+  }
+
+  function pushFilter () {
+    (filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim())
+    lastFilterIndex = i + 1
+  }
+
+  if (filters) {
+    for (i = 0; i < filters.length; i++) {
+      expression = wrapFilter(expression, filters[i])
+    }
+  }
+
+  return expression
+}
+
+function wrapFilter (exp, filter) {
+  const i = filter.indexOf('(')
+  if (i < 0) {
+    return `__resolveFilter__("${filter}")(${exp})`
+  } else {
+    const name = filter.slice(0, i)
+    const args = filter.slice(i + 1)
+    return `__resolveFilter__("${name}")(${exp},${args}`
+  }
+}

+ 21 - 9
src/compiler/parser/index.js

@@ -300,7 +300,17 @@ function processComponent (el) {
 
 function processClassBinding (el) {
   const staticClass = getAndRemoveAttr(el, 'class')
-  el.staticClass = parseText(staticClass, delimiters) || JSON.stringify(staticClass)
+  if (process.env.NODE_ENV !== 'production') {
+    const expression = parseText(staticClass, delimiters)
+    if (expression) {
+      warn(
+        `class="${staticClass}": ` +
+        'Interpolation inside attributes has been deprecated. ' +
+        'Use v-bind or the colon shorthand instead.'
+      )
+    }
+  }
+  el.staticClass = JSON.stringify(staticClass)
   const classBinding = getBindingAttr(el, 'class', false /* getStatic */)
   if (classBinding) {
     el.classBinding = classBinding
@@ -357,15 +367,17 @@ function processAttrs (el) {
       }
     } else {
       // literal attribute
-      let expression = parseText(value, delimiters)
-      if (expression) {
-        warn(
-          'Interpolation inside attributes has been deprecated. ' +
-          'Use v-bind or the colon shorthand instead.'
-        )
-      } else {
-        addStaticAttr(el, name, JSON.stringify(value))
+      if (process.env.NODE_ENV !== 'production') {
+        const expression = parseText(value, delimiters)
+        if (expression) {
+          warn(
+            `${name}="${value}": ` +
+            'Interpolation inside attributes has been deprecated. ' +
+            'Use v-bind or the colon shorthand instead.'
+          )
+        }
       }
+      addStaticAttr(el, name, JSON.stringify(value))
     }
   }
 }

+ 2 - 1
src/compiler/parser/text-parser.js

@@ -1,4 +1,5 @@
 import { cached } from 'shared/util'
+import { parseFilters } from './filter-parser'
 
 const defaultTagRE = /\{\{((?:.|\\n)+?)\}\}/g
 const regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g
@@ -24,7 +25,7 @@ export function parseText (text, delimiters) {
       tokens.push(JSON.stringify(text.slice(lastIndex, index)))
     }
     // tag token
-    const exp = match[1].trim()
+    const exp = parseFilters(match[1].trim())
     tokens.push(`__toString__(${exp})`)
     lastIndex = index + match[0].length
   }

+ 2 - 1
src/core/config.js

@@ -37,7 +37,8 @@ export default {
   _assetTypes: [
     'component',
     'directive',
-    'transition'
+    'transition',
+    'filters'
   ],
 
   /**

+ 7 - 0
src/core/instance/render.js

@@ -1,6 +1,7 @@
 import createElement from '../vdom/create-element'
 import { flatten } from '../vdom/helpers'
 import { bind, isArray, isObject, renderString } from 'shared/util'
+import { resolveAsset } from '../util/options'
 
 export const renderState = {
   activeInstance: null
@@ -42,6 +43,12 @@ export function renderMixin (Vue) {
   // toString for mustaches
   Vue.prototype.__toString__ = renderString
 
+  // filter resolution helper
+  const identity = _ => _
+  Vue.prototype.__resolveFilter__ = function (id) {
+    return resolveAsset(this.$options, 'filters', id, true) || identity
+  }
+
   // render v-for
   Vue.prototype.__renderList__ = function (val, render) {
     let ret, i, l, keys, key