diff --git a/src/compiler/helpers.js b/src/compiler/helpers.js index 2772ebefe60..ad974a347be 100644 --- a/src/compiler/helpers.js +++ b/src/compiler/helpers.js @@ -94,3 +94,87 @@ export function getAndRemoveAttr (el: ASTElement, name: string): ?string { } return val } + +let len, str, chr, index, expressionPos, expressionEndPos + +/** + * parse directive model to do the array update transform. a[idx] = val => $$a.splice($$idx, 1, val) + * + * for loop possible cases: + * + * - test + * - test[idx] + * - test[test1[idx]] + * - test["a"][idx] + * - xxx.test[a[a].test1[idx]] + * - test.xxx.a["asa"][test1[idx]] + * + */ + +export function parseModel (val: string): Object { + str = val + len = str.length + index = expressionPos = expressionEndPos = 0 + + if (val.indexOf('[') < 0) { + return { + exp: val, + idx: null + } + } + + while (!eof()) { + chr = next() + /* istanbul ignore if */ + if (isStringStart(chr)) { + parseString(chr) + } else if (chr === 0x5B) { + parseBracket(chr) + } + } + + return { + exp: val.substring(0, expressionPos), + idx: val.substring(expressionPos + 1, expressionEndPos) + } +} + +function next (): number { + return str.charCodeAt(++index) +} + +function eof (): boolean { + return index >= len +} + +function isStringStart (chr: number): boolean { + return chr === 0x22 || chr === 0x27 +} + +function parseBracket (chr: number): void { + let inBracket = 1 + expressionPos = index + while (!eof()) { + chr = next() + if (isStringStart(chr)) { + parseString(chr) + continue + } + if (chr === 0x5B) inBracket++ + if (chr === 0x5D) inBracket-- + if (inBracket === 0) { + expressionEndPos = index + break + } + } +} + +function parseString (chr: number): void { + const stringQuote = chr + while (!eof()) { + chr = next() + if (chr === stringQuote) { + break + } + } +} diff --git a/src/platforms/web/compiler/directives/model.js b/src/platforms/web/compiler/directives/model.js index 2ae6b711452..5363e545b1c 100644 --- a/src/platforms/web/compiler/directives/model.js +++ b/src/platforms/web/compiler/directives/model.js @@ -1,8 +1,7 @@ /* @flow */ import { isIE } from 'core/util/env' -import { addHandler, addProp, getBindingAttr } from 'compiler/helpers' -import parseModel from 'web/util/model' +import { addHandler, addProp, getBindingAttr, parseModel } from 'compiler/helpers' let warn diff --git a/src/platforms/web/util/model.js b/src/platforms/web/util/model.js deleted file mode 100644 index 45b2b7645e3..00000000000 --- a/src/platforms/web/util/model.js +++ /dev/null @@ -1,85 +0,0 @@ -/* @flow */ - -let len, str, chr, index, expressionPos, expressionEndPos - -/** - * parse directive model to do the array update transform. a[idx] = val => $$a.splice($$idx, 1, val) - * - * for loop possible cases: - * - * - test - * - test[idx] - * - test[test1[idx]] - * - test["a"][idx] - * - xxx.test[a[a].test1[idx]] - * - test.xxx.a["asa"][test1[idx]] - * - */ - -export default function parseModel (val: string): Object { - str = val - len = str.length - index = expressionPos = expressionEndPos = 0 - - if (val.indexOf('[') < 0) { - return { - exp: val, - idx: null - } - } - - while (!eof()) { - chr = next() - /* istanbul ignore if */ - if (isStringStart(chr)) { - parseString(chr) - } else if (chr === 0x5B) { - parseBracket(chr) - } - } - - return { - exp: val.substring(0, expressionPos), - idx: val.substring(expressionPos + 1, expressionEndPos) - } -} - -function next (): number { - return str.charCodeAt(++index) -} - -function eof (): boolean { - return index >= len -} - -function isStringStart (chr: number): boolean { - return chr === 0x22 || chr === 0x27 -} - -function parseBracket (chr: number): void { - let inBracket = 1 - expressionPos = index - while (!eof()) { - chr = next() - if (isStringStart(chr)) { - parseString(chr) - continue - } - if (chr === 0x5B) inBracket++ - if (chr === 0x5D) inBracket-- - if (inBracket === 0) { - expressionEndPos = index - break - } - } -} - -function parseString (chr: number): void { - const stringQuote = chr - while (!eof()) { - chr = next() - if (chr === stringQuote) { - break - } - } -} diff --git a/src/platforms/weex/compiler/directives/index.js b/src/platforms/weex/compiler/directives/index.js index efba7fa6977..12ced224ab7 100755 --- a/src/platforms/weex/compiler/directives/index.js +++ b/src/platforms/weex/compiler/directives/index.js @@ -1,2 +1,5 @@ +import model from './model' + export default { + model } diff --git a/src/platforms/weex/compiler/directives/model.js b/src/platforms/weex/compiler/directives/model.js new file mode 100644 index 00000000000..8ed61905f0e --- /dev/null +++ b/src/platforms/weex/compiler/directives/model.js @@ -0,0 +1,39 @@ +/* @flow */ + +import { addHandler, addAttr, parseModel } from 'compiler/helpers' + +export default function model ( + el: ASTElement, + dir: ASTDirective, + _warn: Function +): ?boolean { + genDefaultModel(el, dir.value, dir.modifiers) +} + +function genDefaultModel ( + el: ASTElement, + value: string, + modifiers: ?ASTModifiers +): ?boolean { + const { lazy, trim } = modifiers || {} + const event = lazy ? 'change' : 'input' + const isNative = el.tag === 'input' || el.tag === 'textarea' + const valueExpression = isNative + ? `$event.target.attr.value${trim ? '.trim()' : ''}` + : `$event` + const code = genAssignmentCode(value, valueExpression) + addAttr(el, 'value', `(${value})`) + addHandler(el, event, code, null, true) +} + +function genAssignmentCode (value: string, assignment: string): string { + const modelRs = parseModel(value) + if (modelRs.idx === null) { + return `${value}=${assignment}` + } else { + return `var $$exp = ${modelRs.exp}, $$idx = ${modelRs.idx};` + + `if (!Array.isArray($$exp)){` + + `${value}=${assignment}}` + + `else{$$exp.splice($$idx, 1, ${assignment})}` + } +} diff --git a/test/unit/features/directives/model-parse.spec.js b/test/unit/features/directives/model-parse.spec.js index 54692b0e60a..6d3a617f130 100644 --- a/test/unit/features/directives/model-parse.spec.js +++ b/test/unit/features/directives/model-parse.spec.js @@ -1,4 +1,4 @@ -import parseModel from 'web/util/model' +import { parseModel } from 'compiler/helpers' describe('model expression parser', () => { it('parse string in brackets', () => { diff --git a/test/weex/compiler/class.spec.js b/test/weex/compiler/class.spec.js index 7f3b3ec2fb0..fe6492e38b4 100644 --- a/test/weex/compiler/class.spec.js +++ b/test/weex/compiler/class.spec.js @@ -1,4 +1,5 @@ import { compile } from '../../../packages/weex-template-compiler' +import { strToRegExp } from '../helpers/index' describe('compile class', () => { it('should be compiled', () => { @@ -6,7 +7,7 @@ describe('compile class', () => { expect(render).not.toBeUndefined() expect(staticRenderFns).not.toBeUndefined() expect(staticRenderFns.length).toEqual(1) - expect(staticRenderFns).toMatch(/staticClass\:\["a","b","c"\]/) + expect(staticRenderFns).toMatch(strToRegExp(`staticClass:["a","b","c"]`)) expect(errors).toEqual([]) }) @@ -14,18 +15,18 @@ describe('compile class', () => { const { render, staticRenderFns, errors } = compile(`
`) expect(render).not.toBeUndefined() expect(staticRenderFns).toEqual([]) - expect(render).toMatch(/class\:\["a",_s\(b\),"c"\]/) + expect(render).toMatch(strToRegExp(`class:["a",_s(b),"c"]`)) expect(errors).not.toBeUndefined() expect(errors.length).toEqual(1) - expect(errors[0]).toMatch(/a \{\{b\}\} c/) - expect(errors[0]).toMatch(/v\-bind/) + expect(errors[0]).toMatch(strToRegExp(`a {{b}} c`)) + expect(errors[0]).toMatch(strToRegExp(`v-bind`)) }) it('should compile class binding of array', () => { const { render, staticRenderFns, errors } = compile(``) expect(render).not.toBeUndefined() expect(staticRenderFns).toEqual([]) - expect(render).toMatch(/class\:\['a', 'b', c\]/) + expect(render).toMatch(strToRegExp(`class:['a', 'b', c]`)) expect(errors).toEqual([]) }) @@ -33,7 +34,7 @@ describe('compile class', () => { const { render, staticRenderFns, errors } = compile(``) expect(render).not.toBeUndefined() expect(staticRenderFns).toEqual([]) - expect(render).toMatch(/class\:\{ a\: true, b\: x \}/) + expect(render).toMatch(strToRegExp(`class:{ a: true, b: x }`)) expect(errors).toEqual([]) }) @@ -41,7 +42,7 @@ describe('compile class', () => { const { render, staticRenderFns, errors } = compile(``) expect(render).not.toBeUndefined() expect(staticRenderFns).toEqual([]) - expect(render).toMatch(/class\:x/) + expect(render).toMatch(strToRegExp(`class:x`)) expect(errors).toEqual([]) }) @@ -49,7 +50,7 @@ describe('compile class', () => { const { render, staticRenderFns, errors } = compile(``) expect(render).not.toBeUndefined() expect(staticRenderFns).toEqual([]) - expect(render).toMatch(/class\:\['a', 'b', c\]/) + expect(render).toMatch(strToRegExp(`class:['a', 'b', c]`)) expect(errors).toEqual([]) }) }) diff --git a/test/weex/compiler/style.spec.js b/test/weex/compiler/style.spec.js index 9066a167ccc..c8d427644e9 100644 --- a/test/weex/compiler/style.spec.js +++ b/test/weex/compiler/style.spec.js @@ -1,4 +1,5 @@ import { compile } from '../../../packages/weex-template-compiler' +import { strToRegExp } from '../helpers/index' describe('compile style', () => { it('should be compiled', () => { @@ -6,7 +7,7 @@ describe('compile style', () => { expect(render).not.toBeUndefined() expect(staticRenderFns).not.toBeUndefined() expect(staticRenderFns.length).toEqual(1) - expect(staticRenderFns).toMatch(/staticStyle\:\{a:"x",b:"y"\}/) + expect(staticRenderFns).toMatch(strToRegExp(`staticStyle:{a:"x",b:"y"}`)) expect(errors).toEqual([]) }) @@ -24,7 +25,7 @@ describe('compile style', () => { expect(render).not.toBeUndefined() expect(staticRenderFns).not.toBeUndefined() expect(staticRenderFns.length).toEqual(1) - expect(staticRenderFns).toMatch(/staticStyle\:\{a:"x",b:"y"\}/) + expect(staticRenderFns).toMatch(strToRegExp(`staticStyle:{a:"x",b:"y"}`)) expect(errors).toEqual([]) }) @@ -33,7 +34,7 @@ describe('compile style', () => { expect(render).not.toBeUndefined() expect(staticRenderFns).not.toBeUndefined() expect(staticRenderFns.length).toEqual(1) - expect(staticRenderFns).toMatch(/staticStyle\:\{AbcDef\:"x-y",abcDef\:"x-y"\}/) + expect(staticRenderFns).toMatch(strToRegExp(`staticStyle:{AbcDef:"x-y",abcDef:"x-y"}`)) expect(errors).toEqual([]) }) @@ -41,18 +42,18 @@ describe('compile style', () => { const { render, staticRenderFns, errors } = compile(``) expect(render).not.toBeUndefined() expect(staticRenderFns).toEqual([]) - expect(render).toMatch(/style\:\{a:"x",b:_s\(y\)\}/) + expect(render).toMatch(strToRegExp(`style:{a:"x",b:_s(y)}`)) expect(errors).not.toBeUndefined() expect(errors.length).toEqual(1) - expect(errors[0]).toMatch(/b\: \{\{y\}\}/) - expect(errors[0]).toMatch(/v\-bind/) + expect(errors[0]).toMatch(strToRegExp(`b: {{y}}`)) + expect(errors[0]).toMatch(strToRegExp(`v-bind`)) }) it('should compile style binding of array', () => { const { render, staticRenderFns, errors } = compile(``) expect(render).not.toBeUndefined() expect(staticRenderFns).toEqual([]) - expect(render).toMatch(/style\:\[a, b, c\]/) + expect(render).toMatch(strToRegExp(`style:[a, b, c]`)) expect(errors).toEqual([]) }) @@ -60,7 +61,7 @@ describe('compile style', () => { const { render, staticRenderFns, errors } = compile(``) expect(render).not.toBeUndefined() expect(staticRenderFns).toEqual([]) - expect(render).toMatch(/style\:\{ a\: x, b\: 'y' \+ z \}/) + expect(render).toMatch(strToRegExp(`style:{ a: x, b: 'y' + z }`)) expect(errors).toEqual([]) }) @@ -68,7 +69,7 @@ describe('compile style', () => { const { render, staticRenderFns, errors } = compile(``) expect(render).not.toBeUndefined() expect(staticRenderFns).toEqual([]) - expect(render).toMatch(/style\:x/) + expect(render).toMatch(strToRegExp(`style:x`)) expect(errors).toEqual([]) }) @@ -76,7 +77,7 @@ describe('compile style', () => { const { render, staticRenderFns, errors } = compile(``) expect(render).not.toBeUndefined() expect(staticRenderFns).toEqual([]) - expect(render).toMatch(/style\:\[a, b, c\]/) + expect(render).toMatch(strToRegExp(`style:[a, b, c]`)) expect(errors).toEqual([]) }) }) diff --git a/test/weex/compiler/v-model.spec.js b/test/weex/compiler/v-model.spec.js new file mode 100644 index 00000000000..3e869c99f1a --- /dev/null +++ b/test/weex/compiler/v-model.spec.js @@ -0,0 +1,56 @@ +import { compile } from '../../../packages/weex-template-compiler' +import { strToRegExp } from '../helpers/index' + +describe('compile v-model', () => { + it('should compile modelable native component', () => { + const { render, staticRenderFns, errors } = compile(``) + expect(render).not.toBeUndefined() + expect(render).toMatch(strToRegExp(`attrs:{"value":(x)}`)) + expect(render).toMatch(strToRegExp(`on:{"input":function($event){x=$event.target.attr.value}}`)) + expect(staticRenderFns).toEqual([]) + expect(errors).toEqual([]) + }) + + it('should compile into render functions without runtime model directive', () => { + }) + + it('should compile other component with whole $event as the value', () => { + const { render, staticRenderFns, errors } = compile(`