diff --git a/example/component/simple/computed.vue b/example/component/simple/computed.vue new file mode 100644 index 0000000..82530fb --- /dev/null +++ b/example/component/simple/computed.vue @@ -0,0 +1,25 @@ + + + \ No newline at end of file diff --git a/example/component/simple/index.vue b/example/component/simple/index.vue index 46e0b97..d6d3d8b 100644 --- a/example/component/simple/index.vue +++ b/example/component/simple/index.vue @@ -23,6 +23,7 @@ + @@ -36,6 +37,7 @@ import Reactive from './reactive'; import Slot from './slot'; import Transition from './transition'; import TransitionGroup from './transition-group'; +import Computed from './computed'; export default { props: { @@ -70,7 +72,8 @@ export default { 'e-trans-group': TransitionGroup, 'a-sync': function (resolve) { import('./async.vue').then(c => resolve(c.default)); - } + }, + computed: Computed }, methods: { onClick(e) { diff --git a/jest.config.js b/jest.config.js index 7d8d8f5..26e7ccf 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,12 @@ module.exports = { verbose: true, collectCoverage: true, - collectCoverageFrom: ['/src/**'], + collectCoverageFrom: [ + '/src/**', + '!/src/runtime/bind-data.js', + '!/src/runtime/bind-data-proxy.js', + '!/src/runtime/calc-computed-observe.js' + ], testTimeout: 30000, projects: [ { diff --git a/packages/compiler/index.js b/packages/compiler/index.js index 5d7cc33..76e5138 100644 --- a/packages/compiler/index.js +++ b/packages/compiler/index.js @@ -1,4 +1,4 @@ -/* ! +/*! * vusa v1.0.0 * (c) 2019-2021 * Released under the MIT License. */ @@ -422,7 +422,7 @@ function transform (code) { const bindKeys$1 = [':class', 'v-bind:class']; -function postTransformNode$c(node) { +function postTransformNode$d(node) { if (node.type === 1 && node.classBinding) { const staticClass = node.attrsMap.class || ''; const classBinding = transform(node.attrsMap[bindKeys$1[0]] || node.attrsMap[bindKeys$1[1]]).code; @@ -433,7 +433,7 @@ function postTransformNode$c(node) { } var clazz = { - postTransformNode: postTransformNode$c, + postTransformNode: postTransformNode$d, }; /** @@ -443,7 +443,7 @@ var clazz = { const bindKeys = [':style', 'v-bind:style', 'v-show']; -function postTransformNode$b(node) { +function postTransformNode$c(node) { let vShow = node.attrsMap['v-show']; if (node.type === 1 && (node.styleBinding || vShow)) { @@ -464,7 +464,7 @@ function postTransformNode$b(node) { } var style = { - postTransformNode: postTransformNode$b, + postTransformNode: postTransformNode$c, }; /** @@ -474,8 +474,7 @@ var style = { const reBind = /^(v-bind)?\:/; -function postTransformNode$a(node) { - // console.log('bind~~~~~~~~~~~~~~~~~'); +function postTransformNode$b(node) { if (node.type !== 1) { return; @@ -495,7 +494,6 @@ function postTransformNode$a(node) { } node.attrsMap[attr] = attrValue; // node.attrsMap[key.replace(reBind, '')] = `{{ ${code} }}`; - node.attrsMap[key.replace(reBind, '')] = `{{ ${code} }}`; // node.attrsMap[key.replace(reBind, '')] = `{{ _b(${code})}}`; } @@ -521,7 +519,7 @@ function postTransformNode$a(node) { } var bind = { - postTransformNode: postTransformNode$a, + postTransformNode: postTransformNode$b, }; /** @@ -529,7 +527,7 @@ var bind = { * @author cxtom(cxtom2008@gmail.com) */ -function postTransformNode$9(node) { +function postTransformNode$a(node) { if (node.type !== 1) { return; } @@ -551,7 +549,7 @@ function postTransformNode$9(node) { } var yf = { - postTransformNode: postTransformNode$9, + postTransformNode: postTransformNode$a, }; /** @@ -559,7 +557,7 @@ var yf = { * @author cxtom(cxtom2008@gmail.com) */ -function postTransformNode$8(node) { +function postTransformNode$9(node) { if (node.type !== 1 || !node.for) { return; @@ -593,7 +591,7 @@ function postTransformNode$8(node) { } var fr = { - postTransformNode: postTransformNode$8, + postTransformNode: postTransformNode$9, }; function stripWith(code) { @@ -641,7 +639,7 @@ function getName() { return nanoid$1(); } -function postTransformNode$7(node, options) { +function postTransformNode$8(node, options) { const eventAttrs = node.attrsList.filter(n => reEvent.test(n.name)); for (const attr of eventAttrs) { delete node.attrsMap[attr.name]; @@ -678,7 +676,7 @@ function postTransformNode$7(node, options) { } var event = { - postTransformNode: postTransformNode$7, + postTransformNode: postTransformNode$8, }; /** @@ -686,7 +684,7 @@ var event = { * @author cxtom(cxtom2008@gmail.com) */ -function postTransformNode$6(node) { +function postTransformNode$7(node) { if (node.attrsMap && node.attrsMap['v-dangerous-html']) { const dir = node.directives.find(d => d.name === 'dangerous-html'); @@ -725,7 +723,7 @@ function postTransformNode$6(node) { } var html = { - postTransformNode: postTransformNode$6, + postTransformNode: postTransformNode$7, }; /** @@ -733,7 +731,7 @@ var html = { * @author cxtom(cxtom2008@gmail.com) */ -function postTransformNode$5(node, options) { +function postTransformNode$6(node, options) { if (node.type !== 1 || !node.attrsMap.ref && !node.attrsMap[':ref']) { return; } @@ -759,7 +757,7 @@ function postTransformNode$5(node, options) { } var ref = { - postTransformNode: postTransformNode$5 + postTransformNode: postTransformNode$6 }; /** @@ -767,7 +765,7 @@ var ref = { * @author cxtom(cxtom2008@gmail.com) */ -function postTransformNode$4(node, options) { +function postTransformNode$5(node, options) { if (!(node.type === 1 && node.tag === 'component')) { return; @@ -786,7 +784,7 @@ function postTransformNode$4(node, options) { } var dynamicComponent = { - postTransformNode: postTransformNode$4, + postTransformNode: postTransformNode$5, }; /** @@ -990,7 +988,7 @@ const htmlTag = { * @author cxtom(cxtom2008@gmail.com) */ -function postTransformNode$3(node) { +function postTransformNode$4(node) { if (!node.type === 1 || !node.attrsMap) { return; } @@ -1000,12 +998,17 @@ function postTransformNode$3(node) { if ((htmlTag[node.tag] && booleanAttr[key]) || noValueAttr[key]) { continue; } + + // input 标签 的 value 不做处理 + if (node.tag === 'input' && (key === 'value' || key === ':value')) { + continue; + } node.attrsMap[key] = `{{ true }}`; } } var bool = { - postTransformNode: postTransformNode$3 + postTransformNode: postTransformNode$4 }; /** @@ -1037,7 +1040,7 @@ function getAttrs(attrsMap) { }); } -function postTransformNode$2(el) { +function postTransformNode$3(el) { if (el.tag === 'transition') { el.tag = 'fragment'; @@ -1075,7 +1078,7 @@ function postTransformNode$2(el) { } var transition = { - postTransformNode: postTransformNode$2, + postTransformNode: postTransformNode$3, }; /** @@ -1083,7 +1086,7 @@ var transition = { * @author cxtom(cxtom2008@gmail.com) */ -function postTransformNode$1(el, state) { +function postTransformNode$2(el, state) { if (el.children && el.children.length > 0) { for (const child of el.children) { if (child.type !== 2 || !child.tokens || child.tokens.length <= 1) { @@ -1113,7 +1116,7 @@ function postTransformNode$1(el, state) { } var textCombine = { - postTransformNode: postTransformNode$1, + postTransformNode: postTransformNode$2, }; /** @@ -1122,7 +1125,7 @@ var textCombine = { */ -function postTransformNode(node) { +function postTransformNode$1(node) { if (node.type !== 1) { return; @@ -1171,6 +1174,43 @@ function postTransformNode(node) { } var forIf = { + postTransformNode: postTransformNode$1, +}; + +/** + * @file 处理v-model的情况 + * @author donghualei + */ + +function postTransformNode(node) { + + if (node.type !== 1 + || !node.attrsMap.hasOwnProperty('v-model') + || (node.tag !== 'input' && node.tag !== 'select')) { + return; + } + + const type = node.attrsMap.type; + + if (node.tag === 'input') { + + // 处理 input 的场景,text的场景 + if (type === 'text' || !type && !node.attrsMap.hasOwnProperty('value')) { + node.attrsMap.value = `{= ${transform(node.attrsMap['v-model']).code} =}`; + } + // 有 value 则为 type = checkbox 或者 radio 的场景 + else { + node.attrsMap.checked = `{= ${transform(node.attrsMap['v-model']).code} =}`; + } + } + else if (node.tag === 'select') { + node.attrsMap.value = `{= ${transform(node.attrsMap['v-model']).code} =}`; + } + + delete node.attrsMap['v-model']; +} + +var model = { postTransformNode, }; @@ -1192,6 +1232,7 @@ var buildInModules = [ clazz, style, + model, // bind 放在所有处理完之后 bind, @@ -1263,9 +1304,7 @@ function stringify(ast, {scopeId, strip, atom}) { */ const camelize = str => str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : '')); - -/** - * 获取数据类型 +/* 获取数据类型 * @param {any} data 源对象 * @returns {string} 'Function' | 'Undefined' | 'Null' | 'Object' | 'Boolean' | 'String' | 'Number' | 'RegExp' | 'Symbol' | 'BigInt'|'HTMLDivElement'; */ @@ -1367,13 +1406,11 @@ function compile(source, options = {}) { } const template = stringify(ast, {scopeId, strip, atom: isAtom}); - const aNode = sanAnodeUtils.parseTemplate(template, { trimWhitespace: 'blank', }).children[0]; // if (ast.tag === 'child') { - // if (ast.tag === 'div1') { // console.log('---------------------------------'); // console.log('ast', ast.children[0]); // console.log('aNode', aNode.children[0]); diff --git a/packages/runtime/vusa.js b/packages/runtime/vusa.js index 5945922..c942c50 100644 --- a/packages/runtime/vusa.js +++ b/packages/runtime/vusa.js @@ -243,6 +243,13 @@ return res; }); + /** + * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). + */ + function noop$1() {} + /** * @file loop expression * @author cxtom(cxtom2008@gmail.com) @@ -565,7 +572,6 @@ : [globalOptions, options]; var methods = {}; - for (var i = 0, len = list.length; i < len; i++) { var opt = list[i]; opt.methods && extend(methods, opt.methods); @@ -644,7 +650,12 @@ } resetTarget(); - var value = computed[computedExpr].call(this); + var userDef = computed[computedExpr]; + if (typeof userDef === 'object') { + userDef = userDef.get || noop$1; + } + + var value = userDef.call(this); var deps = Dep.target; cleanTarget(); diff --git a/packages/runtime/vusa.min.js b/packages/runtime/vusa.min.js index a687c25..8a9ce87 100644 --- a/packages/runtime/vusa.min.js +++ b/packages/runtime/vusa.min.js @@ -1 +1 @@ -(function(e,t){"object"===typeof exports&&"undefined"!==typeof module?t(exports,require("san")):"function"===typeof define&&define.amd?define(["exports","san"],t):(e="undefined"!==typeof globalThis?globalThis:e||self,t(e.Vusa={},e.san))})(this,(function(e,t){"use strict";function n(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t["default"]=e,Object.freeze(t)}var r=n(t),a=t.Data.prototype.get;t.Data.prototype.get=function(e,n){if(!e)return this.raw;var r=e;"string"===typeof e?e=t.parseExpr(e):r=e.paths.map((function(e){return e.value})).join("."),this._dep&&this._dep.depend({key:r,expr:e});var o=a.call(this,e,n);if(!e||void 0!==o||!this.owner||e.type!==t.ExprType.ACCESSOR)return o;var i=e.paths,s=i[0].value;if(this.owner._propKeys.concat(this.owner._dataKeys,this.owner._computedKeys).indexOf(s)>=0)return o;for(var c=1,u=i.length;null!=o&&c-1)return e.splice(n,1)}}var c=Object.prototype.toString;function u(e){return null!==e&&"object"===typeof e}var f=Object.prototype.hasOwnProperty;function p(e,t){return f.call(e,t)}function l(e){return"[object Object]"===c.call(e)}function d(e){return null==e?"":Array.isArray(e)||l(e)&&e.toString===c?JSON.stringify(e,null,2):String(e)}function v(e,t,n){Object.defineProperty(e,t,o({enumerable:!1,configurable:!0},n))}function h(e){var t=Object.create(null);return function(n){var r=t[n];return r||(t[n]=e(n))}}var y=/([^-])([A-Z])/g,m=h((function(e){return e.replace(y,"$1-$2").replace(y,"$1-$2").toLowerCase()})),b=function(e){return e.replace(/-(\w)/g,(function(e,t){return t?t.toUpperCase():""}))};function _(e){var t=!1;return function(){var n=[],r=arguments.length;while(r--)n[r]=arguments[r];t||(t=!0,e.apply(this,n))}}var g="function"===typeof Object.freeze;function C(e){return g&&u(e)?Object.freeze(e):e}function O(e){return{type:t.ExprType.ACCESSOR,paths:[{type:1,value:e}]}}function x(e){return"string"===typeof e||"number"===typeof e||"symbol"===typeof e||"boolean"===typeof e}function w(e){var t=parseFloat(String(e));return t>=0&&Math.floor(t)===t&&isFinite(e)}var A=h((function(e){var t={},n=/;(?![^(]*\))/g,r=/:(.+)/;return e.split(n).forEach((function(e){if(e){var n=e.split(r);n.length>1&&(t[n[0].trim()]=n[1].trim())}})),t})),j=h((function(e){for(var t=new Array(e),n=0;n=0?t+n:e.length+n;return e.slice(t,r)},z.array_join=function(e,t){return e.join(t)},z.str_pos=function(e,t){return e.indexOf(t)},z.object_freeze=function(e){return Object.freeze(e)};var F={json:function(e){return JSON.stringify(e)},lower:function(e){return e.toLowerCase()},upper:function(e){return e.toUpperCase()},_s:function(e){return d(e)},_cat:function(e,t){return e||0===e||(e=""),t||0===t||(t=""),e.toString()+t.toString()},_mc:D,_ms:M},q=["filters"],J={methods:z,filters:F};function G(e,t){return t?e?e.concat(t):Array.isArray(t)?t:[t]:e}function I(e){for(var t={},n=Array.isArray(e.mixins)?[J].concat(e.mixins,[e]):[J,e],r={},a=0,i=n.length;a1&&a.children.forEach(n)}}Y.prototype.walk=function(e){for(var t=this.keys,n=0;n-1?t.split(ce).forEach((function(t){return e.classList.add(t)})):e.classList.add(t);else{var n=" "+(e.getAttribute("class")||"")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function fe(e,t){if(t&&(t=t.trim()))if(e.classList)t.indexOf(" ")>-1?t.split(ce).forEach((function(t){return e.classList.remove(t)})):e.classList.remove(t),e.classList.length||e.removeAttribute("class");else{var n=" "+(e.getAttribute("class")||"")+" ",r=" "+t+" ";while(n.indexOf(r)>=0)n=n.replace(r," ");n=n.trim(),n?e.setAttribute("class",n):e.removeAttribute("class")}}var pe=h((function(e){return{enterClass:e+"-enter",enterToClass:e+"-enter-to",enterActiveClass:e+"-enter-active",leaveClass:e+"-leave",leaveToClass:e+"-leave-to",leaveActiveClass:e+"-leave-active"}}));function le(e){if(e){if("object"===typeof e){var t={};return!1!==e.css&&o(t,pe(e.name||"v")),o(t,e),t}return"string"===typeof e?pe(e):void 0}}var de="undefined"!==typeof window,ve="transition",he="animation",ye="transition",me="transitionend",be="animation",_e="animationend";de&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(ye="WebkitTransition",me="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(be="WebkitAnimation",_e="webkitAnimationEnd"));var ge=de?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(e){return e()};function Ce(e){ge((function(){ge(e)}))}var Oe=/\b(transform|all)(,|$)/;function xe(e,t){var n,r=window.getComputedStyle(e),a=(r[ye+"Delay"]||"").split(", "),o=(r[ye+"Duration"]||"").split(", "),i=we(a,o),s=(r[be+"Delay"]||"").split(", "),c=(r[be+"Duration"]||"").split(", "),u=we(s,c),f=0,p=0;t===ve?i>0&&(n=ve,f=i,p=o.length):t===he?u>0&&(n=he,f=u,p=c.length):(f=Math.max(i,u),n=f>0?i>u?ve:he:null,p=n?n===ve?o.length:c.length:0);var l=n===ve&&Oe.test(r[ye+"Property"]);return{type:n,timeout:f,propCount:p,hasTransform:l}}function we(e,t){while(e.length=i&&f()},f=function(){e.removeEventListener(s,u),n()};setTimeout((function(){c1,P=e._enterCb=_((function(){S&&(Ee(e,O),Ee(e,C)),P.cancelled?(S&&Ee(e,g),j&&j(e)):A&&A(e),e._enterCb=null}));w&&w(e,P),x&&x(e),S&&(je(e,g),je(e,C),Ce((function(){Ee(e,g),P.cancelled||(je(e,O),$||(ke(E)?setTimeout(P,E):Te(e,r,P)))}))),S||$||P(),t()}}function P(e,t){if(e._enterCb&&(e._enterCb.cancelled=!0,e._enterCb()),!e._leaveCb){var n=N(w),a=N(E),o=N(x),i=N(A),s=+(u(k)?k.leave:k),c=n&&n.length>1,f=e._leaveCb=_((function(){S&&(Ee(e,C),Ee(e,O)),f.cancelled?(S&&Ee(e,g),j&&j(e)):(t(),i&&i(e)),e._leaveCb=null}));a?a(p):p()}function p(){f.cancelled||(o&&o(e),S&&(je(e,g),je(e,O),Ce((function(){Ee(e,g),f.cancelled||(je(e,C),c||(ke(s)?setTimeout(f,s):Te(e,r,f)))}))),n&&n(e,f),S||c||f())}}}function Ne(e){return e.split(/(?=<)/g).map((function(e){if(/^<\//.test(e)||e.indexOf(">")<0)return e;var t=/\s*(on[^\s"'<>\/=]+)\s*=/gi,n=e.indexOf(">"),r=e.slice(n+1),a=e.slice(0,n+1).replace(t,(function(e,t){return e.replace(t,t+"-safe")}));return a+r})).join("")}function $e(e){if(e.indexOf("<")>-1){var t=/(()|())/gi,n={"<":"<",">":">",'"':"""};return e=e.replace(t,(function(e){return e.replace(/([<>"])/g,(function(e){return n[e]}))})),Ne(e)}return e}function Pe(e){return"[object Object]"===Object.prototype.toString.call(e)}function Re(e){return null==e?"":Array.isArray(e)||Pe(e)&&e.toString===Object.prototype.toString?JSON.stringify(e,null,2):String(e)}function De(e){return!0===e||e&&"string"===typeof e?"disabled":e}var Le="__COMPONENT_REFERENCE__",Ke=function(){},Me=function(e){return this.filters[e]},Ue={$activate:ie,$deactivate:se,_l:E,_ex:o,_ocp:k,_noop:Ke,_t:Se,_sf:$e,_f:Me,_h:Re,$emit:t.Component.prototype.fire,$on:t.Component.prototype.on,$watch:t.Component.prototype.watch,$nextTick:t.nextTick,$set:ne,_da:De},ze=t.defineComponent(Ue),Fe={$el:function(){return this.el},$data:function(){return this.data&&this.data.raw},$context:function(){return this.owner},$parent:function(){return this.parentComponent},$children:function(){return this._rootNode&&this.tagName!==this._rootNode.tagName&&this.children.unshift(this._rootNode),this.children.filter((function(e){return 5===e.nodeType}))},$root:function(){var e=this;if(this.parentComponent)while(e.parentComponent)e=e.parentComponent;return e},$slots:ae,_isDestroyed:function(){return!!this.lifeCycle.disposed}},qe=t.Component.prototype._update;t.Component.prototype._update=function(e){e&&this._toPhase("beforeUpdate"),qe.call(this,e)};var Je="_SanCtor",Ge=O("$style");function Ie(e){if(e&&e[Le])return e;if(e instanceof t.Component||e instanceof ze){var n=e.prototype;if(!n.hasOwnProperty("_cmptReady")){var r=e.components||n.components||{};n.components=We(r),n._cmptReady=1}return e}return"function"===typeof e?t.createComponentLoader((function(){return new Promise((function(t){e((function(e){t(Be(e))}))}))})):e.template||e.aNode||e.aPack?(e.components&&(e.components=We(e.components),e._cmptReady=1),t.defineComponent(e)):Be(e)}function We(e){return e=Object.keys(e).reduce((function(t,n){var r=e[n];return t[n]=t[m(n)]=Ie(r),t}),o({},J.components))}function Be(e){if(e.hasOwnProperty(Je))return e[Je];if("function"===typeof e)return Ie(e);var n={};if(e.components&&(n.components=We(e.components),n._cmptReady=1),e.template||e.aNode||e.aPack||e instanceof t.Component||e instanceof ze)return t.defineComponent(o({},e,n));var r=e.__sanOptimizeSSR||!1,a=o(n,{template:e.__santemplate,aNode:e.__sanaNode,aPack:e.__sanaPack,_isSan:!0},I(e)),i=e.__sanRefs,s=a.inited;a.inited=function(){var t=this,n=this;if(!r&&(this.$refs=Object.create(null),i)){for(var a=function(e,t){var r=i[e];v(n.$refs,r.name,{get:function(){return r.root?n.el:n.ref(r.name)}})},o=0,c=i.length;o0&&!Array.isArray(e.props))for(var c=0,f=i.length;c=0)return o;for(var c=1,u=i.length;null!=o&&c-1)return e.splice(n,1)}}var c=Object.prototype.toString;function u(e){return null!==e&&"object"===typeof e}var f=Object.prototype.hasOwnProperty;function p(e,t){return f.call(e,t)}function l(e){return"[object Object]"===c.call(e)}function d(e){return null==e?"":Array.isArray(e)||l(e)&&e.toString===c?JSON.stringify(e,null,2):String(e)}function v(e,t,n){Object.defineProperty(e,t,o({enumerable:!1,configurable:!0},n))}function h(e){var t=Object.create(null);return function(n){var r=t[n];return r||(t[n]=e(n))}}var y=/([^-])([A-Z])/g,m=h((function(e){return e.replace(y,"$1-$2").replace(y,"$1-$2").toLowerCase()})),b=function(e){return e.replace(/-(\w)/g,(function(e,t){return t?t.toUpperCase():""}))};function _(e){var t=!1;return function(){var n=[],r=arguments.length;while(r--)n[r]=arguments[r];t||(t=!0,e.apply(this,n))}}var g="function"===typeof Object.freeze;function C(e){return g&&u(e)?Object.freeze(e):e}function O(e){return{type:t.ExprType.ACCESSOR,paths:[{type:1,value:e}]}}function x(e){return"string"===typeof e||"number"===typeof e||"symbol"===typeof e||"boolean"===typeof e}function w(e){var t=parseFloat(String(e));return t>=0&&Math.floor(t)===t&&isFinite(e)}var j=h((function(e){var t={},n=/;(?![^(]*\))/g,r=/:(.+)/;return e.split(n).forEach((function(e){if(e){var n=e.split(r);n.length>1&&(t[n[0].trim()]=n[1].trim())}})),t}));function A(){}var E=h((function(e){for(var t=new Array(e),n=0;n=0?t+n:e.length+n;return e.slice(t,r)},F.array_join=function(e,t){return e.join(t)},F.str_pos=function(e,t){return e.indexOf(t)},F.object_freeze=function(e){return Object.freeze(e)};var q={json:function(e){return JSON.stringify(e)},lower:function(e){return e.toLowerCase()},upper:function(e){return e.toUpperCase()},_s:function(e){return d(e)},_cat:function(e,t){return e||0===e||(e=""),t||0===t||(t=""),e.toString()+t.toString()},_mc:L,_ms:U},J=["filters"],G={methods:F,filters:q};function I(e,t){return t?e?e.concat(t):Array.isArray(t)?t:[t]:e}function W(e){for(var t={},n=Array.isArray(e.mixins)?[G].concat(e.mixins,[e]):[G,e],r={},a=0,i=n.length;a1&&a.children.forEach(n)}}ee.prototype.walk=function(e){for(var t=this.keys,n=0;n-1?t.split(ue).forEach((function(t){return e.classList.add(t)})):e.classList.add(t);else{var n=" "+(e.getAttribute("class")||"")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function pe(e,t){if(t&&(t=t.trim()))if(e.classList)t.indexOf(" ")>-1?t.split(ue).forEach((function(t){return e.classList.remove(t)})):e.classList.remove(t),e.classList.length||e.removeAttribute("class");else{var n=" "+(e.getAttribute("class")||"")+" ",r=" "+t+" ";while(n.indexOf(r)>=0)n=n.replace(r," ");n=n.trim(),n?e.setAttribute("class",n):e.removeAttribute("class")}}var le=h((function(e){return{enterClass:e+"-enter",enterToClass:e+"-enter-to",enterActiveClass:e+"-enter-active",leaveClass:e+"-leave",leaveToClass:e+"-leave-to",leaveActiveClass:e+"-leave-active"}}));function de(e){if(e){if("object"===typeof e){var t={};return!1!==e.css&&o(t,le(e.name||"v")),o(t,e),t}return"string"===typeof e?le(e):void 0}}var ve="undefined"!==typeof window,he="transition",ye="animation",me="transition",be="transitionend",_e="animation",ge="animationend";ve&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(me="WebkitTransition",be="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(_e="WebkitAnimation",ge="webkitAnimationEnd"));var Ce=ve?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(e){return e()};function Oe(e){Ce((function(){Ce(e)}))}var xe=/\b(transform|all)(,|$)/;function we(e,t){var n,r=window.getComputedStyle(e),a=(r[me+"Delay"]||"").split(", "),o=(r[me+"Duration"]||"").split(", "),i=je(a,o),s=(r[_e+"Delay"]||"").split(", "),c=(r[_e+"Duration"]||"").split(", "),u=je(s,c),f=0,p=0;t===he?i>0&&(n=he,f=i,p=o.length):t===ye?u>0&&(n=ye,f=u,p=c.length):(f=Math.max(i,u),n=f>0?i>u?he:ye:null,p=n?n===he?o.length:c.length:0);var l=n===he&&xe.test(r[me+"Property"]);return{type:n,timeout:f,propCount:p,hasTransform:l}}function je(e,t){while(e.length=i&&f()},f=function(){e.removeEventListener(s,u),n()};setTimeout((function(){c1,P=e._enterCb=_((function(){S&&(ke(e,O),ke(e,C)),P.cancelled?(S&&ke(e,g),A&&A(e)):j&&j(e),e._enterCb=null}));w&&w(e,P),x&&x(e),S&&(Ee(e,g),Ee(e,C),Oe((function(){ke(e,g),P.cancelled||(Ee(e,O),$||(Te(E)?setTimeout(P,E):Se(e,r,P)))}))),S||$||P(),t()}}function P(e,t){if(e._enterCb&&(e._enterCb.cancelled=!0,e._enterCb()),!e._leaveCb){var n=N(w),a=N(E),o=N(x),i=N(j),s=+(u(k)?k.leave:k),c=n&&n.length>1,f=e._leaveCb=_((function(){S&&(ke(e,C),ke(e,O)),f.cancelled?(S&&ke(e,g),A&&A(e)):(t(),i&&i(e)),e._leaveCb=null}));a?a(p):p()}function p(){f.cancelled||(o&&o(e),S&&(Ee(e,g),Ee(e,O),Oe((function(){ke(e,g),f.cancelled||(Ee(e,C),c||(Te(s)?setTimeout(f,s):Se(e,r,f)))}))),n&&n(e,f),S||c||f())}}}function $e(e){return e.split(/(?=<)/g).map((function(e){if(/^<\//.test(e)||e.indexOf(">")<0)return e;var t=/\s*(on[^\s"'<>\/=]+)\s*=/gi,n=e.indexOf(">"),r=e.slice(n+1),a=e.slice(0,n+1).replace(t,(function(e,t){return e.replace(t,t+"-safe")}));return a+r})).join("")}function Pe(e){if(e.indexOf("<")>-1){var t=/(()|())/gi,n={"<":"<",">":">",'"':"""};return e=e.replace(t,(function(e){return e.replace(/([<>"])/g,(function(e){return n[e]}))})),$e(e)}return e}function Re(e){return"[object Object]"===Object.prototype.toString.call(e)}function De(e){return null==e?"":Array.isArray(e)||Re(e)&&e.toString===Object.prototype.toString?JSON.stringify(e,null,2):String(e)}function Le(e){return!0===e||e&&"string"===typeof e?"disabled":e}var Ke="__COMPONENT_REFERENCE__",Me=function(){},Ue=function(e){return this.filters[e]},ze={$activate:se,$deactivate:ce,_l:k,_ex:o,_ocp:T,_noop:Me,_t:Ne,_sf:Pe,_f:Ue,_h:De,$emit:t.Component.prototype.fire,$on:t.Component.prototype.on,$watch:t.Component.prototype.watch,$nextTick:t.nextTick,$set:re,_da:Le},Fe=t.defineComponent(ze),qe={$el:function(){return this.el},$data:function(){return this.data&&this.data.raw},$context:function(){return this.owner},$parent:function(){return this.parentComponent},$children:function(){return this._rootNode&&this.tagName!==this._rootNode.tagName&&this.children.unshift(this._rootNode),this.children.filter((function(e){return 5===e.nodeType}))},$root:function(){var e=this;if(this.parentComponent)while(e.parentComponent)e=e.parentComponent;return e},$slots:oe,_isDestroyed:function(){return!!this.lifeCycle.disposed}},Je=t.Component.prototype._update;t.Component.prototype._update=function(e){e&&this._toPhase("beforeUpdate"),Je.call(this,e)};var Ge="_SanCtor",Ie=O("$style");function We(e){if(e&&e[Ke])return e;if(e instanceof t.Component||e instanceof Fe){var n=e.prototype;if(!n.hasOwnProperty("_cmptReady")){var r=e.components||n.components||{};n.components=Be(r),n._cmptReady=1}return e}return"function"===typeof e?t.createComponentLoader((function(){return new Promise((function(t){e((function(e){t(Ve(e))}))}))})):e.template||e.aNode||e.aPack?(e.components&&(e.components=Be(e.components),e._cmptReady=1),t.defineComponent(e)):Ve(e)}function Be(e){return e=Object.keys(e).reduce((function(t,n){var r=e[n];return t[n]=t[m(n)]=We(r),t}),o({},G.components))}function Ve(e){if(e.hasOwnProperty(Ge))return e[Ge];if("function"===typeof e)return We(e);var n={};if(e.components&&(n.components=Be(e.components),n._cmptReady=1),e.template||e.aNode||e.aPack||e instanceof t.Component||e instanceof Fe)return t.defineComponent(o({},e,n));var r=e.__sanOptimizeSSR||!1,a=o(n,{template:e.__santemplate,aNode:e.__sanaNode,aPack:e.__sanaPack,_isSan:!0},W(e)),i=e.__sanRefs,s=a.inited;a.inited=function(){var t=this,n=this;if(!r&&(this.$refs=Object.create(null),i)){for(var a=function(e,t){var r=i[e];v(n.$refs,r.name,{get:function(){return r.root?n.el:n.ref(r.name)}})},o=0,c=i.length;o0&&!Array.isArray(e.props))for(var c=0,f=i.length;c { - // it('should work', done => { - // const vm = new Vue({ - // data: { - // test: 'b', - // }, - // template: - // '', - // }).$mount(); - // document.body.appendChild(vm.$el); - // expect(vm.test).toBe('b'); - // expect(vm.$el.value).toBe('b'); - // expect(vm.$el.childNodes[1].selected).toBe(true); - // vm.test = 'c'; - // waitForUpdate(function () { - // expect(vm.$el.value).toBe('c'); - // expect(vm.$el.childNodes[2].selected).toBe(true); - // updateSelect(vm.$el, 'a'); - // triggerEvent(vm.$el, 'change'); - // expect(vm.test).toBe('a'); - // }).then(done); - // }); + it('should work', done => { + const vm = new Vue({ + data: { + test: 'b', + }, + template: + '', + }).$mount(); + document.body.appendChild(vm.$el); + expect(vm.test).toBe('b'); + expect(vm.$el.value).toBe('b'); + expect(vm.$el.childNodes[1].selected).toBe(true); + vm.test = 'c'; + waitForUpdate(function () { + expect(vm.$el.value).toBe('c'); + expect(vm.$el.childNodes[2].selected).toBe(true); + updateSelect(vm.$el, 'a'); + triggerEvent(vm.$el, 'change'); + expect(vm.test).toBe('a'); + }).then(done); + }); - // // ATTENTION 对于数字和字符串的场景,san目前不支持,因此先解决暂时注释掉了下面的一个断言 - // it('should work with value bindings', done => { - // const vm = new Vue({ - // data: { - // test: 2, - // }, - // template: - // '', - // }).$mount(); - // document.body.appendChild(vm.$el); - // expect(vm.$el.value).toBe('2'); - // expect(vm.$el.childNodes[1].selected).toBe(true); - // vm.test = 3; - // waitForUpdate(function () { - // expect(vm.$el.value).toBe('3'); - // expect(vm.$el.childNodes[2].selected).toBe(true); + // ATTENTION 对于数字和字符串的场景,san目前不支持,因此先解决暂时注释掉了下面的一个断言 + it('should work with value bindings', done => { + const vm = new Vue({ + data: { + test: 2, + }, + template: + '', + }).$mount(); + document.body.appendChild(vm.$el); + expect(vm.$el.value).toBe('2'); + expect(vm.$el.childNodes[1].selected).toBe(true); + vm.test = 3; + waitForUpdate(function () { + expect(vm.$el.value).toBe('3'); + expect(vm.$el.childNodes[2].selected).toBe(true); - // updateSelect(vm.$el, '1'); - // triggerEvent(vm.$el, 'change'); - // expect(vm.test).toBe('1'); + updateSelect(vm.$el, '1'); + triggerEvent(vm.$el, 'change'); + expect(vm.test).toBe('1'); - // updateSelect(vm.$el, '2'); - // triggerEvent(vm.$el, 'change'); - // // expect(vm.test).toBe(2); - // }).then(done); - // }); + updateSelect(vm.$el, '2'); + triggerEvent(vm.$el, 'change'); + // expect(vm.test).toBe(2); + }).then(done); + }); // TODO select 不支持对象 // it('should work with value bindings (object loose equal)', done => { @@ -153,95 +153,95 @@ describe('Directive a-model select', () => { // }).then(done); // }); - // it('should work with a-for', done => { - // const vm = new Vue({ - // data: { - // test: 'b', - // opts: ['a', 'b', 'c'], - // }, - // template: - // '', - // }).$mount(); - // document.body.appendChild(vm.$el); - // expect(vm.test).toBe('b'); - // expect(vm.$el.value).toBe('b'); - // expect(vm.$el.childNodes[1].selected).toBe(true); - // vm.test = 'c'; - // waitForUpdate(function () { - // expect(vm.$el.value).toBe('c'); - // expect(vm.$el.childNodes[2].selected).toBe(true); - // updateSelect(vm.$el, 'a'); - // triggerEvent(vm.$el, 'change'); - // expect(vm.test).toBe('a'); - // // update a-for opts - // vm.opts = ['d', 'a']; - // }).then(() => { - // expect(vm.$el.childNodes[0].selected).toBe(false); - // expect(vm.$el.childNodes[1].selected).toBe(true); - // }).then(done); - // }); + it('should work with a-for', done => { + const vm = new Vue({ + data: { + test: 'b', + opts: ['a', 'b', 'c'], + }, + template: + '', + }).$mount(); + document.body.appendChild(vm.$el); + expect(vm.test).toBe('b'); + expect(vm.$el.value).toBe('b'); + expect(vm.$el.childNodes[1].selected).toBe(true); + vm.test = 'c'; + waitForUpdate(function () { + expect(vm.$el.value).toBe('c'); + expect(vm.$el.childNodes[2].selected).toBe(true); + updateSelect(vm.$el, 'a'); + triggerEvent(vm.$el, 'change'); + expect(vm.test).toBe('a'); + // update a-for opts + vm.opts = ['d', 'a']; + }).then(() => { + expect(vm.$el.childNodes[0].selected).toBe(false); + expect(vm.$el.childNodes[1].selected).toBe(true); + }).then(done); + }); - // // ATTENTION 对于数字和字符串的场景,san目前不支持,因此先解决暂时注释掉了下面的一个断言 - // it('should work with a-for & value bindings', done => { - // const vm = new Vue({ - // data: { - // test: 2, - // opts: [1, 2, 3], - // }, - // template: - // '', - // }).$mount(); - // document.body.appendChild(vm.$el); - // expect(vm.$el.value).toBe('2'); - // expect(vm.$el.childNodes[1].selected).toBe(true); - // vm.test = 3; - // waitForUpdate(function () { - // expect(vm.$el.value).toBe('3'); - // expect(vm.$el.childNodes[2].selected).toBe(true); - // updateSelect(vm.$el, 1); - // triggerEvent(vm.$el, 'change'); - // // expect(vm.test).toBe(1); - // // // update a-for opts - // // vm.opts = [0, 1]; + // ATTENTION 对于数字和字符串的场景,san目前不支持,因此先解决暂时注释掉了下面的一个断言 + it('should work with a-for & value bindings', done => { + const vm = new Vue({ + data: { + test: 2, + opts: [1, 2, 3], + }, + template: + '', + }).$mount(); + document.body.appendChild(vm.$el); + expect(vm.$el.value).toBe('2'); + expect(vm.$el.childNodes[1].selected).toBe(true); + vm.test = 3; + waitForUpdate(function () { + expect(vm.$el.value).toBe('3'); + expect(vm.$el.childNodes[2].selected).toBe(true); + updateSelect(vm.$el, 1); + triggerEvent(vm.$el, 'change'); + // expect(vm.test).toBe(1); + // // update a-for opts + // vm.opts = [0, 1]; - // expect(vm.test).toBe('1'); - // // update a-for opts - // vm.opts = [0, '1']; - // }).then(() => { - // expect(vm.$el.childNodes[0].selected).toBe(false); - // expect(vm.$el.childNodes[1].selected).toBe(true); - // }).then(done); - // }); + expect(vm.test).toBe('1'); + // update a-for opts + vm.opts = [0, '1']; + }).then(() => { + expect(vm.$el.childNodes[0].selected).toBe(false); + expect(vm.$el.childNodes[1].selected).toBe(true); + }).then(done); + }); - // it('should work with select which has no default selected options', done => { - // const spy = jasmine.createSpy(); - // const vm = new Vue({ - // data: { - // id: 4, - // list: [1, 2, 3], - // testChange: 5, - // }, - // template: - // '
' - // + '' - // + '{{testChange}}' - // + '
', - // methods: { - // test: spy, - // }, - // }).$mount(); - // document.body.appendChild(vm.$el); - // vm.testChange = 10; - // waitForUpdate(() => { - // expect(spy.calls.count()).toBe(0); - // }).then(done); - // }); + it('should work with select which has no default selected options', done => { + const spy = jasmine.createSpy(); + const vm = new Vue({ + data: { + id: 4, + list: [1, 2, 3], + testChange: 5, + }, + template: + '
' + + '' + + '{{testChange}}' + + '
', + methods: { + test: spy, + }, + }).$mount(); + document.body.appendChild(vm.$el); + vm.testChange = 10; + waitForUpdate(() => { + expect(spy.calls.count()).toBe(0); + }).then(done); + }); if (!hasMultiSelectBug()) { @@ -334,6 +334,7 @@ describe('Directive a-model select', () => { // }).then(done); // }); + // san 不支持多选场景 // it('should not have multiple attr with falsy values except \'\'', () => { // const vm = new Vue({ // template: @@ -350,6 +351,7 @@ describe('Directive a-model select', () => { // expect(vm.$el.querySelector('#string').multiple).toEqual(true); // }); + // san 不支持多选场景 // it('multiple with static template', () => { // const vm = new Vue({ // template: @@ -365,50 +367,52 @@ describe('Directive a-model select', () => { // expect(opts[2].selected).toBe(true); // }); - // it('multiple selects', done => { - // const spy = jasmine.createSpy(); - // const vm = new Vue({ - // data: { - // selections: ['', ''], - // selectBoxes: [ - // [{ - // value: 'foo', - // text: 'foo', - // }, { - // value: 'bar', - // text: 'bar', - // }], - // [{ - // value: 'day', - // text: 'day', - // }, { - // value: 'night', - // text: 'night', - // }], - // ], - // }, - // watch: { - // selections: spy, - // }, - // template: - // '
' - // + '' - // + '{{selections}}' - // + '
', - // }).$mount(); - // document.body.appendChild(vm.$el); - // var selects = vm.$el.getElementsByTagName('select'); - // var select0 = selects[0]; - // select0.options[0].selected = true; - // triggerEvent(select0, 'change'); - // waitForUpdate(() => { - // expect(spy).toHaveBeenCalled(); - // expect(vm.selections).toEqual(['foo', '']); - // }).then(done); - // }); + it('multiple selects', done => { + const spy = jasmine.createSpy(); + const vm = new Vue({ + data: { + selections: ['', ''], + selectBoxes: [ + [{ + value: 'foo', + text: 'foo', + }, { + value: 'bar', + text: 'bar', + }], + [{ + value: 'day', + text: 'day', + }, { + value: 'night', + text: 'night', + }], + ], + }, + watch: { + selections: spy, + }, + template: + '
' + + '' + + '{{selections}}' + + '
', + }).$mount(); + document.body.appendChild(vm.$el); + var selects = vm.$el.getElementsByTagName('select'); + var select0 = selects[0]; + select0.options[0].selected = true; + triggerEvent(select0, 'change'); + waitForUpdate(() => { + expect(spy).toHaveBeenCalled(); + expect(vm.selections).toEqual(['foo', '']); + }).then(done); + }); + + // ATTENTION 不支持number // it('.number modifier', () => { // const vm = new Vue({ // data: { @@ -427,6 +431,7 @@ describe('Directive a-model select', () => { // expect(vm.test).toBe(1); // }); + // ATTENTION 不支持number // it('should respect different primitive type value', done => { // const vm = new Vue({ // data: { diff --git a/test/spec/runtime/directives/safe-html.spec.js b/test/spec/runtime/directives/safe-html.spec.js new file mode 100644 index 0000000..f5094d5 --- /dev/null +++ b/test/spec/runtime/directives/safe-html.spec.js @@ -0,0 +1,39 @@ +/* eslint-disable quotes */ +import Vue from '../../../helpers/vue'; + +describe('Directive a-html', () => { + + it('should render safe html', () => { + const vm = new Vue({ + template: '
', + data: { + a: '', + }, + }).$mount(); + + expect(vm.$el.innerHTML).toBe('<script>console.log(111);</script>'); + }); + + + it('should render safe html with on', () => { + const vm = new Vue({ + template: '
', + data: { + a: '
console.log(111);', + }, + }).$mount(); + + expect(vm.$el.innerHTML).toBe('
console.log(111);
'); + }); + + it('should render safe html with no', () => { + const vm = new Vue({ + template: '
', + data: { + a: 'hello world', + }, + }).$mount(); + + expect(vm.$el.innerHTML).toBe('hello world'); + }); +});