autotypeset.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /**
  2. * 自动排版
  3. * @file
  4. * @since 1.2.6.1
  5. */
  6. /**
  7. * 对当前编辑器的内容执行自动排版, 排版的行为根据config配置文件里的“autotypeset”选项进行控制。
  8. * @command autotypeset
  9. * @method execCommand
  10. * @param { String } cmd 命令字符串
  11. * @example
  12. * ```javascript
  13. * editor.execCommand( 'autotypeset' );
  14. * ```
  15. */
  16. UE.plugins["autotypeset"] = function() {
  17. this.setOpt({
  18. autotypeset: {
  19. mergeEmptyline: true, //合并空行
  20. removeClass: true, //去掉冗余的class
  21. removeEmptyline: false, //去掉空行
  22. textAlign: "left", //段落的排版方式,可以是 left,right,center,justify 去掉这个属性表示不执行排版
  23. imageBlockLine: "center", //图片的浮动方式,独占一行剧中,左右浮动,默认: center,left,right,none 去掉这个属性表示不执行排版
  24. pasteFilter: false, //根据规则过滤没事粘贴进来的内容
  25. clearFontSize: false, //去掉所有的内嵌字号,使用编辑器默认的字号
  26. clearFontFamily: false, //去掉所有的内嵌字体,使用编辑器默认的字体
  27. removeEmptyNode: false, // 去掉空节点
  28. //可以去掉的标签
  29. removeTagNames: utils.extend({ div: 1 }, dtd.$removeEmpty),
  30. indent: false, // 行首缩进
  31. indentValue: "2em", //行首缩进的大小
  32. bdc2sb: false,
  33. tobdc: false
  34. }
  35. });
  36. var me = this,
  37. opt = me.options.autotypeset,
  38. remainClass = {
  39. selectTdClass: 1,
  40. pagebreak: 1,
  41. anchorclass: 1
  42. },
  43. remainTag = {
  44. li: 1
  45. },
  46. tags = {
  47. div: 1,
  48. p: 1,
  49. //trace:2183 这些也认为是行
  50. blockquote: 1,
  51. center: 1,
  52. h1: 1,
  53. h2: 1,
  54. h3: 1,
  55. h4: 1,
  56. h5: 1,
  57. h6: 1,
  58. span: 1
  59. },
  60. highlightCont;
  61. //升级了版本,但配置项目里没有autotypeset
  62. if (!opt) {
  63. return;
  64. }
  65. readLocalOpts();
  66. function isLine(node, notEmpty) {
  67. if (!node || node.nodeType == 3) return 0;
  68. if (domUtils.isBr(node)) return 1;
  69. if (node && node.parentNode && tags[node.tagName.toLowerCase()]) {
  70. if (
  71. (highlightCont && highlightCont.contains(node)) ||
  72. node.getAttribute("pagebreak")
  73. ) {
  74. return 0;
  75. }
  76. return notEmpty
  77. ? !domUtils.isEmptyBlock(node)
  78. : domUtils.isEmptyBlock(
  79. node,
  80. new RegExp("[\\s" + domUtils.fillChar + "]", "g")
  81. );
  82. }
  83. }
  84. function removeNotAttributeSpan(node) {
  85. if (!node.style.cssText) {
  86. domUtils.removeAttributes(node, ["style"]);
  87. if (
  88. node.tagName.toLowerCase() == "span" &&
  89. domUtils.hasNoAttributes(node)
  90. ) {
  91. domUtils.remove(node, true);
  92. }
  93. }
  94. }
  95. function autotype(type, html) {
  96. var me = this,
  97. cont;
  98. if (html) {
  99. if (!opt.pasteFilter) {
  100. return;
  101. }
  102. cont = me.document.createElement("div");
  103. cont.innerHTML = html.html;
  104. } else {
  105. cont = me.document.body;
  106. }
  107. var nodes = domUtils.getElementsByTagName(cont, "*");
  108. // 行首缩进,段落方向,段间距,段内间距
  109. for (var i = 0, ci; (ci = nodes[i++]); ) {
  110. if (me.fireEvent("excludeNodeinautotype", ci) === true) {
  111. continue;
  112. }
  113. //font-size
  114. if (opt.clearFontSize && ci.style.fontSize) {
  115. domUtils.removeStyle(ci, "font-size");
  116. removeNotAttributeSpan(ci);
  117. }
  118. //font-family
  119. if (opt.clearFontFamily && ci.style.fontFamily) {
  120. domUtils.removeStyle(ci, "font-family");
  121. removeNotAttributeSpan(ci);
  122. }
  123. if (isLine(ci)) {
  124. //合并空行
  125. if (opt.mergeEmptyline) {
  126. var next = ci.nextSibling,
  127. tmpNode,
  128. isBr = domUtils.isBr(ci);
  129. while (isLine(next)) {
  130. tmpNode = next;
  131. next = tmpNode.nextSibling;
  132. if (isBr && (!next || (next && !domUtils.isBr(next)))) {
  133. break;
  134. }
  135. domUtils.remove(tmpNode);
  136. }
  137. }
  138. //去掉空行,保留占位的空行
  139. if (
  140. opt.removeEmptyline &&
  141. domUtils.inDoc(ci, cont) &&
  142. !remainTag[ci.parentNode.tagName.toLowerCase()]
  143. ) {
  144. if (domUtils.isBr(ci)) {
  145. next = ci.nextSibling;
  146. if (next && !domUtils.isBr(next)) {
  147. continue;
  148. }
  149. }
  150. domUtils.remove(ci);
  151. continue;
  152. }
  153. }
  154. if (isLine(ci, true) && ci.tagName != "SPAN") {
  155. if (opt.indent) {
  156. ci.style.textIndent = opt.indentValue;
  157. }
  158. if (opt.textAlign) {
  159. ci.style.textAlign = opt.textAlign;
  160. }
  161. // if(opt.lineHeight)
  162. // ci.style.lineHeight = opt.lineHeight + 'cm';
  163. }
  164. //去掉class,保留的class不去掉
  165. if (
  166. opt.removeClass &&
  167. ci.className &&
  168. !remainClass[ci.className.toLowerCase()]
  169. ) {
  170. if (highlightCont && highlightCont.contains(ci)) {
  171. continue;
  172. }
  173. domUtils.removeAttributes(ci, ["class"]);
  174. }
  175. //表情不处理
  176. if (
  177. opt.imageBlockLine &&
  178. ci.tagName.toLowerCase() == "img" &&
  179. !ci.getAttribute("emotion")
  180. ) {
  181. if (html) {
  182. var img = ci;
  183. switch (opt.imageBlockLine) {
  184. case "left":
  185. case "right":
  186. case "none":
  187. var pN = img.parentNode,
  188. tmpNode,
  189. pre,
  190. next;
  191. while (dtd.$inline[pN.tagName] || pN.tagName == "A") {
  192. pN = pN.parentNode;
  193. }
  194. tmpNode = pN;
  195. if (
  196. tmpNode.tagName == "P" &&
  197. domUtils.getStyle(tmpNode, "text-align") == "center"
  198. ) {
  199. if (
  200. !domUtils.isBody(tmpNode) &&
  201. domUtils.getChildCount(tmpNode, function(node) {
  202. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  203. }) == 1
  204. ) {
  205. pre = tmpNode.previousSibling;
  206. next = tmpNode.nextSibling;
  207. if (
  208. pre &&
  209. next &&
  210. pre.nodeType == 1 &&
  211. next.nodeType == 1 &&
  212. pre.tagName == next.tagName &&
  213. domUtils.isBlockElm(pre)
  214. ) {
  215. pre.appendChild(tmpNode.firstChild);
  216. while (next.firstChild) {
  217. pre.appendChild(next.firstChild);
  218. }
  219. domUtils.remove(tmpNode);
  220. domUtils.remove(next);
  221. } else {
  222. domUtils.setStyle(tmpNode, "text-align", "");
  223. }
  224. }
  225. }
  226. domUtils.setStyle(img, "float", opt.imageBlockLine);
  227. break;
  228. case "center":
  229. if (me.queryCommandValue("imagefloat") != "center") {
  230. pN = img.parentNode;
  231. domUtils.setStyle(img, "float", "none");
  232. tmpNode = img;
  233. while (
  234. pN &&
  235. domUtils.getChildCount(pN, function(node) {
  236. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  237. }) == 1 &&
  238. (dtd.$inline[pN.tagName] || pN.tagName == "A")
  239. ) {
  240. tmpNode = pN;
  241. pN = pN.parentNode;
  242. }
  243. var pNode = me.document.createElement("p");
  244. domUtils.setAttributes(pNode, {
  245. style: "text-align:center"
  246. });
  247. tmpNode.parentNode.insertBefore(pNode, tmpNode);
  248. pNode.appendChild(tmpNode);
  249. domUtils.setStyle(tmpNode, "float", "");
  250. }
  251. }
  252. } else {
  253. var range = me.selection.getRange();
  254. range.selectNode(ci).select();
  255. me.execCommand("imagefloat", opt.imageBlockLine);
  256. }
  257. }
  258. //去掉冗余的标签
  259. if (opt.removeEmptyNode) {
  260. if (
  261. opt.removeTagNames[ci.tagName.toLowerCase()] &&
  262. domUtils.hasNoAttributes(ci) &&
  263. domUtils.isEmptyBlock(ci)
  264. ) {
  265. domUtils.remove(ci);
  266. }
  267. }
  268. }
  269. if (opt.tobdc) {
  270. var root = UE.htmlparser(cont.innerHTML);
  271. root.traversal(function(node) {
  272. if (node.type == "text") {
  273. node.data = ToDBC(node.data);
  274. }
  275. });
  276. cont.innerHTML = root.toHtml();
  277. }
  278. if (opt.bdc2sb) {
  279. var root = UE.htmlparser(cont.innerHTML);
  280. root.traversal(function(node) {
  281. if (node.type == "text") {
  282. node.data = DBC2SB(node.data);
  283. }
  284. });
  285. cont.innerHTML = root.toHtml();
  286. }
  287. if (html) {
  288. html.html = cont.innerHTML;
  289. }
  290. }
  291. if (opt.pasteFilter) {
  292. me.addListener("beforepaste", autotype);
  293. }
  294. function DBC2SB(str) {
  295. var result = "";
  296. for (var i = 0; i < str.length; i++) {
  297. var code = str.charCodeAt(i); //获取当前字符的unicode编码
  298. if (code >= 65281 && code <= 65373) {
  299. //在这个unicode编码范围中的是所有的英文字母已经各种字符
  300. result += String.fromCharCode(str.charCodeAt(i) - 65248); //把全角字符的unicode编码转换为对应半角字符的unicode码
  301. } else if (code == 12288) {
  302. //空格
  303. result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32);
  304. } else {
  305. result += str.charAt(i);
  306. }
  307. }
  308. return result;
  309. }
  310. function ToDBC(txtstring) {
  311. txtstring = utils.html(txtstring);
  312. var tmp = "";
  313. var mark = ""; /*用于判断,如果是html尖括里的标记,则不进行全角的转换*/
  314. for (var i = 0; i < txtstring.length; i++) {
  315. if (txtstring.charCodeAt(i) == 32) {
  316. tmp = tmp + String.fromCharCode(12288);
  317. } else if (txtstring.charCodeAt(i) < 127) {
  318. tmp = tmp + String.fromCharCode(txtstring.charCodeAt(i) + 65248);
  319. } else {
  320. tmp += txtstring.charAt(i);
  321. }
  322. }
  323. return tmp;
  324. }
  325. function readLocalOpts() {
  326. var cookieOpt = me.getPreferences("autotypeset");
  327. utils.extend(me.options.autotypeset, cookieOpt);
  328. }
  329. me.commands["autotypeset"] = {
  330. execCommand: function() {
  331. me.removeListener("beforepaste", autotype);
  332. if (opt.pasteFilter) {
  333. me.addListener("beforepaste", autotype);
  334. }
  335. autotype.call(me);
  336. }
  337. };
  338. };