Przeglądaj źródła

allow config custom interpolation delimiters

Evan You 12 lat temu
rodzic
commit
984304c263
3 zmienionych plików z 110 dodań i 24 usunięć
  1. 11 2
      src/config.js
  2. 34 6
      src/text-parser.js
  3. 65 16
      test/unit/specs/api.js

+ 11 - 2
src/config.js

@@ -1,10 +1,19 @@
-module.exports = {
+var TextParser = require('./text-parser')
 
+module.exports = {
     prefix         : 'v',
     debug          : false,
     silent         : false,
     enterClass     : 'v-enter',
     leaveClass     : 'v-leave',
     interpolate    : true
+}
 
-}
+Object.defineProperty(module.exports, 'delimiters', {
+    get: function () {
+        return TextParser.delimiters
+    },
+    set: function (delimiters) {
+        TextParser.setDelimiters(delimiters)
+    }
+})

+ 34 - 6
src/text-parser.js

@@ -1,7 +1,31 @@
-var BINDING_RE = /{{{?(.+?)}?}}/
+var openChar  = '{',
+    endChar   = '}',
+    ESCAPE_RE  = /[-.*+?^${}()|[\]\/\\]/g,
+    BINDING_RE = buildInterpolationRegex()
 
-/**
+function buildInterpolationRegex () {
+    var open = escapeRegex(openChar),
+        end  = escapeRegex(endChar)
+    return new RegExp(open + open + open + '?(.+?)' + end + '?' + end + end)
+}
+
+function escapeRegex (str) {
+    return str.replace(ESCAPE_RE, '\\$&')
+}
+
+function setDelimiters (delimiters) {
+    exports.delimiters = delimiters
+    openChar = delimiters[0]
+    endChar = delimiters[1]
+    BINDING_RE = buildInterpolationRegex()
+}
+
+/** 
  *  Parse a piece of text, return an array of tokens
+ *  token types:
+ *  1. plain string
+ *  2. object with key = binding key
+ *  3. object with key & html = true
  */
 function parse (text) {
     if (!BINDING_RE.test(text)) return null
@@ -13,8 +37,8 @@ function parse (text) {
         token = { key: m[1].trim() }
         match = m[0]
         token.html =
-            match.charAt(2) === '{' &&
-            match.charAt(match.length - 3) === '}'
+            match.charAt(2) === openChar &&
+            match.charAt(match.length - 3) === endChar
         tokens.push(token)
         text = text.slice(i + m[0].length)
     }
@@ -25,6 +49,8 @@ function parse (text) {
 /**
  *  Parse an attribute value with possible interpolation tags
  *  return a Directive-friendly expression
+ *
+ *  e.g.  a {{b}} c  =>  "a " + b + " c"
  */
 function parseAttr (attr) {
     var tokens = parse(attr)
@@ -42,5 +68,7 @@ function parseAttr (attr) {
     return res.join('+')
 }
 
-exports.parse = parse
-exports.parseAttr = parseAttr
+exports.parse         = parse
+exports.parseAttr     = parseAttr
+exports.setDelimiters = setDelimiters
+exports.delimiters    = [openChar, endChar]

+ 65 - 16
test/unit/specs/api.js

@@ -7,19 +7,6 @@ describe('API', function () {
     describe('config()', function () {
 
         var config = require('vue/src/config')
-        
-        it('should work when changing prefix', function () {
-            var testId = 'config-1'
-            Vue.config({
-                prefix: 'test'
-            })
-            mock(testId, '<span test-text="test"></span>')
-            new Vue({
-                el: '#' + testId,
-                data: { test: testId }
-            })
-            assert.strictEqual(document.querySelector('#' + testId + ' span').innerHTML, testId)
-        })
 
         it('should get', function () {
             assert.strictEqual(Vue.config('debug'), false)
@@ -30,10 +17,72 @@ describe('API', function () {
             assert.strictEqual(config.test, 1)
         })
 
-        after(function () {
-            Vue.config({
-                prefix: 'v'
+        describe('changing prefix', function () {
+            
+            before(function () {
+                Vue.config({ prefix: 'test' })
+            })
+
+            after(function () {
+                Vue.config({ prefix: 'v' })
+            })
+
+            it('should work', function () {
+                var v = new Vue({
+                    template: '<span test-text="test"></span>',
+                    data: { test: 'helllllo' }
+                })
+                assert.strictEqual(v.$el.innerHTML, '<span>' + v.test + '</span>')
+            })
+
+        })
+
+        describe('changing interpolation delimiters', function () {
+            
+            before(function () {
+                Vue.config({ delimiters: ['[', ']'] })
+            })
+
+            after(function () {
+                Vue.config({ delimiters: ['{', '}'] })
+            })
+
+            it('should work', function () {
+                var v = new Vue({
+                    template: '<span>[[text]]</span><div>[[[html]]]</div>',
+                    data: {
+                        text: 'hello!!!',
+                        html: '<span><a>some raw html</a></span>'
+                    }
+                })
+
+                assert.strictEqual(v.$el.querySelector('span').innerHTML, v.text)
+                assert.strictEqual(v.$el.querySelector('div').innerHTML, v.html + '<!--v-html-->')
+            })
+
+        })
+
+        describe('skipping interpolation', function () {
+            
+            before(function () {
+                Vue.config({ interpolate: false })
             })
+
+            after(function () {
+                Vue.config({ interpolate: true })
+            })
+
+            it('should work', function () {
+                var raw = '<span class="{{text}}">{{text}}</span>'
+                var v = new Vue({
+                    template: raw,
+                    data: {
+                        text: 'hello!!!'
+                    }
+                })
+                assert.strictEqual(v.$el.innerHTML, raw)
+            })
+
         })
 
     })