diff --git a/doc/anode-pack.md b/doc/anode-pack.md
index b907ff4e2..d44b7884c 100644
--- a/doc/anode-pack.md
+++ b/doc/anode-pack.md
@@ -1170,4 +1170,50 @@ aPack = [1,"u",1,45,6,1,3,"cmpt"]
"tagName": "u"
}
*/
-```
\ No newline at end of file
+```
+
+
+### var
+
+- head: 46
+- 编码序: `{string}name, {Node}expr`
+
+```js
+aPack = [1,"my-ui",1,46,"title",9,,2,3,"Hello ",7,,6,1,3,"name",]
+/*
+{
+ "directives": {},
+ "props": [],
+ "events": [],
+ "children": [],
+ "tagName": "my-ui",
+ "attrs": [
+ {
+ "name": "title",
+ "expr": {
+ "type": 7,
+ "segs": [
+ {
+ "type": 1,
+ "value": "Hello "
+ },
+ {
+ "type": 5,
+ "expr": {
+ "type": 4,
+ "paths": [
+ {
+ "type": 1,
+ "value": "name"
+ }
+ ]
+ },
+ "filters": []
+ }
+ ]
+ }
+ }
+ ]
+}
+*/
+```
diff --git a/package-lock.json b/package-lock.json
index dd721df6c..ff72a456d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "san",
- "version": "3.13.1",
+ "version": "3.13.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "san",
- "version": "3.13.1",
+ "version": "3.13.3",
"license": "MIT",
"devDependencies": {
"@wdio/cli": "^6.6.6",
@@ -29,8 +29,8 @@
"karma-sourcemap-loader": "^0.3.7",
"mustache": "^3.0.1",
"opener": "^1.5.1",
- "san-anode-cases": "^3.10.1",
- "san-html-cases": "^3.13.4",
+ "san-anode-cases": "^3.14.0",
+ "san-html-cases": "^3.14.0",
"source-map": "^0.7.3",
"swig-templates": "^2.0.3",
"typescript": "^4.3.5",
@@ -9774,15 +9774,15 @@
"dev": true
},
"node_modules/san-anode-cases": {
- "version": "3.10.1",
- "resolved": "https://registry.npmjs.org/san-anode-cases/-/san-anode-cases-3.10.1.tgz",
- "integrity": "sha512-N3quamwUS2iZqxFOQWukElYBbrcB6y9dHn2TnBmrJ8aj1oDyltxqflXZtpT3B5Mdtqj9v4bwHMxnXvHj0MaTjA==",
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/san-anode-cases/-/san-anode-cases-3.14.0.tgz",
+ "integrity": "sha512-pwkbuTqtM7YzGF+67rMmTVrw1S2tYTr0D1fV9BkWABkTk0XkFx6kp8tBzxls3npyxOH0XWUeJ+9pmnWOeuLRNg==",
"dev": true
},
"node_modules/san-html-cases": {
- "version": "3.13.4",
- "resolved": "https://registry.npmjs.org/san-html-cases/-/san-html-cases-3.13.4.tgz",
- "integrity": "sha512-ZYoRuaylnHu9zlajqp1cHvttfy/lHfr/cdfiG9IwcB3EOqTArCsrlB+8mYEVTuu17J+SpPFftHVO+WlGo/hiew==",
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/san-html-cases/-/san-html-cases-3.14.0.tgz",
+ "integrity": "sha512-+fV/ATLw5+891kh7vSmgfwUfaoc4Gpg6KqTImDMB8bS3D9a4Zt0yRGeLN6AmL5jbqaGVBa+8bkeWut1oRmvahw==",
"dev": true
},
"node_modules/saucelabs": {
@@ -19617,15 +19617,15 @@
"dev": true
},
"san-anode-cases": {
- "version": "3.10.1",
- "resolved": "https://registry.npmjs.org/san-anode-cases/-/san-anode-cases-3.10.1.tgz",
- "integrity": "sha512-N3quamwUS2iZqxFOQWukElYBbrcB6y9dHn2TnBmrJ8aj1oDyltxqflXZtpT3B5Mdtqj9v4bwHMxnXvHj0MaTjA==",
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/san-anode-cases/-/san-anode-cases-3.14.0.tgz",
+ "integrity": "sha512-pwkbuTqtM7YzGF+67rMmTVrw1S2tYTr0D1fV9BkWABkTk0XkFx6kp8tBzxls3npyxOH0XWUeJ+9pmnWOeuLRNg==",
"dev": true
},
"san-html-cases": {
- "version": "3.13.4",
- "resolved": "https://registry.npmjs.org/san-html-cases/-/san-html-cases-3.13.4.tgz",
- "integrity": "sha512-ZYoRuaylnHu9zlajqp1cHvttfy/lHfr/cdfiG9IwcB3EOqTArCsrlB+8mYEVTuu17J+SpPFftHVO+WlGo/hiew==",
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/san-html-cases/-/san-html-cases-3.14.0.tgz",
+ "integrity": "sha512-+fV/ATLw5+891kh7vSmgfwUfaoc4Gpg6KqTImDMB8bS3D9a4Zt0yRGeLN6AmL5jbqaGVBa+8bkeWut1oRmvahw==",
"dev": true
},
"saucelabs": {
diff --git a/package.json b/package.json
index 9c5b1f9ee..65f3e4172 100644
--- a/package.json
+++ b/package.json
@@ -54,8 +54,8 @@
"karma-sourcemap-loader": "^0.3.7",
"mustache": "^3.0.1",
"opener": "^1.5.1",
- "san-anode-cases": "^3.10.1",
- "san-html-cases": "^3.13.4",
+ "san-anode-cases": "^3.14.0",
+ "san-html-cases": "^3.14.0",
"source-map": "^0.7.3",
"swig-templates": "^2.0.3",
"typescript": "^4.3.5",
diff --git a/src/browser/input-event-compatible.js b/src/browser/input-event-compatible.js
deleted file mode 100644
index 067d1ddd9..000000000
--- a/src/browser/input-event-compatible.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Copyright (c) Baidu Inc. All rights reserved.
- *
- * This source code is licensed under the MIT license.
- * See LICENSE file in the project root for license information.
- *
- * @file 解决 IE9 在表单元素中删除字符时不触发事件的问题
- */
-
-var ie = require('./ie');
-var on = require('./on');
-var trigger = require('./trigger');
-
-// #[begin] allua
-/* istanbul ignore if */
-if (ie === 9) {
- on(document, 'selectionchange', function () {
- var el = document.activeElement;
- if (el.tagName === 'TEXTAREA' || el.tagName === 'INPUT') {
- trigger(el, 'input');
- }
- });
-}
-// #[end]
diff --git a/src/browser/trigger.js b/src/browser/trigger.js
index 87f240261..c755cf6ea 100644
--- a/src/browser/trigger.js
+++ b/src/browser/trigger.js
@@ -15,7 +15,7 @@
* @param {string} eventName 事件名
*/
function trigger(el, eventName) {
- var event = document.createEvent('HTMLEvents');
+ var event = el.ownerDocument.createEvent('HTMLEvents');
event.initEvent(eventName, true, true);
el.dispatchEvent(event);
}
diff --git a/src/main.js b/src/main.js
index 8dc18f366..587318110 100644
--- a/src/main.js
+++ b/src/main.js
@@ -22,7 +22,6 @@
// require('./util/next-tick');
// require('./browser/ie');
// require('./browser/ie-old-than-9');
- // require('./browser/input-event-compatible');
// require('./browser/auto-close-tags');
// require('./util/data-types.js');
// require('./util/create-data-types-checker.js');
diff --git a/src/parser/integrate-attr.js b/src/parser/integrate-attr.js
index 9b147674b..afd43fb88 100644
--- a/src/parser/integrate-attr.js
+++ b/src/parser/integrate-attr.js
@@ -80,13 +80,28 @@ function integrateAttr(aNode, name, value, options) {
aNode.vars = [];
}
- realName = kebab2camel(realName);
aNode.vars.push({
- name: realName,
+ name: kebab2camel(realName),
expr: parseExpr(value.replace(/(^\{\{|\}\}$)/g, ''))
});
break;
+ case 'attr':
+ if (!aNode.attrs) {
+ aNode.attrs = [];
+ }
+
+ aNode.attrs.push({
+ name: realName,
+ expr: value
+ ? parseText(value, options.delimiters)
+ : boolAttrs[realName]
+ ? {type: ExprType.BOOL, value: true}
+ : {type: ExprType.STRING, value: ''}
+ });
+
+ break;
+
default:
if (prefix === 'prop') {
name = realName;
@@ -167,7 +182,6 @@ function integrateAttr(aNode, name, value, options) {
}
}
}
-
}
aNode.props.push(
diff --git a/src/parser/unpack-anode.js b/src/parser/unpack-anode.js
index 463477656..fb1bad447 100644
--- a/src/parser/unpack-anode.js
+++ b/src/parser/unpack-anode.js
@@ -211,6 +211,7 @@ function unpackANode(packed) {
break;
case 36:
+ case 46:
node = {
name: packed[++i]
};
@@ -293,6 +294,11 @@ function unpackANode(packed) {
current.vars.push(node);
break;
+ case 46:
+ current.attrs = current.attrs || [];
+ current.attrs.push(node);
+ break;
+
case 37:
current.directives['for'] = node;
break;
@@ -390,12 +396,14 @@ function unpackANode(packed) {
// Expr: UNARY
// Prop
// var
+ // attr
// Object Spread Item, Array Item
case 11:
case 2:
case 33:
case 34:
case 36:
+ case 46:
case 15:
case 17:
case 18:
diff --git a/src/view/async-component.js b/src/view/async-component.js
index 55bdf6590..46868b243 100644
--- a/src/view/async-component.js
+++ b/src/view/async-component.js
@@ -10,7 +10,6 @@
var guid = require('../util/guid');
var each = require('../util/each');
var insertBefore = require('../browser/insert-before');
-var nodeOwnCreateStump = require('./node-own-create-stump');
var nodeOwnSimpleDispose = require('./node-own-simple-dispose');
@@ -35,7 +34,7 @@ function AsyncComponent(options, loader) {
this.children[0] = new PlaceholderComponent(options);
}
- this._create();
+ this.el = hydrateWalker.doc.createComment(this.id);
insertBefore(this.el, hydrateWalker.target, hydrateWalker.current);
var me = this;
@@ -47,7 +46,6 @@ function AsyncComponent(options, loader) {
// #[end]
}
-AsyncComponent.prototype._create = nodeOwnCreateStump;
AsyncComponent.prototype.dispose = nodeOwnSimpleDispose;
/**
@@ -64,7 +62,7 @@ AsyncComponent.prototype.attach = function (parentEl, beforeEl) {
component.attach(parentEl, beforeEl);
}
- this._create();
+ this.el = parentEl.ownerDocument.createComment(this.id);
insertBefore(this.el, parentEl, beforeEl);
var me = this;
diff --git a/src/view/component.js b/src/view/component.js
index 8f802bd40..791869934 100644
--- a/src/view/component.js
+++ b/src/view/component.js
@@ -84,6 +84,7 @@ function Component(options) { // eslint-disable-line
var clazz = this.constructor;
+ this.inheritAttrs = !(this.inheritAttrs === false || clazz.inheritAttrs === false);
this.filters = this.filters || clazz.filters || {};
this.computed = this.computed || clazz.computed || {};
this.messages = this.messages || clazz.messages || {};
@@ -227,6 +228,7 @@ function Component(options) { // eslint-disable-line
this.tagName = this.tagName || this.source.tagName;
this.binds = this.source._b;
+ this.attrs = this.source.attrs;
// init s-bind data
this._srcSbindData = nodeSBindInit(this.source.directives.bind, this.scope, this.owner);
@@ -259,6 +261,19 @@ function Component(options) { // eslint-disable-line
initData[bindInfo.name] = value;
}
}
+
+ if (this.attrs) {
+ initData.$attrs = {};
+ for (var i = 0, l = this.attrs.length; i < l; i++) {
+ var attr = this.attrs[i];
+
+ var value = evalExpr(attr.expr, this.scope, this.owner);
+ if (typeof value !== 'undefined') {
+ // See: https://github.com/ecomfe/san/issues/191
+ initData.$attrs[attr.name] = value;
+ }
+ }
+ }
}
this.data = new Data(initData);
@@ -307,6 +322,9 @@ function Component(options) { // eslint-disable-line
}
else {
if (aNode.Clazz || this.components[aNode.tagName]) {
+ if (!aNode.Clazz && this.attrs && this.inheritAttrs) {
+ aNode = aNodeMergeSourceAttrs(aNode, this.source);
+ }
this._rootNode = createHydrateNode(aNode, this, this.data, this, hydrateWalker);
this._rootNode._getElAsRootNode && (this.el = this._rootNode._getElAsRootNode());
}
@@ -327,6 +345,9 @@ function Component(options) { // eslint-disable-line
}
else if (this.el) {
if (aNode.Clazz || this.components[aNode.tagName]) {
+ if (!aNode.Clazz && this.attrs && this.inheritAttrs) {
+ aNode = aNodeMergeSourceAttrs(aNode, this.source);
+ }
hydrateWalker = new DOMChildrenWalker(this.el.parentNode, this.el);
this._rootNode = createHydrateNode(aNode, this, this.data, this, hydrateWalker);
this._rootNode._getElAsRootNode && (this.el = this._rootNode._getElAsRootNode());
@@ -749,6 +770,15 @@ Component.prototype._update = function (changes) {
}
}
});
+debugger
+ each(me.attrs, function (bindItem) {
+ if (changeExprCompare(changeExpr, bindItem.expr, me.scope)) {
+ me.data.set(
+ bindItem._data,
+ evalExpr(bindItem.expr, me.scope, me.owner)
+ );
+ }
+ });
each(me.sourceSlotNameProps, function (bindItem) {
needReloadForSlot = needReloadForSlot || changeExprCompare(changeExpr, bindItem.expr, me.scope);
@@ -833,6 +863,25 @@ Component.prototype._update = function (changes) {
}
}
+ if (this.attrs && this.inheritAttrs) {
+ var attrsData = this.data.get('$attrs');
+
+ for (var i = 0; i < this.attrs.length; i++) {
+ var attr = this.attrs[i];
+
+ if (this.aNode._pi[attr.name] == null) {
+ for (var j = 0; j < dataChanges.length; j++) {
+ var changePaths = dataChanges[j].expr.paths;
+
+ if (changePaths[0].value === '$attrs' && changePaths[1].value === attr.name) {
+ getPropHandler(this.tagName, attr.name)(this.el, attrsData[attr.name], attr.name, this);
+ break;
+ }
+ }
+ }
+ }
+ }
+
for (var i = 0; i < this.children.length; i++) {
this.children[i]._update(dataChanges);
}
@@ -910,7 +959,12 @@ Component.prototype._repaintChildren = function () {
this._rootNode.dispose(0, 1);
this.slotChildren = [];
- this._rootNode = createNode(this.aNode, this, this.data, this);
+ var aNode = this.aNode;
+ if (!aNode.Clazz && this.attrs && this.inheritAttrs) {
+ aNode = aNodeMergeSourceAttrs(aNode, this.source);
+ }
+
+ this._rootNode = createNode(aNode, this, this.data, this);
this._rootNode.attach(parentEl, beforeEl);
this._rootNode._getElAsRootNode && (this.el = this._rootNode._getElAsRootNode());
}
@@ -997,6 +1051,52 @@ Component.prototype._getElAsRootNode = function () {
return this.el;
};
+function aNodeMergeSourceAttrs(aNode, source) {
+ var startIndex = 0;
+
+ var mergedANode = {
+ directives: aNode.directives,
+ props: aNode.props,
+ events: aNode.events,
+ children: aNode.children,
+ tagName: aNode.tagName,
+ attrs: [],
+ vars: aNode.vars,
+ _ht: aNode._ht,
+ _i: aNode._i,
+ _dp: aNode._dp,
+ _xp: aNode._xp,
+ _pi: aNode._pi,
+ _b: aNode._b,
+ _ce: aNode._ce
+ };
+
+ var aNodeAttrIndex = {};
+ if (aNode.attrs) {
+ startIndex = aNode.attrs.length;
+ for (var i = 0; i < startIndex; i++) {
+ var attr = aNode.attrs[i];
+ aNodeAttrIndex[attr.name] = i;
+ mergedANode.attrs[i] = attr;
+ }
+ }
+
+ for (var i = 0; i < source.attrs.length; i++) {
+ var attr = source.attrs[i];
+
+ if (aNodeAttrIndex[attr.name] == null) {
+ mergedANode.attrs[startIndex] = {
+ name: attr.name,
+ expr: attr._data,
+ _data: attr._data
+ };
+ startIndex++;
+ }
+ }
+
+ return mergedANode;
+}
+
/**
* 将组件attach到页面
*
@@ -1015,6 +1115,13 @@ Component.prototype.attach = function (parentEl, beforeEl) {
// #[begin] devtool
this._toPhase('beforeCreate');
// #[end]
+
+ // aNode.Clazz 在 preheat 阶段为 if/else/for/fragment 等特殊标签或指令预热生成
+ // 这里不能用 this.components[aNode.tagName] 判断,因为可能特殊指令和组件在同一个节点上并存
+ if (!aNode.Clazz && this.attrs && this.inheritAttrs) {
+ aNode = aNodeMergeSourceAttrs(aNode, this.source);
+ }
+
this._rootNode = this._rootNode || createNode(aNode, this, this.data, this);
this._rootNode.attach(parentEl, beforeEl);
this._rootNode._getElAsRootNode && (this.el = this._rootNode._getElAsRootNode());
@@ -1027,16 +1134,16 @@ Component.prototype.attach = function (parentEl, beforeEl) {
// #[end]
var props;
-
+ var doc = parentEl.ownerDocument;
if (aNode._ce && aNode._i > 2) {
props = aNode._dp;
- this.el = (aNode._el || preheatEl(aNode)).cloneNode(false);
+ this.el = (aNode._el || preheatEl(aNode, doc)).cloneNode(false);
}
else {
props = aNode.props;
- this.el = svgTags[this.tagName] && document.createElementNS
- ? document.createElementNS('http://www.w3.org/2000/svg', this.tagName)
- : document.createElement(this.tagName);
+ this.el = svgTags[this.tagName] && doc.createElementNS
+ ? doc.createElementNS('http://www.w3.org/2000/svg', this.tagName)
+ : doc.createElement(this.tagName);
}
if (this._sbindData) {
@@ -1061,6 +1168,16 @@ Component.prototype.attach = function (parentEl, beforeEl) {
}
}
+ if (this.attrs && this.inheritAttrs) {
+ var attrsData = this.data.get('$attrs');
+ for (var i = 0; i < this.attrs.length; i++) {
+ var attr = this.attrs[i];
+ if (this.aNode._pi[attr.name] == null) {
+ getPropHandler(this.tagName, attr.name)(this.el, attrsData[attr.name], attr.name, this);
+ }
+ }
+ }
+
this._toPhase('created');
}
diff --git a/src/view/dom-children-walker.js b/src/view/dom-children-walker.js
index f827c07ac..813fa9568 100644
--- a/src/view/dom-children-walker.js
+++ b/src/view/dom-children-walker.js
@@ -21,6 +21,7 @@ var removeEl = require('../browser/remove-el');
function DOMChildrenWalker(el, onlyCurrent) {
this.index = 0;
this.target = el;
+ this.doc = el.ownerDocument;
if (onlyCurrent) {
this.children = [onlyCurrent, onlyCurrent.nextSibling];
diff --git a/src/view/element-own-attached.js b/src/view/element-own-attached.js
index ee59ae63a..b0b9ed99f 100644
--- a/src/view/element-own-attached.js
+++ b/src/view/element-own-attached.js
@@ -11,6 +11,8 @@
var empty = require('../util/empty');
var isBrowser = require('../browser/is-browser');
var trigger = require('../browser/trigger');
+var ie = require('../browser/ie');
+var on = require('../browser/on');
var NodeType = require('./node-type');
var elementGetTransition = require('./element-get-transition');
var getEventListener = require('./get-event-listener');
@@ -133,6 +135,17 @@ function xPropOutput(element, bindInfo, data) {
on(element.el, name, listener, capture);
}
+// #[begin] allua
+function ie9InputEventCompatible(doc) {
+ on(doc, 'selectionchange', function () {
+ var el = doc.activeElement;
+ if (el.tagName === 'TEXTAREA' || el.tagName === 'INPUT') {
+ trigger(el, 'input');
+ }
+ });
+}
+// #[end]
+
/**
* 完成元素 attached 后的行为
*
@@ -158,6 +171,16 @@ function elementOwnAttached() {
switch (this.tagName) {
case 'input':
case 'textarea':
+ // #[begin] allua
+ if (ie === 9) {
+ var doc = this.el.ownerDocument;
+ if (!doc.__sanInputEventCompatible) {
+ doc.__sanInputEventCompatible = true;
+ ie9InputEventCompatible(doc);
+ }
+ }
+ // #[end]
+
if (isBrowser) {
elementOnEl(this, 'change', inputOnCompositionEnd);
elementOnEl(this, 'compositionstart', inputOnCompositionStart);
diff --git a/src/view/element.js b/src/view/element.js
index 7b4103500..32d43cb91 100644
--- a/src/view/element.js
+++ b/src/view/element.js
@@ -116,19 +116,20 @@ Element.prototype.nodeType = NodeType.ELEM;
Element.prototype.attach = function (parentEl, beforeEl) {
if (!this.lifeCycle.attached) {
var aNode = this.aNode;
+ var doc = parentEl.ownerDocument;
if (!this.el) {
var props;
if (aNode._ce && aNode._i > 2) {
props = aNode._dp;
- this.el = (aNode._el || preheatEl(aNode)).cloneNode(false);
+ this.el = (aNode._el || preheatEl(aNode, doc)).cloneNode(false);
}
else {
props = aNode.props;
- this.el = svgTags[this.tagName] && document.createElementNS
- ? document.createElementNS('http://www.w3.org/2000/svg', this.tagName)
- : document.createElement(this.tagName);
+ this.el = svgTags[this.tagName] && doc.createElementNS
+ ? doc.createElementNS('http://www.w3.org/2000/svg', this.tagName)
+ : doc.createElement(this.tagName);
}
if (this._sbindData) {
diff --git a/src/view/for-node.js b/src/view/for-node.js
index c8fff83cf..20dbb24bd 100644
--- a/src/view/for-node.js
+++ b/src/view/for-node.js
@@ -22,7 +22,6 @@ var NodeType = require('./node-type');
var createNode = require('./create-node');
var createHydrateNode = require('./create-hydrate-node');
var nodeOwnSimpleDispose = require('./node-own-simple-dispose');
-var nodeOwnCreateStump = require('./node-own-create-stump');
/**
@@ -200,7 +199,7 @@ function ForNode(aNode, parent, scope, owner, hydrateWalker) {
}
}
- this._create();
+ this.el = hydrateWalker.doc.createComment(this.id);
insertBefore(this.el, hydrateWalker.target, hydrateWalker.current);
}
// #[end]
@@ -208,7 +207,6 @@ function ForNode(aNode, parent, scope, owner, hydrateWalker) {
ForNode.prototype.nodeType = NodeType.FOR;
-ForNode.prototype._create = nodeOwnCreateStump;
ForNode.prototype.dispose = nodeOwnSimpleDispose;
/**
@@ -218,7 +216,7 @@ ForNode.prototype.dispose = nodeOwnSimpleDispose;
* @param {HTMLElement=} beforeEl 要添加到哪个元素之前
*/
ForNode.prototype.attach = function (parentEl, beforeEl) {
- this._create();
+ this.el = parentEl.ownerDocument.createComment(this.id);
insertBefore(this.el, parentEl, beforeEl);
this.listData = evalExpr(this.param.value, this.scope, this.owner);
@@ -359,7 +357,7 @@ ForNode.prototype._disposeChildren = function (children, callback) {
}
// #[end]
- this.el = document.createComment(this.id);
+ this.el = parentEl.ownerDocument.createComment(this.id);
parentEl.appendChild(this.el);
callback && callback();
}
diff --git a/src/view/fragment-node.js b/src/view/fragment-node.js
index b7d2ecb4c..b7fa7581c 100644
--- a/src/view/fragment-node.js
+++ b/src/view/fragment-node.js
@@ -50,7 +50,7 @@ function FragmentNode(aNode, parent, scope, owner, hydrateWalker) {
hydrateWalker.goNext();
}
else {
- this.sel = document.createComment(this.id);
+ this.sel = hydrateWalker.doc.createComment(this.id);
insertBefore(this.sel, hydrateWalker.target, hydrateWalker.current);
}
@@ -68,7 +68,7 @@ function FragmentNode(aNode, parent, scope, owner, hydrateWalker) {
hydrateWalker.goNext();
}
else {
- this.el = document.createComment(this.id);
+ this.el = hydrateWalker.doc.createComment(this.id);
insertBefore(this.el, hydrateWalker.target, hydrateWalker.current);
}
diff --git a/src/view/if-node.js b/src/view/if-node.js
index 49cf2ca7b..a9c352df1 100644
--- a/src/view/if-node.js
+++ b/src/view/if-node.js
@@ -13,7 +13,6 @@ var evalExpr = require('../runtime/eval-expr');
var NodeType = require('./node-type');
var createNode = require('./create-node');
var createHydrateNode = require('./create-hydrate-node');
-var nodeOwnCreateStump = require('./node-own-create-stump');
var nodeOwnSimpleDispose = require('./node-own-simple-dispose');
/**
@@ -72,7 +71,7 @@ function IfNode(aNode, parent, scope, owner, hydrateWalker) {
}
}
- this._create();
+ this.el = hydrateWalker.doc.createComment(this.id);
insertBefore(this.el, hydrateWalker.target, hydrateWalker.current);
}
// #[end]
@@ -80,7 +79,6 @@ function IfNode(aNode, parent, scope, owner, hydrateWalker) {
IfNode.prototype.nodeType = NodeType.IF;
-IfNode.prototype._create = nodeOwnCreateStump;
IfNode.prototype.dispose = nodeOwnSimpleDispose;
/**
@@ -118,7 +116,7 @@ IfNode.prototype.attach = function (parentEl, beforeEl) {
}
- this._create();
+ this.el = parentEl.ownerDocument.createComment(this.id);
insertBefore(this.el, parentEl, beforeEl);
};
diff --git a/src/view/node-own-create-stump.js b/src/view/node-own-create-stump.js
deleted file mode 100644
index 5fca1cc01..000000000
--- a/src/view/node-own-create-stump.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) Baidu Inc. All rights reserved.
- *
- * This source code is licensed under the MIT license.
- * See LICENSE file in the project root for license information.
- *
- * @file 创建节点对应的 stump comment 元素
- */
-
-
-
-/**
- * 创建节点对应的 stump comment 主元素
- */
-function nodeOwnCreateStump() {
- this.el = this.el || document.createComment(this.id);
-}
-
-exports = module.exports = nodeOwnCreateStump;
diff --git a/src/view/node-own-only-children-attach.js b/src/view/node-own-only-children-attach.js
index 71f3ca8df..f4401c6cd 100644
--- a/src/view/node-own-only-children-attach.js
+++ b/src/view/node-own-only-children-attach.js
@@ -20,7 +20,8 @@ var createNode = require('./create-node');
* @param {HTMLElement=} beforeEl 要添加到哪个元素之前
*/
function nodeOwnOnlyChildrenAttach(parentEl, beforeEl) {
- this.sel = document.createComment(this.id);
+ var doc = parentEl.ownerDocument;
+ this.sel = doc.createComment(this.id);
insertBefore(this.sel, parentEl, beforeEl);
for (var i = 0; i < this.aNode.children.length; i++) {
@@ -34,7 +35,7 @@ function nodeOwnOnlyChildrenAttach(parentEl, beforeEl) {
child.attach(parentEl, beforeEl);
}
- this.el = document.createComment(this.id);
+ this.el = doc.createComment(this.id);
insertBefore(this.el, parentEl, beforeEl);
this.lifeCycle = LifeCycle.attached;
diff --git a/src/view/parse-component-template.js b/src/view/parse-component-template.js
index b78c3dc0d..b1c2825d8 100644
--- a/src/view/parse-component-template.js
+++ b/src/view/parse-component-template.js
@@ -50,7 +50,8 @@ function parseComponentTemplate(ComponentClass) {
delete aNode.tagName;
}
- if (proto.autoFillStyleAndId !== false && ComponentClass.autoFillStyleAndId !== false) {
+ if (proto.autoFillStyleAndId !== false && ComponentClass.autoFillStyleAndId !== false
+ && proto.inheritAttrs !== false && ComponentClass.inheritAttrs !== false) {
fillStyleAndId(aNode.props);
if (aNode.elses) {
diff --git a/src/view/preheat-a-node.js b/src/view/preheat-a-node.js
index c40f6df9b..7c8033db6 100644
--- a/src/view/preheat-a-node.js
+++ b/src/view/preheat-a-node.js
@@ -67,6 +67,8 @@ function preheatANode(aNode, componentInstance) {
aNode._xp = []; // hotspot: x props
aNode._pi = {}; // hotspot: props index
aNode._b = []; // hotspot: binds
+ aNode._ab = []; // hotspot: attr binds
+ aNode._ap = []; // hotspot: attr props
aNode._ce = !aNode.directives.is // cache element
&& aNode.tagName && aNode.tagName.indexOf('-') < 0
&& !/^(template|select|input|option|button|video|audio|canvas|img|embed|object|iframe)$/i.test(aNode.tagName);
@@ -77,6 +79,17 @@ function preheatANode(aNode, componentInstance) {
recordHotspotData(varItem.expr);
});
+ each(aNode.attrs, function (attr, i) {
+ attr._data = {
+ type: ExprType.ACCESSOR,
+ paths: [
+ {type: ExprType.STRING, value: '$attrs'},
+ {type: ExprType.STRING, value: attr.name}
+ ]
+ };
+ recordHotspotData(attr.expr);
+ });
+
var props = aNode.props;
var propsLen = props.length;
diff --git a/src/view/preheat-el.js b/src/view/preheat-el.js
index 0ffff2d99..350d60037 100644
--- a/src/view/preheat-el.js
+++ b/src/view/preheat-el.js
@@ -8,6 +8,7 @@
*/
var svgTags = require('../browser/svg-tags');
+const nextTick = require('../util/next-tick');
/**
* ANode预热HTML元素,用于循环创建时clone
@@ -15,10 +16,10 @@ var svgTags = require('../browser/svg-tags');
* @param {Object} aNode 要预热的ANode
* @return {HTMLElement}
*/
-function preheatEl(aNode) {
- var el = svgTags[aNode.tagName] && document.createElementNS
- ? document.createElementNS('http://www.w3.org/2000/svg', aNode.tagName)
- : document.createElement(aNode.tagName);
+function preheatEl(aNode, doc) {
+ var el = svgTags[aNode.tagName] && doc.createElementNS
+ ? doc.createElementNS('http://www.w3.org/2000/svg', aNode.tagName)
+ : doc.createElement(aNode.tagName);
aNode._el = el;
for (var i = 0, l = aNode.props.length; i < l; i++) {
@@ -28,6 +29,11 @@ function preheatEl(aNode) {
}
}
+ nextTick(function () {
+ aNode._el = null;
+ aNode._i = 0;
+ });
+
return el;
}
diff --git a/src/view/slot-node.js b/src/view/slot-node.js
index 7eb299f45..a1ef3bc9c 100644
--- a/src/view/slot-node.js
+++ b/src/view/slot-node.js
@@ -116,7 +116,7 @@ function SlotNode(aNode, parent, scope, owner, hydrateWalker) {
hydrateWalker.goNext();
}
else {
- this.sel = document.createComment(this.id);
+ this.sel = hydrateWalker.doc.createComment(this.id);
hydrateWalker.current
? hydrateWalker.target.insertBefore(this.sel, hydrateWalker.current)
: hydrateWalker.target.appendChild(this.sel);
@@ -139,7 +139,7 @@ function SlotNode(aNode, parent, scope, owner, hydrateWalker) {
hydrateWalker.goNext();
}
else {
- this.el = document.createComment(this.id);
+ this.el = hydrateWalker.doc.createComment(this.id);
hydrateWalker.current
? hydrateWalker.target.insertBefore(this.el, hydrateWalker.current)
: hydrateWalker.target.appendChild(this.el);
diff --git a/src/view/template-component.js b/src/view/template-component.js
index 5541416aa..15800c368 100644
--- a/src/view/template-component.js
+++ b/src/view/template-component.js
@@ -246,16 +246,17 @@ TemplateComponent.prototype.attach = function (parentEl, beforeEl) {
// #[end]
var props;
+ var doc = parentEl.ownerDocument;
if (aNode._ce && aNode._i > 2) {
props = aNode._dp;
- this.el = (aNode._el || preheatEl(aNode)).cloneNode(false);
+ this.el = (aNode._el || preheatEl(aNode, doc)).cloneNode(false);
}
else {
props = aNode.props;
- this.el = svgTags[this.tagName] && document.createElementNS
- ? document.createElementNS('http://www.w3.org/2000/svg', this.tagName)
- : document.createElement(this.tagName);
+ this.el = svgTags[this.tagName] && doc.createElementNS
+ ? doc.createElementNS('http://www.w3.org/2000/svg', this.tagName)
+ : doc.createElement(this.tagName);
}
if (this._sbindData) {
diff --git a/src/view/text-node.js b/src/view/text-node.js
index 2f385723b..8e7453f3f 100644
--- a/src/view/text-node.js
+++ b/src/view/text-node.js
@@ -8,7 +8,7 @@
*/
var guid = require('../util/guid');
-var isBrowser = require('../browser/is-browser');
+var ie = require('../browser/ie');
var removeEl = require('../browser/remove-el');
var insertBefore = require('../browser/insert-before');
var changeExprCompare = require('../runtime/change-expr-compare');
@@ -76,7 +76,7 @@ function TextNode(aNode, parent, scope, owner, hydrateWalker) {
}
}
else {
- this.el = document.createTextNode('');
+ this.el = hydrateWalker.doc.createTextNode('');
insertBefore(this.el, hydrateWalker.target, hydrateWalker.current);
}
}
@@ -97,21 +97,22 @@ TextNode.prototype.attach = function (parentEl, beforeEl) {
this.content = '';
}
+ var doc = parentEl.ownerDocument;
if (this.aNode.textExpr.original) {
this.id = this.id || guid++;
- this.sel = document.createComment(this.id);
+ this.sel = doc.createComment(this.id);
insertBefore(this.sel, parentEl, beforeEl);
- this.el = document.createComment(this.id);
+ this.el = doc.createComment(this.id);
insertBefore(this.el, parentEl, beforeEl);
- var tempFlag = document.createElement('script');
+ var tempFlag = doc.createElement('script');
parentEl.insertBefore(tempFlag, this.el);
tempFlag.insertAdjacentHTML('beforebegin', this.content);
parentEl.removeChild(tempFlag);
}
else {
- this.el = document.createTextNode(this.content);
+ this.el = doc.createTextNode(this.content);
insertBefore(this.el, parentEl, beforeEl);
}
};
@@ -131,10 +132,12 @@ TextNode.prototype.dispose = function (noDetach) {
this.sel = null;
};
-var textUpdateProp = isBrowser
- && (typeof document.createTextNode('').textContent === 'string'
- ? 'textContent'
- : 'data');
+
+// #[begin] allua
+var textUpdateProp = ie && ie < 9 ? 'data' : 'textContent';
+// #[end]
+
+
/**
* 更新 text 节点的视图
@@ -171,13 +174,18 @@ TextNode.prototype._update = function (changes) {
warnSetHTML(parentEl);
// #[end]
- var tempFlag = document.createElement('script');
+ var tempFlag = parentEl.ownerDocument.createElement('script');
parentEl.insertBefore(tempFlag, this.el);
tempFlag.insertAdjacentHTML('beforebegin', text);
parentEl.removeChild(tempFlag);
}
else {
+ // #[begin] allua
this.el[textUpdateProp] = text;
+ // #[end]
+ // #[begin] modern
+ this.el.textContent = text;
+ // #[end]
}
}
diff --git a/src/view/warn-set-html.js b/src/view/warn-set-html.js
index 8c1d8d231..09e3c99ec 100644
--- a/src/view/warn-set-html.js
+++ b/src/view/warn-set-html.js
@@ -18,13 +18,12 @@ var warn = require('../util/warn');
function warnSetHTML(el) {
// dont warn if not in browser runtime
/* istanbul ignore if */
- if (!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document)) {
+ if (!(typeof window !== 'undefined' && typeof navigator !== 'undefined')) {
return;
}
// some html elements cannot set innerHTML in old ie
// see: https://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
-
if (/^(col|colgroup|frameset|style|table|tbody|tfoot|thead|tr|select)$/i.test(el.tagName)) {
warn('set html for element "' + el.tagName + '" may cause an error in old IE');
}
diff --git a/test/component-attr-inherit.spec.js b/test/component-attr-inherit.spec.js
new file mode 100644
index 000000000..f2899ed4e
--- /dev/null
+++ b/test/component-attr-inherit.spec.js
@@ -0,0 +1,389 @@
+describe("Component Attribute Inherit", function () {
+
+ it("1 level", function (done) {
+ var Inner = san.defineComponent({
+ template: '