serialize.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. ///import core
  2. ///commands 定制过滤规则
  3. ///commandsName Serialize
  4. ///commandsTitle 定制过滤规则
  5. UE.plugins['serialize'] = function () {
  6. var ie = browser.ie,
  7. version = browser.version;
  8. function ptToPx(value){
  9. return /pt/.test(value) ? value.replace( /([\d.]+)pt/g, function( str ) {
  10. return Math.round(parseFloat(str) * 96 / 72) + "px";
  11. } ) : value;
  12. }
  13. var me = this, autoClearEmptyNode = me.options.autoClearEmptyNode,
  14. EMPTY_TAG = dtd.$empty,
  15. parseHTML = function () {
  16. //干掉<a> 后便变得空格,保留</a> 这样的空格
  17. var RE_PART = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
  18. RE_ATTR = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g,
  19. EMPTY_ATTR = {checked:1,compact:1,declare:1,defer:1,disabled:1,ismap:1,multiple:1,nohref:1,noresize:1,noshade:1,nowrap:1,readonly:1,selected:1},
  20. CDATA_TAG = {script:1,style: 1},
  21. NEED_PARENT_TAG = {
  22. "li": { "$": 'ul', "ul": 1, "ol": 1 },
  23. "dd": { "$": "dl", "dl": 1 },
  24. "dt": { "$": "dl", "dl": 1 },
  25. "option": { "$": "select", "select": 1 },
  26. "td": { "$": "tr", "tr": 1 },
  27. "th": { "$": "tr", "tr": 1 },
  28. "tr": { "$": "tbody", "tbody": 1, "thead": 1, "tfoot": 1, "table": 1 },
  29. "tbody": { "$": "table", 'table':1,"colgroup": 1 },
  30. "thead": { "$": "table", "table": 1 },
  31. "tfoot": { "$": "table", "table": 1 },
  32. "col": { "$": "colgroup","colgroup":1 }
  33. };
  34. var NEED_CHILD_TAG = {
  35. "table": "td", "tbody": "td", "thead": "td", "tfoot": "td", //"tr": "td",
  36. "colgroup": "col",
  37. "ul": "li", "ol": "li",
  38. "dl": "dd",
  39. "select": "option"
  40. };
  41. function parse( html, callbacks ) {
  42. var match,
  43. nextIndex = 0,
  44. tagName,
  45. cdata;
  46. RE_PART.exec( "" );
  47. while ( (match = RE_PART.exec( html )) ) {
  48. var tagIndex = match.index;
  49. if ( tagIndex > nextIndex ) {
  50. var text = html.slice( nextIndex, tagIndex );
  51. if ( cdata ) {
  52. cdata.push( text );
  53. } else {
  54. var isSpace=/^\s*$/.test(text);
  55. if(!isSpace){
  56. callbacks.onText( text );
  57. }
  58. }
  59. }
  60. nextIndex = RE_PART.lastIndex;
  61. if ( (tagName = match[1]) ) {
  62. tagName = tagName.toLowerCase();
  63. if ( cdata && tagName == cdata._tag_name ) {
  64. callbacks.onCDATA( cdata.join( '' ) );
  65. cdata = null;
  66. }
  67. if ( !cdata ) {
  68. callbacks.onTagClose( tagName );
  69. continue;
  70. }
  71. }
  72. if ( cdata ) {
  73. cdata.push( match[0] );
  74. continue;
  75. }
  76. if ( (tagName = match[3]) ) {
  77. if ( /="/.test( tagName ) ) {
  78. continue;
  79. }
  80. tagName = tagName.toLowerCase();
  81. var attrPart = match[4],
  82. attrMatch,
  83. attrMap = {},
  84. selfClosing = attrPart && attrPart.slice( -1 ) == '/';
  85. if ( attrPart ) {
  86. RE_ATTR.exec( "" );
  87. while ( (attrMatch = RE_ATTR.exec( attrPart )) ) {
  88. var attrName = attrMatch[1].toLowerCase(),
  89. attrValue = attrMatch[2] || attrMatch[3] || attrMatch[4] || '';
  90. if ( !attrValue && EMPTY_ATTR[attrName] ) {
  91. attrValue = attrName;
  92. }
  93. if ( attrName == 'style' ) {
  94. if ( ie && version <= 6 ) {
  95. attrValue = attrValue.replace( /(?!;)\s*([\w-]+):/g, function ( m, p1 ) {
  96. return p1.toLowerCase() + ':';
  97. } );
  98. }
  99. }
  100. //没有值的属性不添加
  101. if ( attrValue ) {
  102. attrMap[attrName] = attrValue.replace( /:\s*/g, ':' )
  103. }
  104. }
  105. }
  106. callbacks.onTagOpen( tagName, attrMap, selfClosing );
  107. if ( !cdata && CDATA_TAG[tagName] ) {
  108. cdata = [];
  109. cdata._tag_name = tagName;
  110. }
  111. continue;
  112. }
  113. if ( (tagName = match[2]) ) {
  114. callbacks.onComment( tagName );
  115. }
  116. }
  117. if ( html.length > nextIndex ) {
  118. callbacks.onText( html.slice( nextIndex, html.length ) );
  119. }
  120. }
  121. return function ( html, forceDtd ) {
  122. var fragment = {
  123. type: 'fragment',
  124. parent: null,
  125. children: []
  126. };
  127. var currentNode = fragment;
  128. function addChild( node ) {
  129. node.parent = currentNode;
  130. currentNode.children.push( node );
  131. }
  132. function addElement( element, open ) {
  133. var node = element;
  134. // 遇到结构化标签的时候
  135. if ( NEED_PARENT_TAG[node.tag] ) {
  136. // 考虑这种情况的时候, 结束之前的标签
  137. // e.g. <table><tr><td>12312`<tr>`4566
  138. while ( NEED_PARENT_TAG[currentNode.tag] && NEED_PARENT_TAG[currentNode.tag][node.tag] ) {
  139. currentNode = currentNode.parent;
  140. }
  141. // 如果前一个标签和这个标签是同一级, 结束之前的标签
  142. // e.g. <ul><li>123<li>
  143. if ( currentNode.tag == node.tag ) {
  144. currentNode = currentNode.parent;
  145. }
  146. // 向上补齐父标签
  147. while ( NEED_PARENT_TAG[node.tag] ) {
  148. if ( NEED_PARENT_TAG[node.tag][currentNode.tag] ) break;
  149. node = node.parent = {
  150. type: 'element',
  151. tag: NEED_PARENT_TAG[node.tag]['$'],
  152. attributes: {},
  153. children: [node]
  154. };
  155. }
  156. }
  157. if ( forceDtd ) {
  158. // 如果遇到这个标签不能放在前一个标签内部,则结束前一个标签,span单独处理
  159. while ( dtd[node.tag] && !(currentNode.tag == 'span' ? utils.extend( dtd['strong'], {'a':1,'A':1} ) : (dtd[currentNode.tag] || dtd['div']))[node.tag] ) {
  160. if ( tagEnd( currentNode ) ) continue;
  161. if ( !currentNode.parent ) break;
  162. currentNode = currentNode.parent;
  163. }
  164. }
  165. node.parent = currentNode;
  166. currentNode.children.push( node );
  167. if ( open ) {
  168. currentNode = element;
  169. }
  170. if ( element.attributes.style ) {
  171. element.attributes.style = element.attributes.style.toLowerCase();
  172. }
  173. return element;
  174. }
  175. // 结束一个标签的时候,需要判断一下它是否缺少子标签
  176. // e.g. <table></table>
  177. function tagEnd( node ) {
  178. var needTag;
  179. if ( !node.children.length && (needTag = NEED_CHILD_TAG[node.tag]) ) {
  180. addElement( {
  181. type: 'element',
  182. tag: needTag,
  183. attributes: {},
  184. children: []
  185. }, true );
  186. return true;
  187. }
  188. return false;
  189. }
  190. parse( html, {
  191. onText: function ( text ) {
  192. while ( !(dtd[currentNode.tag] || dtd['div'])['#'] ) {
  193. if ( tagEnd( currentNode ) ) continue;
  194. currentNode = currentNode.parent;
  195. }
  196. addChild( {
  197. type: 'text',
  198. data: text
  199. } );
  200. },
  201. onComment: function ( text ) {
  202. addChild( {
  203. type: 'comment',
  204. data: text
  205. } );
  206. },
  207. onCDATA: function ( text ) {
  208. while ( !(dtd[currentNode.tag] || dtd['div'])['#'] ) {
  209. if ( tagEnd( currentNode ) ) continue;
  210. currentNode = currentNode.parent;
  211. }
  212. addChild( {
  213. type: 'cdata',
  214. data: text
  215. } );
  216. },
  217. onTagOpen: function ( tag, attrs, closed ) {
  218. closed = closed || EMPTY_TAG[tag] ;
  219. addElement( {
  220. type: 'element',
  221. tag: tag,
  222. attributes: attrs,
  223. closed: closed,
  224. children: []
  225. }, !closed );
  226. },
  227. onTagClose: function ( tag ) {
  228. var node = currentNode;
  229. // 向上找匹配的标签, 这里不考虑dtd的情况是因为tagOpen的时候已经处理过了, 这里不会遇到
  230. while ( node && tag != node.tag ) {
  231. node = node.parent;
  232. }
  233. if ( node ) {
  234. // 关闭中间的标签
  235. for ( var tnode = currentNode; tnode !== node.parent; tnode = tnode.parent ) {
  236. tagEnd( tnode );
  237. }
  238. //去掉空白的inline节点
  239. //分页,锚点保留
  240. //|| dtd.$removeEmptyBlock[node.tag])
  241. // if ( !node.children.length && dtd.$removeEmpty[node.tag] && !node.attributes.anchorname && node.attributes['class'] != 'pagebreak' && node.tag != 'a') {
  242. //
  243. // node.parent.children.pop();
  244. // }
  245. currentNode = node.parent;
  246. } else {
  247. // 如果没有找到开始标签, 则创建新标签
  248. // eg. </div> => <div></div>
  249. //针对视屏网站embed会给结束符,这里特殊处理一下
  250. if ( !(dtd.$removeEmpty[tag] || dtd.$removeEmptyBlock[tag] || tag == 'embed') ) {
  251. node = {
  252. type: 'element',
  253. tag: tag,
  254. attributes: {},
  255. children: []
  256. };
  257. addElement( node, true );
  258. tagEnd( node );
  259. currentNode = node.parent;
  260. }
  261. }
  262. }
  263. } );
  264. // 处理这种情况, 只有开始标签没有结束标签的情况, 需要关闭开始标签
  265. // eg. <table>
  266. while ( currentNode !== fragment ) {
  267. tagEnd( currentNode );
  268. currentNode = currentNode.parent;
  269. }
  270. return fragment;
  271. };
  272. }();
  273. var unhtml1 = function () {
  274. var map = { '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
  275. function rep( m ) {
  276. return map[m];
  277. }
  278. return function ( str ) {
  279. str = str + '';
  280. return str ? str.replace( /[<>"']/g, rep ) : '';
  281. };
  282. }();
  283. var toHTML = function () {
  284. function printChildren( node, pasteplain ) {
  285. var children = node.children;
  286. var buff = [];
  287. for ( var i = 0,ci; ci = children[i]; i++ ) {
  288. buff.push( toHTML( ci, pasteplain ) );
  289. }
  290. return buff.join( '' );
  291. }
  292. function printAttrs( attrs ) {
  293. var buff = [];
  294. for ( var k in attrs ) {
  295. var value = attrs[k];
  296. if(k == 'style'){
  297. //pt==>px
  298. value = ptToPx(value);
  299. //color rgb ==> hex
  300. if(/rgba?\s*\([^)]*\)/.test(value)){
  301. value = value.replace( /rgba?\s*\(([^)]*)\)/g, function( str ) {
  302. return utils.fixColor('color',str);
  303. } )
  304. }
  305. //过滤掉所有的white-space,在纯文本编辑器里粘贴过来的内容,到chrome中会带有span和white-space属性,导致出现不能折行的情况
  306. //所以在这里去掉这个属性
  307. attrs[k] = utils.optCss(value.replace(/windowtext/g,'#000'))
  308. .replace(/white-space[^;]+;/g,'');
  309. if(!attrs[k]){
  310. continue;
  311. }
  312. }
  313. buff.push( k + '="' + unhtml1( attrs[k] ) + '"' );
  314. }
  315. return buff.join( ' ' )
  316. }
  317. function printData( node, notTrans ) {
  318. //trace:1399 输入html代码时空格转换成为&nbsp;
  319. //node.data.replace(/&nbsp;/g,' ') 针对pre中的空格和出现的&nbsp;把他们在得到的html代码中都转换成为空格,为了在源码模式下显示为空格而不是&nbsp;
  320. return notTrans ? node.data.replace(/&nbsp;/g,' ') : unhtml1( node.data ).replace(/ /g,'&nbsp;');
  321. }
  322. //纯文本模式下标签转换
  323. var transHtml = {
  324. 'li':'p',
  325. 'h1':'p','h2':'p','h3':'p','h4':'p','h5':'p','h6':'p',
  326. 'tr':'p',
  327. 'br':'br',
  328. 'div':'p',
  329. 'p':'p'//trace:1398 碰到p标签自己要加上p,否则transHtml[tag]是undefined
  330. };
  331. var clearTagName ={
  332. 'table':1,
  333. 'tbody':1,
  334. 'ol':1,
  335. 'ul':1,
  336. 'dt':1
  337. }
  338. function printElement( node, pasteplain ) {
  339. if ( node.type == 'element' && !node.children.length && (dtd.$removeEmpty[node.tag]) && node.tag != 'a' && utils.isEmptyObject(node.attributes) && autoClearEmptyNode) {// 锚点保留
  340. return html;
  341. }
  342. var tag = node.tag;
  343. if ( pasteplain && tag == 'td' ) {
  344. if ( !html ) html = '';
  345. html += printChildren( node, pasteplain ) + '&nbsp;&nbsp;&nbsp;';
  346. } else {
  347. var attrs = printAttrs( node.attributes );
  348. var html = pasteplain && clearTagName[tag] ? '' :
  349. '<' + (pasteplain && transHtml[tag] !==undefined? transHtml[tag] : tag) + (attrs ? ' ' + attrs : '') + (EMPTY_TAG[tag] ? ' />' : '>');
  350. if ( !EMPTY_TAG[tag] ) {
  351. //trace:1627 ,2070
  352. //p标签为空,将不占位这里占位符不起作用,用&nbsp;或者br
  353. if( tag == 'p' && !node.children.length){
  354. html += browser.ie ? '&nbsp;' : '<br/>';
  355. }
  356. html += printChildren( node, pasteplain );
  357. html +=(pasteplain && clearTagName[tag] ? '' : '</' + (pasteplain && transHtml[tag]!==undefined? transHtml[tag] : tag) + '>');
  358. }
  359. }
  360. return html;
  361. }
  362. return function ( node, pasteplain ) {
  363. if ( node.type == 'fragment' ) {
  364. return printChildren( node, pasteplain );
  365. } else if ( node.type == 'element' ) {
  366. return printElement( node, pasteplain );
  367. } else if ( node.type == 'text' || node.type == 'cdata' ) {
  368. return printData( node, dtd.$notTransContent[node.parent.tag] );
  369. } else if ( node.type == 'comment' ) {
  370. return '<!--' + node.data + '-->';
  371. }
  372. return '';
  373. };
  374. }();
  375. var NODE_NAME_MAP = {
  376. 'text': '#text',
  377. 'comment': '#comment',
  378. 'cdata': '#cdata-section',
  379. 'fragment': '#document-fragment'
  380. };
  381. //写入编辑器时,调用,进行转换操作
  382. function transNode( node, word_img_flag ) {
  383. var sizeMap = [0, 10, 12, 16, 18, 24, 32, 48],
  384. attr,
  385. indexOf = utils.indexOf;
  386. switch ( node.tag ) {
  387. case 'script':
  388. node.tag = 'div';
  389. node.attributes._ue_org_tagName = 'script';
  390. node.attributes._ue_div_script = 1;
  391. node.attributes._ue_script_data = node.children[0] ? encodeURIComponent(node.children[0].data) : '';
  392. node.attributes._ue_custom_node_ = 1;
  393. node.children = [];
  394. break;
  395. case 'style':
  396. node.tag = 'div';
  397. node.attributes._ue_div_style = 1;
  398. node.attributes._ue_org_tagName = 'style';
  399. node.attributes._ue_style_data = node.children[0] ? encodeURIComponent(node.children[0].data) : '';
  400. node.attributes._ue_custom_node_ = 1;
  401. node.children = [];
  402. break;
  403. case 'img':
  404. //todo base64暂时去掉,后边做远程图片上传后,干掉这个
  405. if(node.attributes.src && /^data:/.test(node.attributes.src)){
  406. return {
  407. type : 'fragment',
  408. children:[]
  409. }
  410. }
  411. if ( node.attributes.src && /^(?:file)/.test( node.attributes.src ) ) {
  412. if ( !/(gif|bmp|png|jpg|jpeg)$/.test( node.attributes.src ) ) {
  413. return {
  414. type : 'fragment',
  415. children:[]
  416. }
  417. }
  418. node.attributes.word_img = node.attributes.src;
  419. node.attributes.src = me.options.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif';
  420. var flag = parseInt(node.attributes.width)<128||parseInt(node.attributes.height)<43;
  421. node.attributes.style="background:url(" + (flag? me.options.themePath+me.options.theme +"/images/word.gif":me.options.langPath+me.options.lang + "/images/localimage.png")+") no-repeat center center;border:1px solid #ddd";
  422. //node.attributes.style = 'width:395px;height:173px;';
  423. word_img_flag && (word_img_flag.flag = 1);
  424. }
  425. if(browser.ie && browser.version < 7 )
  426. node.attributes.orgSrc = node.attributes.src;
  427. node.attributes.data_ue_src = node.attributes.data_ue_src || node.attributes.src;
  428. break;
  429. case 'li':
  430. var child = node.children[0];
  431. if ( !child || child.type != 'element' || child.tag != 'p' && dtd.p[child.tag] ) {
  432. var tmpPNode = {
  433. type: 'element',
  434. tag: 'p',
  435. attributes: {},
  436. parent : node
  437. };
  438. tmpPNode.children = child ? node.children :[
  439. browser.ie ? {
  440. type:'text',
  441. data:domUtils.fillChar,
  442. parent : tmpPNode
  443. }:
  444. {
  445. type : 'element',
  446. tag : 'br',
  447. attributes:{},
  448. closed: true,
  449. children: [],
  450. parent : tmpPNode
  451. }
  452. ];
  453. node.children = [tmpPNode];
  454. }
  455. break;
  456. case 'table':
  457. case 'td':
  458. optStyle( node );
  459. break;
  460. case 'a'://锚点,a==>img
  461. if ( node.attributes['anchorname'] ) {
  462. node.tag = 'img';
  463. node.attributes = {
  464. 'class' : 'anchorclass',
  465. 'anchorname':node.attributes['name']
  466. };
  467. node.closed = 1;
  468. }
  469. node.attributes.href && (node.attributes.data_ue_src = node.attributes.href);
  470. break;
  471. case 'b':
  472. node.tag = node.name = 'strong';
  473. break;
  474. case 'i':
  475. node.tag = node.name = 'em';
  476. break;
  477. case 'u':
  478. node.tag = node.name = 'span';
  479. node.attributes.style = (node.attributes.style || '') + ';text-decoration:underline;';
  480. break;
  481. case 's':
  482. case 'del':
  483. node.tag = node.name = 'span';
  484. node.attributes.style = (node.attributes.style || '') + ';text-decoration:line-through;';
  485. if ( node.children.length == 1 ) {
  486. child = node.children[0];
  487. if ( child.tag == node.tag ) {
  488. node.attributes.style += ";" + child.attributes.style;
  489. node.children = child.children;
  490. }
  491. }
  492. break;
  493. case 'span':
  494. var style = node.attributes.style;
  495. if ( style ) {
  496. if ( !node.attributes.style || browser.webkit && style == "white-space:nowrap;") {
  497. delete node.attributes.style;
  498. }
  499. }
  500. //针对ff3.6span的样式不能正确继承的修复
  501. if(browser.gecko && browser.version <= 10902 && node.parent){
  502. var parent = node.parent;
  503. if(parent.tag == 'span' && parent.attributes && parent.attributes.style){
  504. node.attributes.style = parent.attributes.style + ';' + node.attributes.style;
  505. }
  506. }
  507. if ( utils.isEmptyObject( node.attributes ) && autoClearEmptyNode) {
  508. node.type = 'fragment'
  509. }
  510. break;
  511. case 'font':
  512. node.tag = node.name = 'span';
  513. attr = node.attributes;
  514. node.attributes = {
  515. 'style': (attr.size ? 'font-size:' + (sizeMap[attr.size] || 12) + 'px' : '')
  516. + ';' + (attr.color ? 'color:'+ attr.color : '')
  517. + ';' + (attr.face ? 'font-family:'+ attr.face : '')
  518. + ';' + (attr.style||'')
  519. };
  520. while(node.parent.tag == node.tag && node.parent.children.length == 1){
  521. node.attributes.style && (node.parent.attributes.style ? (node.parent.attributes.style += ";" + node.attributes.style) : (node.parent.attributes.style = node.attributes.style));
  522. node.parent.children = node.children;
  523. node = node.parent;
  524. }
  525. break;
  526. case 'p':
  527. if ( node.attributes.align ) {
  528. node.attributes.style = (node.attributes.style || '') + ';text-align:' +
  529. node.attributes.align + ';';
  530. delete node.attributes.align;
  531. }
  532. }
  533. return node;
  534. }
  535. function optStyle( node ) {
  536. if ( ie && node.attributes.style ) {
  537. var style = node.attributes.style;
  538. node.attributes.style = style.replace(/;\s*/g,';');
  539. node.attributes.style = node.attributes.style.replace( /^\s*|\s*$/, '' )
  540. }
  541. }
  542. //getContent调用转换
  543. function transOutNode( node ) {
  544. switch ( node.tag ) {
  545. case 'div' :
  546. if(node.attributes._ue_div_script){
  547. node.tag = 'script';
  548. node.children = [{type:'cdata',data:node.attributes._ue_script_data?decodeURIComponent(node.attributes._ue_script_data):'',parent:node}];
  549. delete node.attributes._ue_div_script;
  550. delete node.attributes._ue_script_data;
  551. delete node.attributes._ue_custom_node_;
  552. delete node.attributes._ue_org_tagname;
  553. }
  554. if(node.attributes._ue_div_style){
  555. node.tag = 'style';
  556. node.children = [{type:'cdata',data:node.attributes._ue_style_data?decodeURIComponent(node.attributes._ue_style_data):'',parent:node}];
  557. delete node.attributes._ue_div_style;
  558. delete node.attributes._ue_style_data;
  559. delete node.attributes._ue_custom_node_;
  560. delete node.attributes._ue_org_tagname;
  561. }
  562. break;
  563. case 'table':
  564. !node.attributes.style && delete node.attributes.style;
  565. if ( ie && node.attributes.style ) {
  566. optStyle( node );
  567. }
  568. break;
  569. case 'td':
  570. case 'th':
  571. if ( /display\s*:\s*none/i.test( node.attributes.style ) ) {
  572. return {
  573. type: 'fragment',
  574. children: []
  575. };
  576. }
  577. if ( ie && !node.children.length ) {
  578. var txtNode = {
  579. type: 'text',
  580. data:domUtils.fillChar,
  581. parent : node
  582. };
  583. node.children[0] = txtNode;
  584. }
  585. if ( ie && node.attributes.style ) {
  586. optStyle( node );
  587. }
  588. break;
  589. case 'img'://锚点,img==>a
  590. if ( node.attributes.anchorname ) {
  591. node.tag = 'a';
  592. node.attributes = {
  593. name : node.attributes.anchorname,
  594. anchorname : 1
  595. };
  596. node.closed = null;
  597. }else{
  598. if(node.attributes.data_ue_src){
  599. node.attributes.src = node.attributes.data_ue_src;
  600. delete node.attributes.data_ue_src;
  601. }
  602. }
  603. break;
  604. case 'a':
  605. if(node.attributes.data_ue_src){
  606. node.attributes.href = node.attributes.data_ue_src;
  607. delete node.attributes.data_ue_src;
  608. }
  609. }
  610. return node;
  611. }
  612. function childrenAccept( node, visit, ctx ) {
  613. if ( !node.children || !node.children.length ) {
  614. return node;
  615. }
  616. var children = node.children;
  617. for ( var i = 0; i < children.length; i++ ) {
  618. var newNode = visit( children[i], ctx );
  619. if ( newNode.type == 'fragment' ) {
  620. var args = [i, 1];
  621. args.push.apply( args, newNode.children );
  622. children.splice.apply( children, args );
  623. //节点为空的就干掉,不然后边的补全操作会添加多余的节点
  624. if ( !children.length ) {
  625. node = {
  626. type: 'fragment',
  627. children: []
  628. }
  629. }
  630. i --;
  631. } else {
  632. children[i] = newNode;
  633. }
  634. }
  635. return node;
  636. }
  637. function Serialize( rules ) {
  638. this.rules = rules;
  639. }
  640. Serialize.prototype = {
  641. // NOTE: selector目前只支持tagName
  642. rules: null,
  643. // NOTE: node必须是fragment
  644. filter: function ( node, rules, modify ) {
  645. rules = rules || this.rules;
  646. var whiteList = rules && rules.whiteList;
  647. var blackList = rules && rules.blackList;
  648. function visitNode( node, parent ) {
  649. node.name = node.type == 'element' ?
  650. node.tag : NODE_NAME_MAP[node.type];
  651. if ( parent == null ) {
  652. return childrenAccept( node, visitNode, node );
  653. }
  654. if ( blackList && (blackList[node.name]|| (node.attributes && node.attributes._ue_org_tagName && blackList[node.attributes._ue_org_tagName]))) {
  655. modify && (modify.flag = 1);
  656. return {
  657. type: 'fragment',
  658. children: []
  659. };
  660. }
  661. if ( whiteList ) {
  662. if ( node.type == 'element' ) {
  663. if ( parent.type == 'fragment' ? whiteList[node.name] : whiteList[node.name] && whiteList[parent.name][node.name] ) {
  664. var props;
  665. if ( (props = whiteList[node.name].$) ) {
  666. var oldAttrs = node.attributes;
  667. var newAttrs = {};
  668. for ( var k in props ) {
  669. if ( oldAttrs[k] ) {
  670. newAttrs[k] = oldAttrs[k];
  671. }
  672. }
  673. node.attributes = newAttrs;
  674. }
  675. } else {
  676. modify && (modify.flag = 1);
  677. node.type = 'fragment';
  678. // NOTE: 这里算是一个hack
  679. node.name = parent.name;
  680. }
  681. } else {
  682. // NOTE: 文本默认允许
  683. }
  684. }
  685. if ( blackList || whiteList ) {
  686. childrenAccept( node, visitNode, node );
  687. }
  688. return node;
  689. }
  690. return visitNode( node, null );
  691. },
  692. transformInput: function ( node, word_img_flag ) {
  693. function visitNode( node ) {
  694. node = transNode( node, word_img_flag );
  695. node = childrenAccept( node, visitNode, node );
  696. if ( me.options.pageBreakTag && node.type == 'text' && node.data.replace( /\s/g, '' ) == me.options.pageBreakTag ) {
  697. node.type = 'element';
  698. node.name = node.tag = 'hr';
  699. delete node.data;
  700. node.attributes = {
  701. 'class' : 'pagebreak',
  702. noshade:"noshade",
  703. size:"5",
  704. 'unselectable' : 'on',
  705. 'style' : 'moz-user-select:none;-khtml-user-select: none;'
  706. };
  707. node.children = [];
  708. }
  709. //去掉多余的空格和换行
  710. if(node.type == 'text' && !dtd.$notTransContent[node.parent.tag]){
  711. node.data = node.data.replace(/[\r\t\n]*/g,'')//.replace(/[ ]*$/g,'')
  712. }
  713. return node;
  714. }
  715. return visitNode( node );
  716. },
  717. transformOutput: function ( node ) {
  718. function visitNode( node ) {
  719. if ( node.tag == 'hr' && node.attributes['class'] == 'pagebreak' ) {
  720. delete node.tag;
  721. node.type = 'text';
  722. node.data = me.options.pageBreakTag;
  723. delete node.children;
  724. }
  725. node = transOutNode( node );
  726. node = childrenAccept( node, visitNode, node );
  727. return node;
  728. }
  729. return visitNode( node );
  730. },
  731. toHTML: toHTML,
  732. parseHTML: parseHTML,
  733. word: UE.filterWord
  734. };
  735. me.serialize = new Serialize( me.options.serialize || {});
  736. UE.serialize = new Serialize( {} );
  737. };