diff --git a/_src/core/htmlparser.js b/_src/core/htmlparser.js
new file mode 100644
index 0000000000000000000000000000000000000000..026c078b4742975ce84875a68e862945629c4051
--- /dev/null
+++ b/_src/core/htmlparser.js
@@ -0,0 +1,105 @@
+//html字符串转换成uNode节点
+//by zhanyi
+var htmlparser = UE.htmlparser = function(htmlstr){
+ var reg = new RegExp( domUtils.fillChar, 'g' );
+ //ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除
+ htmlstr = htmlstr.replace( reg, '' ).replace( />[\t\r\n]*?<' );
+
+ var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
+ re_attr = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g;
+
+ var uNode = UE.uNode,
+ needparentNode = {
+ 'td' : 'tr',
+ 'tr' : 'tbody',
+ 'tbody' : 'table',
+ 'th' : 'tr',
+ 'thead':'table',
+ 'tfoot':'table',
+ 'caption':'table',
+ 'li':['ul','ol'],
+ 'dt':'dl',
+ 'dd':'dl',
+ 'option':'select'
+ };
+
+ function text(parent,data){
+ parent.children.push(new uNode({
+ type : 'text',
+ data : data,
+ parentNode : parent
+ }));
+ }
+
+ function element(parent,tagName,htmlattr){
+ var needParentTag;
+ if(needParentTag = needparentNode[tagName]){
+ if(tagName == parent.tagName){
+ parent = parent.parentNode;
+ }else if(utils.isArray(needParentTag) ? utils.indexOf(needParentTag,parent.tagName) == -1 : needParentTag != parent.tagName){
+ parent = element(parent,utils.isArray(needParentTag) ? needParentTag[0] : needParentTag)
+ }
+ }
+ var elm = new uNode({
+ parentNode : parent,
+ type : 'element',
+ tagName : tagName,
+ //是自闭合的处理一下
+ children : dtd.$empty[tagName] ? null : []
+ });
+ //如果属性存在,处理属性
+ if(htmlattr){
+ var attrs = {},match;
+ while(match = re_attr.exec(htmlattr)){
+ attrs[match[1].toLowerCase()] = match[2]
+ }
+ elm.attrs = attrs;
+ }
+
+ parent.children.push(elm);
+ //如果是自闭合节点返回父亲节点
+ return dtd.$empty[tagName] ? parent : elm
+ }
+
+ function comment(parent,data){
+ parent.children.push(new uNode({
+ type : 'comment',
+ data : data,
+ parentNode : parent
+ }));
+ }
+
+ var match,currentIndex = 0,nextIndex = 0;
+ //设置根节点
+ var root = new uNode({
+ type : 'root',
+ children : []
+ });
+ var currentParent = root;
+ while(match = re_tag.exec(htmlstr)){
+ currentIndex = match.index;
+ if(currentIndex > nextIndex){
+ //text node
+ text(currentParent,htmlstr.slice(nextIndex,currentIndex));
+ }
+ if(match[3]){
+ //start tag
+ currentParent = element(currentParent,match[3],match[4]);
+
+ }else if(match[1]){
+ //end tag
+ currentParent = currentParent.parentNode;
+ }else if(match[2]){
+ //comment
+ comment(currentParent,match[2])
+ }
+ nextIndex = re_tag.lastIndex;
+
+ }
+ //如果结束是文本,就有可能丢掉,所以这里手动判断一下
+ //例如
sdfsdfsdfsdfsdfsdfsdf
+ if(nextIndex < htmlstr.length){
+ text(currentParent,htmlstr.slice(nextIndex));
+ }
+ return root;
+};
\ No newline at end of file
diff --git a/_src/core/node.js b/_src/core/node.js
new file mode 100644
index 0000000000000000000000000000000000000000..28bd0a4e325af91cdb0eaec5fb4d13404bce12a4
--- /dev/null
+++ b/_src/core/node.js
@@ -0,0 +1,356 @@
+///import editor.js
+///import core/utils.js
+///import core/dom/dom.js
+///import core/dom/dtd.js
+///import core/htmlparser.js
+//模拟的节点类
+//by zhanyi
+(function () {
+ var uNode = UE.uNode = function (obj) {
+ this.type = obj.type;
+ this.data = obj.data;
+ this.tagName = obj.tagName;
+ this.parentNode = obj.parentNode;
+ this.attrs = obj.attrs || {};
+ this.children = obj.children;
+ };
+ var indentChar = ' ',
+ breakChar = '\n',
+ needWrap = utils.extend(utils.extend({},dtd.$block),dtd.$cdata);
+
+ function insertLine(arr, current, begin) {
+ arr.push(breakChar);
+ return current + (begin ? 1 : -1);
+ }
+
+ function insertIndent(arr, current) {
+ //插入缩进
+ for (var i = 0; i < current; i++) {
+ arr.push(indentChar);
+ }
+ }
+
+
+ //创建uNode的静态方法
+ //支持标签和html
+ uNode.createElement = function (html) {
+ if (/[<>]/.test(html)) {
+ return UE.htmlparser(html).children[0]
+ } else {
+ return new uNode({
+ type:'element',
+ children:[],
+ tagName:html
+ })
+ }
+ };
+ uNode.createText = function (data) {
+ return new UE.uNode({
+ type:'text',
+ 'data':data || ''
+ })
+ };
+ function nodeToHtml(node, arr, formatter, current) {
+ switch (node.type) {
+ case 'root':
+ for (var i = 0, ci; ci = node.children[i++];) {
+ //插入新行
+ if (formatter && ci.type == 'element' && needWrap[ci.tagName] && i > 1) {
+ insertLine(arr, current, true);
+ insertIndent(arr, current)
+ }
+ nodeToHtml(ci, arr, formatter, current)
+ }
+ break;
+ case 'text':
+ isText(node, arr);
+ break;
+ case 'element':
+ isElement(node, arr, formatter, current);
+ break;
+ case 'comment':
+ isComment(node, arr, formatter);
+ }
+ return arr;
+ }
+
+ function isText(node, arr) {
+ arr.push(node.data)
+ }
+
+ function isElement(node, arr, formatter, current) {
+ var attrhtml = '';
+ if (node.attrs) {
+ attrhtml = [];
+ var attrs = node.attrs;
+ for (var a in attrs) {
+ attrhtml.push(a + (attrs[a] !== undefined ? '="' + attrs[a] + '"' : ''))
+ }
+ attrhtml = attrhtml.join(' ');
+ }
+ arr.push('<' + node.tagName +
+ (attrhtml ? ' ' + attrhtml + ' ' : '') +
+ (dtd.$empty[node.tagName] ? '\/' : '' ) + '>'
+ );
+ //插入新行
+ if (formatter && needWrap[node.tagName]) {
+ current = insertLine(arr, current, true);
+ insertIndent(arr, current)
+ }
+ if (node.children && node.children.length) {
+ for (var i = 0, ci; ci = node.children[i++];) {
+ if (formatter && ci.type == 'element' && needWrap[ci.tagName] && i>1) {
+ insertLine(arr, current);
+ insertIndent(arr, current)
+ }
+ nodeToHtml(ci, arr, formatter, current)
+ }
+ }
+ if (!dtd.$empty[node.tagName]) {
+ if (formatter && needWrap[node.tagName]) {
+ current = insertLine(arr, current);
+ insertIndent(arr, current)
+ }
+ arr.push('<\/' + node.tagName + '>');
+ }
+
+ }
+
+ function isComment(node, arr) {
+ arr.push('');
+ }
+
+ function getNodeById(root, id) {
+ var node;
+ if (root.type == 'element' && root.getAttr('id') == id) {
+ return root;
+ }
+ if (root.children && root.children.length) {
+ for (var i = 0, ci; ci = root.children[i++];) {
+ if (node = getNodeById(ci, id)) {
+ return node;
+ }
+ }
+ }
+ }
+
+ function getNodesByTagName(node, tagName, arr) {
+ if (node.type == 'element' && node.tagName == tagName) {
+ arr.push(node);
+ }
+ if (node.children && node.children.length) {
+ for (var i = 0, ci; ci = node.children[i++];) {
+ getNodesByTagName(ci, tagName, arr)
+ }
+ }
+ }
+
+ uNode.prototype = {
+ toHtml:function (formatter) {
+ var arr = [];
+ nodeToHtml(this, arr, formatter, 0);
+ return arr.join('')
+ },
+ innerHTML:function (htmlstr) {
+ if (this.type != 'element' || dtd.$empty[this.tagName]) {
+ return this;
+ }
+ if (htmlstr) {
+ for (var i = 0, ci; ci = this.children[i++];) {
+ ci.parentNode = null;
+ }
+ this.children = [];
+ var tmpRoot = UE.htmlparser(htmlstr);
+ for (var i = 0, ci; ci = tmpRoot.children[i++];) {
+ this.children.push(ci);
+ ci.parentNode = this;
+ }
+ return this;
+ } else {
+ var tmpRoot = new UE.uNode({
+ type:'root',
+ children:this.children
+ });
+ return tmpRoot.toHtml();
+ }
+ },
+ innerText:function () {
+ if (this.type != 'element' || dtd.$empty[this.tagName]) {
+ return this;
+ }
+ var html = this.toHtml();
+ return html.replace(/<[^>]+>/g, '');
+ },
+ getData:function () {
+ if (this.type == 'element')
+ return '';
+ return this.data
+ },
+ firstChild:function () {
+ if (this.type != 'element' || dtd.$empty[this.tagName]) {
+ return this;
+ }
+ return this.children ? this.children[0] : null;
+ },
+ lastChild:function () {
+ if (this.type != 'element' || dtd.$empty[this.tagName]) {
+ return this;
+ }
+ return this.children ? this.children[this.children.length - 1] : null;
+ },
+ replaceChild:function (target, source) {
+ if (this.children) {
+ for (var i = 0, ci; ci = this.children[i]; i++) {
+ if (ci === source) {
+ this.children.splice(i, 1, target);
+ source.parentNode = null;
+ target.parentNode = this;
+ return target;
+ }
+ }
+ }
+ },
+ appendChild:function (node) {
+ if (this.type == 'element' && !dtd.$empty[this.tagName]) {
+ if (!this.children) {
+ this.children = []
+ }
+ for (var i = 0, ci; ci = this.children[i]; i++) {
+ if (ci === node) {
+ this.children.splice(i, 1)
+ break;
+ }
+ }
+ this.children.push(node);
+ node.parentNode = this;
+ return node;
+ }
+
+ },
+ insertBefore:function (target, source) {
+ if (this.children) {
+ for (var i = 0, ci; ci = this.children[i]; i++) {
+ if (ci === target) {
+ this.children.splice(i, 1);
+ i--;
+ }
+ if (ci === source) {
+ this.children.splice(i, 0, target);
+ target.parentNode = this;
+ i++;
+ }
+ }
+ return target;
+ }
+ },
+ insertAfter:function (target, source) {
+ if (this.children) {
+ for (var i = 0, ci; ci = this.children[i]; i++) {
+ if (ci === target) {
+ this.children.splice(i, 1);
+ i--;
+ }
+ if (ci === source) {
+ this.children.splice(i + 1, 1, target);
+ target.parentNode = this;
+ i = i + 2;
+
+ }
+ return target;
+ }
+ }
+ },
+ removeChild:function (node) {
+ if (this.children) {
+ for (var i = 0, ci; ci = this.children[i]; i++) {
+ if (ci === node) {
+ this.children.splice(i, 1);
+ ci.parentNode = null;
+ return ci;
+ }
+ }
+ }
+ },
+ getAttr:function (attrName) {
+ return this.attrs[attrName.toLowerCase()]
+ },
+ setAttr:function (attrName, attrVal) {
+ if(!attrName){
+ delete this.attrs;
+ return;
+ }
+ if (utils.isObject(attrName)) {
+ for (var a in attrName) {
+ if (!attrName[a]) {
+ delete this.attrs[a]
+ } else {
+ this.attrs[a.toLowerCase()] = attrName[a];
+ }
+ }
+ } else {
+ if (!attrVal) {
+ delete this.attrs[attrName]
+ } else {
+ this.attrs[attrName.toLowerCase()] = attrVal;
+ }
+
+ }
+ },
+ getNodeById:function (id) {
+ var node;
+ if (this.children && this.children.length) {
+ for (var i = 0, ci; ci = this.children[i++];) {
+ if (node = getNodeById(ci, id)) {
+ return node;
+ }
+ }
+ }
+ },
+ getNodesByTagName:function (tagNames) {
+ tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, ' ').split(' ');
+ var arr = [], me = this;
+ utils.each(tagNames, function (tagName) {
+ if (me.children && me.children.length) {
+ for (var i = 0, ci; ci = me.children[i++];) {
+ getNodesByTagName(ci, tagName, arr)
+ }
+ }
+ });
+ return arr;
+ },
+ getStyle : function(name){
+ var cssStyle = this.getAttr('style');
+ if(!cssStyle){
+ return ''
+ }
+ var reg = new RegExp(name + ':([^;]+)');
+ var match = cssStyle.match(reg);
+ if(match[0]){
+ return match[1]
+ }
+ return '';
+ },
+ setStyle : function(name,val){
+ function exec(name,val){
+ var reg = new RegExp(name + ':([^;]+);?','gi');
+ cssStyle = cssStyle.replace(reg,'');
+ if(val){
+ cssStyle = name + ':' + val + ';' + cssStyle
+ }
+
+ }
+ var cssStyle = this.getAttr('style');
+ if(!cssStyle){
+ cssStyle = '';
+ }
+ if (utils.isObject(name)) {
+ for(var a in name){
+ exec(a,name[a])
+ }
+ } else {
+ exec(name,val)
+ }
+ this.setAttr('style',cssStyle)
+ }
+ }
+})();
diff --git a/_src/core/utils.js b/_src/core/utils.js
index b147205ff63f9eaa0448065aa3cf1dfebe6a3b2e..9ccf0cce0a82225ea63f4f3dbd52686dbd8d2eed 100644
--- a/_src/core/utils.js
+++ b/_src/core/utils.js
@@ -572,7 +572,7 @@ var utils = UE.utils = {
* @name isNumber
* @grammar UE.utils.isNumber(obj) => true|false
*/
-utils.each(['String','Function','Array','Number','RegExp'],function(v){
+utils.each(['String','Function','Array','Number','RegExp','Object'],function(v){
UE.utils['is' + v] = function(obj){
return Object.prototype.toString.apply(obj) == '[object ' + v + ']';
}