insertcode.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. /**
  2. * 插入代码插件
  3. * @file
  4. * @since 1.2.6.1
  5. */
  6. UE.plugins['insertcode'] = function() {
  7. var me = this;
  8. me.ready(function(){
  9. utils.cssRule('pre','pre{margin:.5em 0;padding:.4em .6em;border-radius:8px;background:#f8f8f8;}',
  10. me.document)
  11. });
  12. me.setOpt('insertcode',{
  13. 'as3':'ActionScript3',
  14. 'bash':'Bash/Shell',
  15. 'cpp':'C/C++',
  16. 'css':'Css',
  17. 'cf':'CodeFunction',
  18. 'c#':'C#',
  19. 'delphi':'Delphi',
  20. 'diff':'Diff',
  21. 'erlang':'Erlang',
  22. 'groovy':'Groovy',
  23. 'html':'Html',
  24. 'java':'Java',
  25. 'jfx':'JavaFx',
  26. 'js':'Javascript',
  27. 'pl':'Perl',
  28. 'php':'Php',
  29. 'plain':'Plain Text',
  30. 'ps':'PowerShell',
  31. 'python':'Python',
  32. 'ruby':'Ruby',
  33. 'scala':'Scala',
  34. 'sql':'Sql',
  35. 'vb':'Vb',
  36. 'xml':'Xml'
  37. });
  38. /**
  39. * 插入代码
  40. * @command insertcode
  41. * @method execCommand
  42. * @param { String } cmd 命令字符串
  43. * @param { String } lang 插入代码的语言
  44. * @example
  45. * ```javascript
  46. * editor.execCommand( 'insertcode', 'javascript' );
  47. * ```
  48. */
  49. /**
  50. * 如果选区所在位置是插入插入代码区域,返回代码的语言
  51. * @command insertcode
  52. * @method queryCommandValue
  53. * @param { String } cmd 命令字符串
  54. * @return { String } 返回代码的语言
  55. * @example
  56. * ```javascript
  57. * editor.queryCommandValue( 'insertcode' );
  58. * ```
  59. */
  60. me.commands['insertcode'] = {
  61. execCommand : function(cmd,lang){
  62. var me = this,
  63. rng = me.selection.getRange(),
  64. pre = domUtils.findParentByTagName(rng.startContainer,'pre',true);
  65. if(pre){
  66. pre.className = 'brush:'+lang+';toolbar:false;';
  67. }else{
  68. var code = '';
  69. if(rng.collapsed){
  70. code = browser.ie && browser.ie11below ? (browser.version <= 8 ? '&nbsp;':''):'<br/>';
  71. }else{
  72. var frag = rng.extractContents();
  73. var div = me.document.createElement('div');
  74. div.appendChild(frag);
  75. utils.each(UE.filterNode(UE.htmlparser(div.innerHTML.replace(/[\r\t]/g,'')),me.options.filterTxtRules).children,function(node){
  76. if(browser.ie && browser.ie11below && browser.version > 8){
  77. if(node.type =='element'){
  78. if(node.tagName == 'br'){
  79. code += '\n'
  80. }else if(!dtd.$empty[node.tagName]){
  81. utils.each(node.children,function(cn){
  82. if(cn.type =='element'){
  83. if(cn.tagName == 'br'){
  84. code += '\n'
  85. }else if(!dtd.$empty[node.tagName]){
  86. code += cn.innerText();
  87. }
  88. }else{
  89. code += cn.data
  90. }
  91. })
  92. if(!/\n$/.test(code)){
  93. code += '\n';
  94. }
  95. }
  96. }else{
  97. code += node.data + '\n'
  98. }
  99. if(!node.nextSibling() && /\n$/.test(code)){
  100. code = code.replace(/\n$/,'');
  101. }
  102. }else{
  103. if(browser.ie && browser.ie11below){
  104. if(node.type =='element'){
  105. if(node.tagName == 'br'){
  106. code += '<br>'
  107. }else if(!dtd.$empty[node.tagName]){
  108. utils.each(node.children,function(cn){
  109. if(cn.type =='element'){
  110. if(cn.tagName == 'br'){
  111. code += '<br>'
  112. }else if(!dtd.$empty[node.tagName]){
  113. code += cn.innerText();
  114. }
  115. }else{
  116. code += cn.data
  117. }
  118. });
  119. if(!/br>$/.test(code)){
  120. code += '<br>';
  121. }
  122. }
  123. }else{
  124. code += node.data + '<br>'
  125. }
  126. if(!node.nextSibling() && /<br>$/.test(code)){
  127. code = code.replace(/<br>$/,'');
  128. }
  129. }else{
  130. code += (node.type == 'element' ? (dtd.$empty[node.tagName] ? '' : node.innerText()) : node.data);
  131. if(!/br\/?\s*>$/.test(code)){
  132. if(!node.nextSibling())
  133. return;
  134. code += '<br>'
  135. }
  136. }
  137. }
  138. });
  139. }
  140. me.execCommand('inserthtml','<pre id="coder"class="brush:'+lang+';toolbar:false">'+code+'</pre>',true);
  141. pre = me.document.getElementById('coder');
  142. domUtils.removeAttributes(pre,'id');
  143. var tmpNode = pre.previousSibling;
  144. if(tmpNode && (tmpNode.nodeType == 3 && tmpNode.nodeValue.length == 1 && browser.ie && browser.version == 6 || domUtils.isEmptyBlock(tmpNode))){
  145. domUtils.remove(tmpNode)
  146. }
  147. var rng = me.selection.getRange();
  148. if(domUtils.isEmptyBlock(pre)){
  149. rng.setStart(pre,0).setCursor(false,true)
  150. }else{
  151. rng.selectNodeContents(pre).select()
  152. }
  153. }
  154. },
  155. queryCommandValue : function(){
  156. var path = this.selection.getStartElementPath();
  157. var lang = '';
  158. utils.each(path,function(node){
  159. if(node.nodeName =='PRE'){
  160. var match = node.className.match(/brush:([^;]+)/);
  161. lang = match && match[1] ? match[1] : '';
  162. return false;
  163. }
  164. });
  165. return lang;
  166. }
  167. };
  168. me.addInputRule(function(root){
  169. utils.each(root.getNodesByTagName('pre'),function(pre){
  170. var brs = pre.getNodesByTagName('br');
  171. if(brs.length){
  172. browser.ie && browser.ie11below && browser.version > 8 && utils.each(brs,function(br){
  173. var txt = UE.uNode.createText('\n');
  174. br.parentNode.insertBefore(txt,br);
  175. br.parentNode.removeChild(br);
  176. });
  177. return;
  178. }
  179. if(browser.ie && browser.ie11below && browser.version > 8)
  180. return;
  181. var code = pre.innerText().split(/\n/);
  182. pre.innerHTML('');
  183. utils.each(code,function(c){
  184. if(c.length){
  185. pre.appendChild(UE.uNode.createText(c));
  186. }
  187. pre.appendChild(UE.uNode.createElement('br'))
  188. })
  189. })
  190. });
  191. me.addOutputRule(function(root){
  192. utils.each(root.getNodesByTagName('pre'),function(pre){
  193. var code = '';
  194. utils.each(pre.children,function(n){
  195. if(n.type == 'text'){
  196. //在ie下文本内容有可能末尾带有\n要去掉
  197. //trace:3396
  198. code += n.data.replace(/[ ]/g,'&nbsp;').replace(/\n$/,'');
  199. }else{
  200. if(n.tagName == 'br'){
  201. code += '\n'
  202. }else{
  203. code += (!dtd.$empty[n.tagName] ? '' : n.innerText());
  204. }
  205. }
  206. });
  207. pre.innerText(code.replace(/(&nbsp;|\n)+$/,''))
  208. })
  209. });
  210. //不需要判断highlight的command列表
  211. me.notNeedCodeQuery ={
  212. help:1,
  213. undo:1,
  214. redo:1,
  215. source:1,
  216. print:1,
  217. searchreplace:1,
  218. fullscreen:1,
  219. preview:1,
  220. insertparagraph:1,
  221. elementpath:1,
  222. insertcode:1,
  223. inserthtml:1,
  224. selectall:1
  225. };
  226. //将queyCommamndState重置
  227. var orgQuery = me.queryCommandState;
  228. me.queryCommandState = function(cmd){
  229. var me = this;
  230. if(!me.notNeedCodeQuery[cmd.toLowerCase()] && me.selection && me.queryCommandValue('insertcode')){
  231. return -1;
  232. }
  233. return UE.Editor.prototype.queryCommandState.apply(this,arguments)
  234. };
  235. me.addListener('beforeenterkeydown',function(){
  236. var rng = me.selection.getRange();
  237. var pre = domUtils.findParentByTagName(rng.startContainer,'pre',true);
  238. if(pre){
  239. me.fireEvent('saveScene');
  240. if(!rng.collapsed){
  241. rng.deleteContents();
  242. }
  243. if(!browser.ie || browser.ie9above){
  244. var tmpNode = me.document.createElement('br'),pre;
  245. rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true);
  246. var next = tmpNode.nextSibling;
  247. if(!next && (!browser.ie || browser.version > 10)){
  248. rng.insertNode(tmpNode.cloneNode(false));
  249. }else{
  250. rng.setStartAfter(tmpNode);
  251. }
  252. pre = tmpNode.previousSibling;
  253. var tmp;
  254. while(pre ){
  255. tmp = pre;
  256. pre = pre.previousSibling;
  257. if(!pre || pre.nodeName == 'BR'){
  258. pre = tmp;
  259. break;
  260. }
  261. }
  262. if(pre){
  263. var str = '';
  264. while(pre && pre.nodeName != 'BR' && new RegExp('^[\\s'+domUtils.fillChar+']*$').test(pre.nodeValue)){
  265. str += pre.nodeValue;
  266. pre = pre.nextSibling;
  267. }
  268. if(pre.nodeName != 'BR'){
  269. var match = pre.nodeValue.match(new RegExp('^([\\s'+domUtils.fillChar+']+)'));
  270. if(match && match[1]){
  271. str += match[1]
  272. }
  273. }
  274. if(str){
  275. str = me.document.createTextNode(str);
  276. rng.insertNode(str).setStartAfter(str);
  277. }
  278. }
  279. rng.collapse(true).select(true);
  280. }else{
  281. if(browser.version > 8){
  282. var txt = me.document.createTextNode('\n');
  283. var start = rng.startContainer;
  284. if(rng.startOffset == 0){
  285. var preNode = start.previousSibling;
  286. if(preNode){
  287. rng.insertNode(txt);
  288. var fillchar = me.document.createTextNode(' ');
  289. rng.setStartAfter(txt).insertNode(fillchar).setStart(fillchar,0).collapse(true).select(true)
  290. }
  291. }else{
  292. rng.insertNode(txt).setStartAfter(txt);
  293. var fillchar = me.document.createTextNode(' ');
  294. start = rng.startContainer.childNodes[rng.startOffset];
  295. if(start && !/^\n/.test(start.nodeValue)){
  296. rng.setStartBefore(txt)
  297. }
  298. rng.insertNode(fillchar).setStart(fillchar,0).collapse(true).select(true)
  299. }
  300. }else{
  301. var tmpNode = me.document.createElement('br');
  302. rng.insertNode(tmpNode);
  303. rng.insertNode(me.document.createTextNode(domUtils.fillChar));
  304. rng.setStartAfter(tmpNode);
  305. pre = tmpNode.previousSibling;
  306. var tmp;
  307. while(pre ){
  308. tmp = pre;
  309. pre = pre.previousSibling;
  310. if(!pre || pre.nodeName == 'BR'){
  311. pre = tmp;
  312. break;
  313. }
  314. }
  315. if(pre){
  316. var str = '';
  317. while(pre && pre.nodeName != 'BR' && new RegExp('^[ '+domUtils.fillChar+']*$').test(pre.nodeValue)){
  318. str += pre.nodeValue;
  319. pre = pre.nextSibling;
  320. }
  321. if(pre.nodeName != 'BR'){
  322. var match = pre.nodeValue.match(new RegExp('^([ '+domUtils.fillChar+']+)'));
  323. if(match && match[1]){
  324. str += match[1]
  325. }
  326. }
  327. str = me.document.createTextNode(str);
  328. rng.insertNode(str).setStartAfter(str);
  329. }
  330. rng.collapse(true).select();
  331. }
  332. }
  333. me.fireEvent('saveScene');
  334. return true;
  335. }
  336. });
  337. me.addListener('tabkeydown',function(cmd,evt){
  338. var rng = me.selection.getRange();
  339. var pre = domUtils.findParentByTagName(rng.startContainer,'pre',true);
  340. if(pre){
  341. me.fireEvent('saveScene');
  342. if(evt.shiftKey){
  343. }else{
  344. if(!rng.collapsed){
  345. var bk = rng.createBookmark();
  346. var start = bk.start.previousSibling;
  347. while(start){
  348. if(pre.firstChild === start && !domUtils.isBr(start)){
  349. pre.insertBefore(me.document.createTextNode(' '),start);
  350. break;
  351. }
  352. if(domUtils.isBr(start)){
  353. pre.insertBefore(me.document.createTextNode(' '),start.nextSibling);
  354. break;
  355. }
  356. start = start.previousSibling;
  357. }
  358. var end = bk.end;
  359. start = bk.start.nextSibling;
  360. if(pre.firstChild === bk.start){
  361. pre.insertBefore(me.document.createTextNode(' '),start.nextSibling)
  362. }
  363. while(start && start !== end){
  364. if(domUtils.isBr(start) && start.nextSibling){
  365. if(start.nextSibling === end){
  366. break;
  367. }
  368. pre.insertBefore(me.document.createTextNode(' '),start.nextSibling)
  369. }
  370. start = start.nextSibling;
  371. }
  372. rng.moveToBookmark(bk).select();
  373. }else{
  374. var tmpNode = me.document.createTextNode(' ');
  375. rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true).select(true);
  376. }
  377. }
  378. me.fireEvent('saveScene');
  379. return true;
  380. }
  381. });
  382. me.addListener('beforeinserthtml',function(evtName,html){
  383. var me = this,
  384. rng = me.selection.getRange(),
  385. pre = domUtils.findParentByTagName(rng.startContainer,'pre',true);
  386. if(pre){
  387. if(!rng.collapsed){
  388. rng.deleteContents()
  389. }
  390. var htmlstr = '';
  391. if(browser.ie && browser.version > 8){
  392. utils.each(UE.filterNode(UE.htmlparser(html),me.options.filterTxtRules).children,function(node){
  393. if(node.type =='element'){
  394. if(node.tagName == 'br'){
  395. htmlstr += '\n'
  396. }else if(!dtd.$empty[node.tagName]){
  397. utils.each(node.children,function(cn){
  398. if(cn.type =='element'){
  399. if(cn.tagName == 'br'){
  400. htmlstr += '\n'
  401. }else if(!dtd.$empty[node.tagName]){
  402. htmlstr += cn.innerText();
  403. }
  404. }else{
  405. htmlstr += cn.data
  406. }
  407. })
  408. if(!/\n$/.test(htmlstr)){
  409. htmlstr += '\n';
  410. }
  411. }
  412. }else{
  413. htmlstr += node.data + '\n'
  414. }
  415. if(!node.nextSibling() && /\n$/.test(htmlstr)){
  416. htmlstr = htmlstr.replace(/\n$/,'');
  417. }
  418. });
  419. var tmpNode = me.document.createTextNode(utils.html(htmlstr.replace(/&nbsp;/g,' ')));
  420. rng.insertNode(tmpNode).selectNode(tmpNode).select();
  421. }else{
  422. var frag = me.document.createDocumentFragment();
  423. utils.each(UE.filterNode(UE.htmlparser(html),me.options.filterTxtRules).children,function(node){
  424. if(node.type =='element'){
  425. if(node.tagName == 'br'){
  426. frag.appendChild(me.document.createElement('br'))
  427. }else if(!dtd.$empty[node.tagName]){
  428. utils.each(node.children,function(cn){
  429. if(cn.type =='element'){
  430. if(cn.tagName == 'br'){
  431. frag.appendChild(me.document.createElement('br'))
  432. }else if(!dtd.$empty[node.tagName]){
  433. frag.appendChild(me.document.createTextNode(utils.html(cn.innerText().replace(/&nbsp;/g,' '))));
  434. }
  435. }else{
  436. frag.appendChild(me.document.createTextNode(utils.html( cn.data.replace(/&nbsp;/g,' '))));
  437. }
  438. })
  439. if(frag.lastChild.nodeName != 'BR'){
  440. frag.appendChild(me.document.createElement('br'))
  441. }
  442. }
  443. }else{
  444. frag.appendChild(me.document.createTextNode(utils.html( node.data.replace(/&nbsp;/g,' '))));
  445. }
  446. if(!node.nextSibling() && frag.lastChild.nodeName == 'BR'){
  447. frag.removeChild(frag.lastChild)
  448. }
  449. });
  450. rng.insertNode(frag).select();
  451. }
  452. return true;
  453. }
  454. });
  455. //方向键的处理
  456. me.addListener('keydown',function(cmd,evt){
  457. var me = this,keyCode = evt.keyCode || evt.which;
  458. if(keyCode == 40){
  459. var rng = me.selection.getRange(),pre,start = rng.startContainer;
  460. if(rng.collapsed && (pre = domUtils.findParentByTagName(rng.startContainer,'pre',true)) && !pre.nextSibling){
  461. var last = pre.lastChild
  462. while(last && last.nodeName == 'BR'){
  463. last = last.previousSibling;
  464. }
  465. if(last === start || rng.startContainer === pre && rng.startOffset == pre.childNodes.length){
  466. me.execCommand('insertparagraph');
  467. domUtils.preventDefault(evt)
  468. }
  469. }
  470. }
  471. });
  472. //trace:3395
  473. me.addListener('delkeydown',function(type,evt){
  474. var rng = this.selection.getRange();
  475. rng.txtToElmBoundary(true);
  476. var start = rng.startContainer;
  477. if(domUtils.isTagNode(start,'pre') && rng.collapsed && domUtils.isStartInblock(rng)){
  478. var p = me.document.createElement('p');
  479. domUtils.fillNode(me.document,p);
  480. start.parentNode.insertBefore(p,start);
  481. domUtils.remove(start);
  482. rng.setStart(p,0).setCursor(false,true);
  483. domUtils.preventDefault(evt);
  484. return true;
  485. }
  486. })
  487. };