inserthtml.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /**
  2. * 插入html字符串插件
  3. * @file
  4. * @since 1.2.6.1
  5. */
  6. /**
  7. * 插入html代码
  8. * @command inserthtml
  9. * @method execCommand
  10. * @param { String } cmd 命令字符串
  11. * @param { String } html 插入的html字符串
  12. * @remaind 插入的标签内容是在当前的选区位置上插入,如果当前是闭合状态,那直接插入内容, 如果当前是选中状态,将先清除当前选中内容后,再做插入
  13. * @warning 注意:该命令会对当前选区的位置,对插入的内容进行过滤转换处理。 过滤的规则遵循html语意化的原则。
  14. * @example
  15. * ```javascript
  16. * //xxx[BB]xxx 当前选区为非闭合选区,选中BB这两个文本
  17. * //执行命令,插入<b>CC</b>
  18. * //插入后的效果 xxx<b>CC</b>xxx
  19. * //<p>xx|xxx</p> 当前选区为闭合状态
  20. * //插入<p>CC</p>
  21. * //结果 <p>xx</p><p>CC</p><p>xxx</p>
  22. * //<p>xxxx</p>|</p>xxx</p> 当前选区在两个p标签之间
  23. * //插入 xxxx
  24. * //结果 <p>xxxx</p><p>xxxx</p></p>xxx</p>
  25. * ```
  26. */
  27. UE.commands["inserthtml"] = {
  28. execCommand: function(command, html, notNeedFilter) {
  29. var me = this,
  30. range,
  31. div;
  32. if (!html) {
  33. return;
  34. }
  35. if (me.fireEvent("beforeinserthtml", html) === true) {
  36. return;
  37. }
  38. range = me.selection.getRange();
  39. div = range.document.createElement("div");
  40. div.style.display = "inline";
  41. if (!notNeedFilter) {
  42. var root = UE.htmlparser(html);
  43. //如果给了过滤规则就先进行过滤
  44. if (me.options.filterRules) {
  45. UE.filterNode(root, me.options.filterRules);
  46. }
  47. //执行默认的处理
  48. me.filterInputRule(root);
  49. html = root.toHtml();
  50. }
  51. div.innerHTML = utils.trim(html);
  52. if (!range.collapsed) {
  53. var tmpNode = range.startContainer;
  54. if (domUtils.isFillChar(tmpNode)) {
  55. range.setStartBefore(tmpNode);
  56. }
  57. tmpNode = range.endContainer;
  58. if (domUtils.isFillChar(tmpNode)) {
  59. range.setEndAfter(tmpNode);
  60. }
  61. range.txtToElmBoundary();
  62. //结束边界可能放到了br的前边,要把br包含进来
  63. // x[xxx]<br/>
  64. if (range.endContainer && range.endContainer.nodeType == 1) {
  65. tmpNode = range.endContainer.childNodes[range.endOffset];
  66. if (tmpNode && domUtils.isBr(tmpNode)) {
  67. range.setEndAfter(tmpNode);
  68. }
  69. }
  70. if (range.startOffset == 0) {
  71. tmpNode = range.startContainer;
  72. if (domUtils.isBoundaryNode(tmpNode, "firstChild")) {
  73. tmpNode = range.endContainer;
  74. if (
  75. range.endOffset ==
  76. (tmpNode.nodeType == 3
  77. ? tmpNode.nodeValue.length
  78. : tmpNode.childNodes.length) &&
  79. domUtils.isBoundaryNode(tmpNode, "lastChild")
  80. ) {
  81. me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
  82. range.setStart(me.body.firstChild, 0).collapse(true);
  83. }
  84. }
  85. }
  86. !range.collapsed && range.deleteContents();
  87. if (range.startContainer.nodeType == 1) {
  88. var child = range.startContainer.childNodes[range.startOffset],
  89. pre;
  90. if (
  91. child &&
  92. domUtils.isBlockElm(child) &&
  93. (pre = child.previousSibling) &&
  94. domUtils.isBlockElm(pre)
  95. ) {
  96. range.setEnd(pre, pre.childNodes.length).collapse();
  97. while (child.firstChild) {
  98. pre.appendChild(child.firstChild);
  99. }
  100. domUtils.remove(child);
  101. }
  102. }
  103. }
  104. var child,
  105. parent,
  106. pre,
  107. tmp,
  108. hadBreak = 0,
  109. nextNode;
  110. //如果当前位置选中了fillchar要干掉,要不会产生空行
  111. if (range.inFillChar()) {
  112. child = range.startContainer;
  113. if (domUtils.isFillChar(child)) {
  114. range.setStartBefore(child).collapse(true);
  115. domUtils.remove(child);
  116. } else if (domUtils.isFillChar(child, true)) {
  117. child.nodeValue = child.nodeValue.replace(fillCharReg, "");
  118. range.startOffset--;
  119. range.collapsed && range.collapse(true);
  120. }
  121. }
  122. //列表单独处理
  123. var li = domUtils.findParentByTagName(range.startContainer, "li", true);
  124. if (li) {
  125. var next, last;
  126. while ((child = div.firstChild)) {
  127. //针对hr单独处理一下先
  128. while (
  129. child &&
  130. (child.nodeType == 3 ||
  131. !domUtils.isBlockElm(child) ||
  132. child.tagName == "HR")
  133. ) {
  134. next = child.nextSibling;
  135. range.insertNode(child).collapse();
  136. last = child;
  137. child = next;
  138. }
  139. if (child) {
  140. if (/^(ol|ul)$/i.test(child.tagName)) {
  141. while (child.firstChild) {
  142. last = child.firstChild;
  143. domUtils.insertAfter(li, child.firstChild);
  144. li = li.nextSibling;
  145. }
  146. domUtils.remove(child);
  147. } else {
  148. var tmpLi;
  149. next = child.nextSibling;
  150. tmpLi = me.document.createElement("li");
  151. domUtils.insertAfter(li, tmpLi);
  152. tmpLi.appendChild(child);
  153. last = child;
  154. child = next;
  155. li = tmpLi;
  156. }
  157. }
  158. }
  159. li = domUtils.findParentByTagName(range.startContainer, "li", true);
  160. if (domUtils.isEmptyBlock(li)) {
  161. domUtils.remove(li);
  162. }
  163. if (last) {
  164. range.setStartAfter(last).collapse(true).select(true);
  165. }
  166. } else {
  167. while ((child = div.firstChild)) {
  168. if (hadBreak) {
  169. var p = me.document.createElement("p");
  170. while (child && (child.nodeType == 3 || !dtd.$block[child.tagName])) {
  171. nextNode = child.nextSibling;
  172. p.appendChild(child);
  173. child = nextNode;
  174. }
  175. if (p.firstChild) {
  176. child = p;
  177. }
  178. }
  179. range.insertNode(child);
  180. nextNode = child.nextSibling;
  181. if (
  182. !hadBreak &&
  183. child.nodeType == domUtils.NODE_ELEMENT &&
  184. domUtils.isBlockElm(child)
  185. ) {
  186. parent = domUtils.findParent(child, function(node) {
  187. return domUtils.isBlockElm(node);
  188. });
  189. if (
  190. parent &&
  191. parent.tagName.toLowerCase() != "body" &&
  192. !(
  193. dtd[parent.tagName][child.nodeName] && child.parentNode === parent
  194. )
  195. ) {
  196. if (!dtd[parent.tagName][child.nodeName]) {
  197. pre = parent;
  198. } else {
  199. tmp = child.parentNode;
  200. while (tmp !== parent) {
  201. pre = tmp;
  202. tmp = tmp.parentNode;
  203. }
  204. }
  205. domUtils.breakParent(child, pre || tmp);
  206. //去掉break后前一个多余的节点 <p>|<[p> ==> <p></p><div></div><p>|</p>
  207. var pre = child.previousSibling;
  208. domUtils.trimWhiteTextNode(pre);
  209. if (!pre.childNodes.length) {
  210. domUtils.remove(pre);
  211. }
  212. //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位
  213. if (
  214. !browser.ie &&
  215. (next = child.nextSibling) &&
  216. domUtils.isBlockElm(next) &&
  217. next.lastChild &&
  218. !domUtils.isBr(next.lastChild)
  219. ) {
  220. next.appendChild(me.document.createElement("br"));
  221. }
  222. hadBreak = 1;
  223. }
  224. }
  225. var next = child.nextSibling;
  226. if (!div.firstChild && next && domUtils.isBlockElm(next)) {
  227. range.setStart(next, 0).collapse(true);
  228. break;
  229. }
  230. range.setEndAfter(child).collapse();
  231. }
  232. child = range.startContainer;
  233. if (nextNode && domUtils.isBr(nextNode)) {
  234. domUtils.remove(nextNode);
  235. }
  236. //用chrome可能有空白展位符
  237. if (domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)) {
  238. if ((nextNode = child.nextSibling)) {
  239. domUtils.remove(child);
  240. if (nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) {
  241. range.setStart(nextNode, 0).collapse(true).shrinkBoundary();
  242. }
  243. } else {
  244. try {
  245. child.innerHTML = browser.ie ? domUtils.fillChar : "<br/>";
  246. } catch (e) {
  247. range.setStartBefore(child);
  248. domUtils.remove(child);
  249. }
  250. }
  251. }
  252. //加上true因为在删除表情等时会删两次,第一次是删的fillData
  253. try {
  254. range.select(true);
  255. } catch (e) {}
  256. }
  257. setTimeout(function() {
  258. range = me.selection.getRange();
  259. range.scrollToView(
  260. me.autoHeightEnabled,
  261. me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0
  262. );
  263. me.fireEvent("afterinserthtml", html);
  264. }, 200);
  265. }
  266. };