paste.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. ///import core
  2. ///import plugins/inserthtml.js
  3. ///import plugins/undo.js
  4. ///import plugins/serialize.js
  5. ///commands 粘贴
  6. ///commandsName PastePlain
  7. ///commandsTitle 纯文本粘贴模式
  8. /**
  9. * @description 粘贴
  10. * @author zhanyi
  11. */
  12. UE.plugins['paste'] = function () {
  13. function getClipboardData(callback) {
  14. var doc = this.document;
  15. if (doc.getElementById('baidu_pastebin')) {
  16. return;
  17. }
  18. var range = this.selection.getRange(),
  19. bk = range.createBookmark(),
  20. //创建剪贴的容器div
  21. pastebin = doc.createElement('div');
  22. pastebin.id = 'baidu_pastebin';
  23. // Safari 要求div必须有内容,才能粘贴内容进来
  24. browser.webkit && pastebin.appendChild(doc.createTextNode(domUtils.fillChar + domUtils.fillChar));
  25. doc.body.appendChild(pastebin);
  26. //trace:717 隐藏的span不能得到top
  27. //bk.start.innerHTML = ' ';
  28. bk.start.style.display = '';
  29. pastebin.style.cssText = "position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
  30. //要在现在光标平行的位置加入,否则会出现跳动的问题
  31. domUtils.getXY(bk.start).y + 'px';
  32. range.selectNodeContents(pastebin).select(true);
  33. setTimeout(function () {
  34. if (browser.webkit) {
  35. for (var i = 0, pastebins = doc.querySelectorAll('#baidu_pastebin'), pi; pi = pastebins[i++];) {
  36. if (domUtils.isEmptyNode(pi)) {
  37. domUtils.remove(pi);
  38. } else {
  39. pastebin = pi;
  40. break;
  41. }
  42. }
  43. }
  44. try {
  45. pastebin.parentNode.removeChild(pastebin);
  46. } catch (e) {
  47. }
  48. range.moveToBookmark(bk).select(true);
  49. callback(pastebin);
  50. }, 0);
  51. }
  52. var me = this;
  53. me.setOpt({
  54. retainOnlyLabelPasted : false
  55. });
  56. var txtContent, htmlContent, address;
  57. function getPureHtml(html){
  58. return html.replace(/<(\/?)([\w\-]+)([^>]*)>/gi, function (a, b, tagName, attrs) {
  59. tagName = tagName.toLowerCase();
  60. if ({img: 1}[tagName]) {
  61. return a;
  62. }
  63. attrs = attrs.replace(/([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi, function (str, atr, val) {
  64. if ({
  65. 'src': 1,
  66. 'href': 1,
  67. 'name': 1
  68. }[atr.toLowerCase()]) {
  69. return atr + '=' + val + ' '
  70. }
  71. return ''
  72. });
  73. if ({
  74. 'span': 1,
  75. 'div': 1
  76. }[tagName]) {
  77. return ''
  78. } else {
  79. return '<' + b + tagName + ' ' + utils.trim(attrs) + '>'
  80. }
  81. });
  82. }
  83. function filter(div) {
  84. var html;
  85. if (div.firstChild) {
  86. //去掉cut中添加的边界值
  87. var nodes = domUtils.getElementsByTagName(div, 'span');
  88. for (var i = 0, ni; ni = nodes[i++];) {
  89. if (ni.id == '_baidu_cut_start' || ni.id == '_baidu_cut_end') {
  90. domUtils.remove(ni);
  91. }
  92. }
  93. if (browser.webkit) {
  94. var brs = div.querySelectorAll('div br');
  95. for (var i = 0, bi; bi = brs[i++];) {
  96. var pN = bi.parentNode;
  97. if (pN.tagName == 'DIV' && pN.childNodes.length == 1) {
  98. pN.innerHTML = '<p><br/></p>';
  99. domUtils.remove(pN);
  100. }
  101. }
  102. var divs = div.querySelectorAll('#baidu_pastebin');
  103. for (var i = 0, di; di = divs[i++];) {
  104. var tmpP = me.document.createElement('p');
  105. di.parentNode.insertBefore(tmpP, di);
  106. while (di.firstChild) {
  107. tmpP.appendChild(di.firstChild);
  108. }
  109. domUtils.remove(di);
  110. }
  111. var metas = div.querySelectorAll('meta');
  112. for (var i = 0, ci; ci = metas[i++];) {
  113. domUtils.remove(ci);
  114. }
  115. var brs = div.querySelectorAll('br');
  116. for (i = 0; ci = brs[i++];) {
  117. if (/^apple-/i.test(ci.className)) {
  118. domUtils.remove(ci);
  119. }
  120. }
  121. }
  122. if (browser.gecko) {
  123. var dirtyNodes = div.querySelectorAll('[_moz_dirty]');
  124. for (i = 0; ci = dirtyNodes[i++];) {
  125. ci.removeAttribute('_moz_dirty');
  126. }
  127. }
  128. if (!browser.ie) {
  129. var spans = div.querySelectorAll('span.Apple-style-span');
  130. for (var i = 0, ci; ci = spans[i++];) {
  131. domUtils.remove(ci, true);
  132. }
  133. }
  134. //ie下使用innerHTML会产生多余的\r\n字符,也会产生&nbsp;这里过滤掉
  135. html = div.innerHTML;//.replace(/>(?:(\s|&nbsp;)*?)</g,'><');
  136. //过滤word粘贴过来的冗余属性
  137. html = UE.filterWord(html);
  138. //取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
  139. var root = UE.htmlparser(html);
  140. //如果给了过滤规则就先进行过滤
  141. if (me.options.filterRules) {
  142. UE.filterNode(root, me.options.filterRules);
  143. }
  144. //执行默认的处理
  145. me.filterInputRule(root);
  146. //针对chrome的处理
  147. if (browser.webkit) {
  148. var br = root.lastChild();
  149. if (br && br.type == 'element' && br.tagName == 'br') {
  150. root.removeChild(br)
  151. }
  152. utils.each(me.body.querySelectorAll('div'), function (node) {
  153. if (domUtils.isEmptyBlock(node)) {
  154. domUtils.remove(node,true)
  155. }
  156. })
  157. }
  158. html = {'html': root.toHtml()};
  159. me.fireEvent('beforepaste', html, root);
  160. //抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
  161. if(!html.html){
  162. return;
  163. }
  164. root = UE.htmlparser(html.html,true);
  165. //如果开启了纯文本模式
  166. if (me.queryCommandState('pasteplain') === 1) {
  167. me.execCommand('insertHtml', UE.filterNode(root, me.options.filterTxtRules).toHtml(), true);
  168. } else {
  169. //文本模式
  170. UE.filterNode(root, me.options.filterTxtRules);
  171. txtContent = root.toHtml();
  172. //完全模式
  173. htmlContent = html.html;
  174. address = me.selection.getRange().createAddress(true);
  175. me.execCommand('insertHtml', me.getOpt('retainOnlyLabelPasted') === true ? getPureHtml(htmlContent) : htmlContent, true);
  176. }
  177. me.fireEvent("afterpaste", html);
  178. }
  179. }
  180. me.addListener('pasteTransfer', function (cmd, plainType) {
  181. if (address && txtContent && htmlContent && txtContent != htmlContent) {
  182. var range = me.selection.getRange();
  183. range.moveToAddress(address, true);
  184. if (!range.collapsed) {
  185. while (!domUtils.isBody(range.startContainer)
  186. ) {
  187. var start = range.startContainer;
  188. if(start.nodeType == 1){
  189. start = start.childNodes[range.startOffset];
  190. if(!start){
  191. range.setStartBefore(range.startContainer);
  192. continue;
  193. }
  194. var pre = start.previousSibling;
  195. if(pre && pre.nodeType == 3 && new RegExp('^[\n\r\t '+domUtils.fillChar+']*$').test(pre.nodeValue)){
  196. range.setStartBefore(pre)
  197. }
  198. }
  199. if(range.startOffset == 0){
  200. range.setStartBefore(range.startContainer);
  201. }else{
  202. break;
  203. }
  204. }
  205. while (!domUtils.isBody(range.endContainer)
  206. ) {
  207. var end = range.endContainer;
  208. if(end.nodeType == 1){
  209. end = end.childNodes[range.endOffset];
  210. if(!end){
  211. range.setEndAfter(range.endContainer);
  212. continue;
  213. }
  214. var next = end.nextSibling;
  215. if(next && next.nodeType == 3 && new RegExp('^[\n\r\t'+domUtils.fillChar+']*$').test(next.nodeValue)){
  216. range.setEndAfter(next)
  217. }
  218. }
  219. if(range.endOffset == range.endContainer[range.endContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length){
  220. range.setEndAfter(range.endContainer);
  221. }else{
  222. break;
  223. }
  224. }
  225. }
  226. range.deleteContents();
  227. range.select(true);
  228. me.__hasEnterExecCommand = true;
  229. var html = htmlContent;
  230. if (plainType === 2 ) {
  231. html = getPureHtml(html);
  232. } else if (plainType) {
  233. html = txtContent;
  234. }
  235. me.execCommand('inserthtml', html, true);
  236. me.__hasEnterExecCommand = false;
  237. var rng = me.selection.getRange();
  238. while (!domUtils.isBody(rng.startContainer) && !rng.startOffset &&
  239. rng.startContainer[rng.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
  240. ) {
  241. rng.setStartBefore(rng.startContainer);
  242. }
  243. var tmpAddress = rng.createAddress(true);
  244. address.endAddress = tmpAddress.startAddress;
  245. }
  246. });
  247. me.addListener('ready', function () {
  248. domUtils.on(me.body, 'cut', function () {
  249. var range = me.selection.getRange();
  250. if (!range.collapsed && me.undoManger) {
  251. me.undoManger.save();
  252. }
  253. });
  254. //ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
  255. domUtils.on(me.body, browser.ie || browser.opera ? 'keydown' : 'paste', function (e) {
  256. if ((browser.ie || browser.opera) && ((!e.ctrlKey && !e.metaKey) || e.keyCode != '86')) {
  257. return;
  258. }
  259. getClipboardData.call(me, function (div) {
  260. filter(div);
  261. });
  262. });
  263. });
  264. me.commands['paste'] = {
  265. execCommand: function (cmd) {
  266. if (browser.ie) {
  267. getClipboardData.call(me, function (div) {
  268. filter(div);
  269. });
  270. me.document.execCommand('paste');
  271. } else {
  272. alert(me.getLang('pastemsg'));
  273. }
  274. }
  275. }
  276. };