index.js 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567
  1. var MagicEditor = {
  2. init : function(){
  3. this.config = {};
  4. var skin = this.getValue('skin');
  5. if(skin){
  6. $('body').addClass('skin-' + skin);
  7. }
  8. this.addedGroups = {};
  9. this.apiId = null;
  10. this.apiList = [];
  11. this.debugSessionId = null;
  12. this.defaultRequestValue = '{\r\n\t"request" : {\r\n\t\t"message" : "Hello MagicAPI!"\r\n\t},\r\n\t"path" : {\r\n\t\t"id" : "123456"\r\n\t},\r\n\t"body" : {\r\n\t\t"id" : "123456"\r\n\t},\r\n\t"header" : {\r\n\t\t"token" : "tokenValue"\r\n\t},\r\n\t"cookie" : {\r\n\t\t"cookieName" : "cookieValue"\r\n\t},\r\n\t"session" : {\r\n\t\t"userId" : "123"\r\n\t}\r\n}';
  13. this.initMTA();
  14. this.loadAPI();
  15. this.initShortKey();
  16. this.initSkin();
  17. this.initLeftToobarContainer();
  18. this.initBottomContainer();
  19. this.initSelect();
  20. this.initContextMenu();
  21. this.initScriptEditor();
  22. this.resetEditor();
  23. this.checkUpdate();
  24. this.backupInterval();
  25. var _this = this;
  26. $.getJSON('config.json',function(data){
  27. _this.config = data;
  28. })
  29. },
  30. initSkin : function(){
  31. var skinSelector = $('.skin-selector');
  32. $('.button-skin').on('click',function(){
  33. skinSelector.toggle();
  34. return false;
  35. });
  36. var $body = $('body');
  37. $body.on('click',function(){
  38. skinSelector.hide();
  39. })
  40. var _this = this;
  41. skinSelector.on('click','li',function(){
  42. skinSelector.hide();
  43. $(this).siblings().each(function(){
  44. $body.removeClass('skin-' + $(this).text())
  45. })
  46. _this.setSkin($(this).text());
  47. })
  48. },
  49. resetEditor : function(){
  50. $('input[name=group]').val('未分组');
  51. $('input[name=method]').val('GET');
  52. $('input[name=name]').val('');
  53. $('input[name=path]').val('');
  54. $('input[name=prefix]').val('');
  55. this.outputJson = null;
  56. this.apiId = null;
  57. this.scriptEditor&&this.scriptEditor.setValue('return message;');
  58. this.requestEditor && this.requestEditor.setValue(this.defaultRequestValue);
  59. this.resultEditor&&this.resultEditor.setValue('');
  60. this.optionsEditor && this.optionsEditor.setValue('{\r\n}');
  61. },
  62. addBreakPoint : function(line){
  63. var model = this.scriptEditor.getModel();
  64. model.deltaDecorations([],[{
  65. range : new monaco.Range(line, 1, line, 1),
  66. options: {
  67. isWholeLine: true,
  68. linesDecorationsClassName: 'breakpoints',
  69. className : 'breakpoint-line',
  70. }
  71. }])
  72. },
  73. removeBreakPoint : function(line){
  74. var model = this.scriptEditor.getModel();
  75. var decorations = [];
  76. if (line !== undefined) {
  77. decorations = model.getLineDecorations(line);
  78. } else {
  79. decorations = model.getAllDecorations();
  80. }
  81. var ids = [];
  82. for (var i=0,len =decorations.length;i<len;i++) {
  83. if (decorations[i].options.linesDecorationsClassName === 'breakpoints') {
  84. ids.push(decorations[i].id)
  85. }
  86. }
  87. model.deltaDecorations(ids, [])
  88. },
  89. hasBreakPoint : function(line){
  90. var decorations = this.scriptEditor.getLineDecorations(line);
  91. for (var i=0,len =decorations.length;i<len;i++) {
  92. if (decorations[i].options.linesDecorationsClassName === 'breakpoints') {
  93. return true;
  94. }
  95. }
  96. },
  97. renderApiList : function(){
  98. var empty = true;
  99. var root = [];
  100. var groups = {};
  101. var apiList = this.apiList;
  102. if(apiList&&apiList.length > 0){
  103. var $groupUL = $('input[name=group]').next();
  104. for(var i=0,len = apiList.length;i<len;i++){
  105. var info = apiList[i];
  106. info.groupName = info.groupName || '未分组';
  107. if(!groups[info.groupName]){
  108. groups[info.groupName] = {
  109. id : info.groupName,
  110. children : [],
  111. spread : true,
  112. groupPrefix : info.groupPrefix,
  113. title : info.groupName
  114. }
  115. if($groupUL.find('[data-name='+$.escapeSelector(info.groupName)+']').length == 0){
  116. $groupUL.append($('<li data-name="'+info.groupName+'" data-prefix="'+(info.groupPrefix || '')+'"/>').append(info.groupName))
  117. }
  118. }
  119. if(info.show!==false){
  120. groups[info.groupName].children.push({
  121. id : info.id,
  122. groupName : info.groupName,
  123. groupPrefix : info.groupPrefix,
  124. name : info.name,
  125. title : '<label style="padding-right: 4px;color:#000">' + info.name + "</label>" + info.path,
  126. path : info.path
  127. });
  128. }
  129. }
  130. }
  131. for(var key in this.addedGroups){
  132. if(!groups[key]){
  133. groups[key] = this.addedGroups[key];
  134. }
  135. }
  136. var $dom = $('.api-list-container').html('');
  137. for(var key in groups){
  138. var group = groups[key];
  139. var $item = $('<div/>').addClass('group-item')
  140. .addClass('opened')
  141. .append($('<div/>').addClass('group-header')
  142. .append('<i class="iconfont icon-arrow-bottom"></i><i class="iconfont icon-list"></i>')
  143. .append($('<label/>').append(key))
  144. .append(group.groupPrefix ? '<span>('+group.groupPrefix+')</span>': '')
  145. );
  146. if(group.children){
  147. var $ul = $('<ul/>').addClass('group-list');
  148. for(var i =0,len = group.children.length;i<len;i++){
  149. var info = group.children[i];
  150. $ul.append($('<li/>').attr('data-id',info.id).append('<i class="iconfont icon-script"></i>')
  151. .append('<label>'+info.name+'</label>')
  152. .append('<span>('+info.path+')</span>'));
  153. }
  154. $item.append($ul);
  155. }
  156. $dom.append($item);
  157. }
  158. },
  159. loadAPI : function(id,isCopy){
  160. var _this = this;
  161. if(id){
  162. this.ajax({
  163. url : 'get',
  164. data : {
  165. id : id
  166. },
  167. success : function(info){
  168. _this.resetEditor();
  169. $('.button-delete').removeClass('disabled');
  170. if(isCopy === true){
  171. $('input[name=name]').val();
  172. $('input[name=path]').val();
  173. MagicEditor.setStatusBar('复制接口:' + info.name + '(' + info.path + ')')
  174. }else{
  175. _this.apiId = id;
  176. $('input[name=name]').val(info.name);
  177. $('input[name=path]').val(info.path);
  178. MagicEditor.setStatusBar('编辑接口:' + info.name + '(' + info.path + ')')
  179. }
  180. $('input[name=method]').val(info.method);
  181. $('input[name=group]').val(info.groupName || '未分组');
  182. $('input[name=prefix]').val(info.groupPrefix || '');
  183. $('.button-run,.button-delete').removeClass('disabled');
  184. _this.scriptEditor && _this.scriptEditor.setValue(info.script);
  185. _this.requestEditor && _this.requestEditor.setValue(info.parameter || _this.defaultRequestValue);
  186. _this.optionsEditor && _this.optionsEditor.setValue(info.option || '{\r\n}');
  187. }
  188. })
  189. }else{
  190. this.ajax({
  191. url : 'list',
  192. success : function(list){
  193. _this.apiList = list;
  194. _this.renderApiList();
  195. }
  196. })
  197. }
  198. },
  199. createNew : function($header){
  200. MagicEditor.createDialog({
  201. title : '新建接口',
  202. content : '新建接口会清空当前编辑器,是否继续?',
  203. buttons : [{
  204. name : '继续',
  205. click : function(){
  206. $('.group-item .group-list li.selected').removeClass('selected');
  207. MagicEditor.resetEditor();
  208. $('.button-delete').addClass('disabled');
  209. if($header){
  210. $('input[name=group]').val($header.find('label').text());
  211. var prefix = $header.find('span').text();
  212. if(prefix){
  213. $('input[name=prefix]').val(prefix.substring(1,prefix.length - 1));
  214. }
  215. }
  216. MagicEditor.report('create_api');
  217. MagicEditor.setStatusBar('创建接口');
  218. }
  219. },{
  220. name : '取消'
  221. }]
  222. })
  223. },
  224. setStatusBar : function(value){
  225. $('.footer-container').html(value);
  226. },
  227. initMTA : function(){
  228. window._mtac = {};
  229. var element = document.createElement("script");
  230. element.src = "//pingjs.qq.com/h5/stats.js?v2.0.4";
  231. element.setAttribute("name", "MTAH5");
  232. element.setAttribute("sid", "500724136");
  233. element.setAttribute("cid", "500724141");
  234. var s = document.getElementsByTagName("script")[0];
  235. s.parentNode.insertBefore(element, s);
  236. var _this = this;
  237. element.onload = element.onreadystatechange = function(){
  238. if(!this.readyState||this.readyState=='loaded'||this.readyState=='complete') {
  239. _this.report('v0_3_4');
  240. }
  241. }
  242. },
  243. // 修改分组
  244. updateGroup : function($header){
  245. var _this = MagicEditor;
  246. var oldGroupName = $header.find('label').text();
  247. var oldPrefix = $header.find('span').text();
  248. oldPrefix = oldPrefix ? oldPrefix.substring(1,oldPrefix.length - 1) : '';
  249. _this.createDialog({
  250. title : '修改分组:' + oldGroupName,
  251. content : '<label>分组名称:</label><input type="text" name="name" value="'+oldGroupName+'" autocomplete="off"/><div style="height:2px;"></div><label>分组前缀:</label><input type="text" value="'+oldPrefix+'" name="prefix" autocomplete="off"/>',
  252. replace : false,
  253. buttons : [{
  254. name : '修改',
  255. click : function($dom){
  256. var groupName = $dom.find('input[name=name]').val();
  257. var groupPrefix = $dom.find('input[name=prefix]').val();
  258. if(!groupName){
  259. $dom.find('input[name=path]').focus();
  260. return false;
  261. }
  262. var exists = false;
  263. $('.group-header').each(function(){
  264. if(this !== $header[0]){
  265. var name = $(this).find('label').text();
  266. if(name == groupName){
  267. exists = true;
  268. return false;
  269. }
  270. }
  271. });
  272. if(groupName.indexOf("'")!= -1 || groupName.indexOf('"') != -1){
  273. _this.alert('创建分组','分组名不能包含特殊字符 \' "');
  274. return false;
  275. }
  276. if(groupPrefix.indexOf("'")!= -1 || groupPrefix.indexOf('"') != -1){
  277. _this.alert('创建分组','分组前缀不能包含特殊字符 \' "');
  278. return false;
  279. }
  280. if(exists){
  281. _this.alert('创建分组','分组已存在!');
  282. return false;
  283. }
  284. _this.report('group_update');
  285. _this.ajax({
  286. url : 'group/update',
  287. data : {
  288. oldGroupName : oldGroupName,
  289. groupName : groupName,
  290. prefix : groupPrefix
  291. },
  292. success : function(){
  293. if(_this.addedGroups[oldGroupName]){
  294. delete _this.addedGroups[oldGroupName]
  295. }
  296. _this.addedGroups[groupName] = {
  297. groupName : groupName,
  298. groupPrefix : groupPrefix
  299. }
  300. var apiList = _this.apiList;
  301. if(apiList&&apiList.length > 0){
  302. for(var i=0,len = apiList.length;i<len;i++){
  303. if(apiList[i].groupName == oldGroupName){
  304. apiList[i].groupName = groupName;
  305. apiList[i].groupPrefix = groupPrefix || '';
  306. }
  307. }
  308. }
  309. var $group = $('input[name=group]');
  310. $group.next().find('li[data-name='+$.escapeSelector(oldGroupName)+']').attr('data-prefix',(groupPrefix || '')).attr('data-name',groupName).html(groupName);
  311. if($group.val() == oldGroupName){
  312. $group.val(groupName);
  313. $('input[name=prefix]').val(groupPrefix);
  314. }
  315. $header.find('label').html(groupName).next().html(groupPrefix ? '('+groupPrefix+')' : '');
  316. _this.renderApiList();
  317. }
  318. })
  319. }
  320. },{
  321. name : '取消'
  322. }]
  323. })
  324. },
  325. // 创建分组
  326. createGroup : function(){
  327. var _this = MagicEditor;
  328. _this.setStatusBar('创建分组..');
  329. MagicEditor.createDialog({
  330. title : '创建分组',
  331. content : '<label>分组名称:</label><input type="text" name="name" autocomplete="off"/><div style="height:2px;"></div><label>分组前缀:</label><input type="text" name="prefix" autocomplete="off"/>',
  332. replace : false,
  333. buttons : [{
  334. name : '创建',
  335. click : function($dom){
  336. var groupName = $dom.find('input[name=name]').val();
  337. var groupPrefix = $dom.find('input[name=prefix]').val();
  338. if(!groupName){
  339. $dom.find('input[name=path]').focus();
  340. return false;
  341. }
  342. if(groupName.indexOf("'")!= -1 || groupName.indexOf('"') != -1){
  343. _this.alert('创建分组','分组名不能包含特殊字符 \' "');
  344. return false;
  345. }
  346. if(groupPrefix.indexOf("'")!= -1 || groupPrefix.indexOf('"') != -1){
  347. _this.alert('创建分组','分组前缀不能包含特殊字符 \' "');
  348. return false;
  349. }
  350. var exists = false;
  351. $('.group-header').each(function(){
  352. var name = $(this).find('label').text();
  353. if(name == groupName){
  354. exists = true;
  355. return false;
  356. }
  357. });
  358. if(exists){
  359. _this.setStatusBar('分组「'+groupName + '」');
  360. _this.alert('创建分组','分组已存在!');
  361. return false;
  362. }
  363. _this.addedGroups[groupName] = {
  364. groupName : groupName,
  365. groupPrefix : groupPrefix
  366. }
  367. _this.report('group_create');
  368. _this.setStatusBar('分组「'+groupName + '」创建成功');
  369. $('input[name=group]').next().append($('<li data-name="'+groupName+'" data-prefix="'+(groupPrefix || '')+'"/>').append(groupName));
  370. _this.renderApiList();
  371. }
  372. },{
  373. name : '取消'
  374. }]
  375. })
  376. },
  377. // 删除分组
  378. deleteGroup : function($header){
  379. var _this = MagicEditor;
  380. var groupName = $header.find('label').text();
  381. _this.setStatusBar('准备删除分组「'+groupName + '」');
  382. _this.createDialog({
  383. title : '删除接口分组',
  384. content : '是否要删除接口分组「'+groupName + '」',
  385. buttons : [{
  386. name : '删除',
  387. click : function(){
  388. _this.report('group_delete');
  389. var ids = [];
  390. $header.next().find('li').each(function(){
  391. ids.push($(this).data('id'));
  392. });
  393. _this.setStatusBar('准备删除接口分组「'+groupName + '」');
  394. delete _this.addedGroups[groupName];
  395. _this.ajax({
  396. url : 'group/delete',
  397. data : {
  398. apiIds : ids.join(','),
  399. groupName : groupName
  400. },
  401. success : function(){
  402. _this.setStatusBar('接口分组「'+groupName + '」已删除');
  403. _this.loadAPI(); //重新加载
  404. }
  405. })
  406. }
  407. },{
  408. name : '取消'
  409. }]
  410. })
  411. },
  412. report : function(eventId){
  413. try{
  414. MtaH5.clickStat(eventId);
  415. }catch(ignored){}
  416. },
  417. deleteApi : function($li){
  418. var text = $li.text();
  419. MagicEditor.createDialog({
  420. title : '删除接口',
  421. content : '是否要删除接口「'+text + '」',
  422. buttons : [{
  423. name : '删除',
  424. click : function(){
  425. MagicEditor.setStatusBar('准备删除接口');
  426. MagicEditor.report('script_delete')
  427. var apiId = $li.data('id');
  428. MagicEditor.ajax({
  429. url : 'delete',
  430. data : {
  431. id : apiId
  432. },
  433. success : function(){
  434. if(MagicEditor.apiId == apiId){
  435. MagicEditor.apiId = null;
  436. }
  437. MagicEditor.setStatusBar('接口「'+text + '」已删除');
  438. MagicEditor.loadAPI(); //重新加载
  439. }
  440. })
  441. }
  442. },{
  443. name : '取消'
  444. }]
  445. })
  446. },
  447. ajax : function(options){
  448. $.ajax({
  449. url : options.url,
  450. async : options.async,
  451. type : 'post',
  452. dataType : 'json',
  453. contentType : options.contentType,
  454. data : options.data,
  455. success : function(json,data,xhr){
  456. if(json.code == 1){
  457. options&&options.success(json.data,json,xhr);
  458. }else{
  459. var val = options.exception&&options.exception(json.code,json.message,json);
  460. if(val !== false){
  461. MagicEditor.alert('Error',json.message);
  462. }
  463. }
  464. },
  465. error : function(){
  466. MagicEditor.setStatusBar('ajax请求失败');
  467. MagicEditor.alert('网络错误','ajax请求失败');
  468. options.error&&options.error();
  469. }
  470. })
  471. },
  472. copyApi : function($li){
  473. var id = $li&&$li.data('id');
  474. id&&MagicEditor.confirm('复制接口','复制接口会清空当前编辑器,是否继续?',function(){
  475. MagicEditor.loadAPI(id,true);
  476. })
  477. },
  478. copyApiPath : function($li){
  479. var _this = MagicEditor;
  480. var path = $li&&$li.find('span').text();
  481. if(_this.config.web&&path){
  482. path = path.substring(1,path.length - 1);
  483. var prefix = $li.parent().prev().find('span').text() || '';
  484. if(prefix){
  485. prefix = prefix.substring(1,prefix.length - 1).replace(/(^\/+)|(\/+$)/g,'');
  486. }
  487. path = prefix + '/' + path.replace(/(^\/+)/g,'');
  488. if(_this.config&&_this.config.prefix){
  489. path = _this.config.prefix.replace(/(^\/+)|(\/+$)/g,'') + '/'+ path;
  490. }
  491. var host = location.href.substring(0,location.href.indexOf(_this.config.web)).replace(/(\/+$)/g,'');
  492. if(_this.config.prefix){
  493. host = host + '/' + _this.config.prefix.replace(/(^\/+)|(\/+$)/g,'');
  494. }
  495. path = host + '/' + path;
  496. try {
  497. var copyText = document.createElement('textarea');
  498. copyText.style = 'position:absolute;left:-99999999px';
  499. document.body.appendChild(copyText);
  500. copyText.innerHTML = path;
  501. copyText.readOnly = false;
  502. copyText.select();
  503. copyText.setSelectionRange(0, copyText.value.length);
  504. document.execCommand("copy");
  505. _this.alert('复制接口路径','复制成功');
  506. } catch (e) {
  507. _this.alert('复制接口路径失败,请手动赋值',path);
  508. }
  509. }
  510. },
  511. resetDebugContent : function(){
  512. $('.bottom-item-body table tbody').html('<tr><td colspan="3" align="center">no message.</td></tr>');
  513. },
  514. doContinue : function(step){
  515. if($('.button-continue').hasClass('disabled')){
  516. return;
  517. }
  518. if(this.debugSessionId){
  519. MagicEditor.resetDebugContent();
  520. $('.button-continue,.button-step-over').addClass('disabled');
  521. var _this = this;
  522. this.ajax({
  523. url : 'continue',
  524. data : {
  525. id : this.debugSessionId,
  526. breakpoints : _this.getBreakPoints().join(','),
  527. step : step ? '1' : '0'
  528. },
  529. success : function(data,json,xhr){
  530. _this.convertResult(json.code,json.message,json,xhr);
  531. },
  532. exception : function(code,message,json){
  533. return _this.convertResult(code,message,json);
  534. },
  535. error : function(){
  536. $('.button-run').removeClass('disabled');
  537. }
  538. })
  539. }
  540. },
  541. paddingZero : function(val){
  542. if(val < 10){
  543. return '0' + val;
  544. }
  545. return val.toString();
  546. },
  547. getTimeStr : function(date){
  548. var month = date.getMonth() + 1;
  549. var day = date.getDate();
  550. var hour = date.getHours();
  551. var minute = date.getMinutes();
  552. var seconds = date.getSeconds();
  553. return date.getFullYear() + '-' + this.paddingZero(month) + '-' + this.paddingZero(day) + ' ' + this.paddingZero(hour) + ':' + this.paddingZero(minute) + ':'+this.paddingZero(seconds);
  554. },
  555. appendLog : function(level,message,throwable){
  556. var $div = $('<div class="output-log-line level-'+level+'"/>')
  557. $div.append($('<div class="timestamp"/>').append(this.getTimeStr(new Date())));
  558. $div.append($('<div class="level"/>').append(level.toUpperCase()));
  559. var messages = message.replace(/ /g,'&nbsp;').replace(/\t/g,'&nbsp;&nbsp;&nbsp;&nbsp;').split('\n');
  560. $div.append($('<div class="message"/>').append(messages[0]));
  561. if(messages.length > 1){
  562. for(var i=1;i<messages.length;i++){
  563. $div.append($('<div class="message-line level-'+level+'" />').append(messages[i]));
  564. }
  565. }
  566. if(throwable){
  567. messages = throwable.replace(/ /g,'&nbsp;').replace(/\t/g,'&nbsp;&nbsp;&nbsp;&nbsp;').split('\n');
  568. for(var i=0;i<messages.length;i++){
  569. $div.append($('<div class="message-line level-'+level+'" />').append(messages[i]));
  570. }
  571. }
  572. if(!this.$output){
  573. this.$output = $('.bottom-container .bottom-item-body.output');
  574. }
  575. this.$output.append($div);
  576. this.$output.scrollTop(this.$output[0].scrollHeight);
  577. },
  578. createConsole : function(callback){
  579. var source = new EventSource('console');
  580. var _this = this;
  581. source.onerror = function(){
  582. source.close();
  583. }
  584. source.addEventListener('create',function(e){
  585. _this.navigateTo(4);
  586. callback&&callback(e.data);
  587. })
  588. source.addEventListener('close',function(e){
  589. source.close();
  590. })
  591. source.addEventListener('log',function(e){
  592. var data = JSON.parse(e.data);
  593. _this.appendLog(data.level,data.message,data.throwable);
  594. })
  595. },
  596. getBreakPoints : function(){
  597. var decorations = MagicEditor.scriptEditor.getModel().getAllDecorations();
  598. var breakpoints = [];
  599. for (var i=0,len =decorations.length;i<len;i++) {
  600. if (decorations[i].options.linesDecorationsClassName === 'breakpoints') {
  601. breakpoints.push(decorations[i].range.startLineNumber);
  602. }
  603. }
  604. return breakpoints;
  605. },
  606. doTest : function(){
  607. var _this = this;
  608. if($('.button-run').hasClass('disabled')){
  609. return;
  610. }
  611. var request = _this.requestEditor.getValue();
  612. try{
  613. request = JSON.parse(request);
  614. if(typeof request != 'object'){
  615. _this.setStatusBar('请求参数有误!');
  616. _this.alert('运行测试','请求参数有误!');
  617. return;
  618. }
  619. }catch(e){
  620. _this.setStatusBar('请求参数有误!');
  621. _this.alert('运行测试','请求参数有误!');
  622. return;
  623. }
  624. var options = _this.optionsEditor.getValue();
  625. try{
  626. options = JSON.parse(options);
  627. if(typeof options != 'object'){
  628. _this.setStatusBar('接口选项有误!');
  629. _this.alert('运行测试','接口选项有误!');
  630. return;
  631. }
  632. }catch(e){
  633. _this.setStatusBar('接口选项有误!');
  634. _this.alert('运行测试','接口选项有误!');
  635. return;
  636. }
  637. _this.setStatusBar('开始测试...');
  638. _this.createConsole(function(sessionId){
  639. _this.report('run');
  640. request.script = _this.scriptEditor.getValue();
  641. var breakpoints = _this.getBreakPoints();
  642. request.breakpoints = breakpoints;
  643. request.sessionId = sessionId;
  644. request.options = options;
  645. _this.resetDebugContent();
  646. $('.button-run').addClass('disabled');
  647. $('.button-continue,.button-step-over').addClass('disabled');
  648. _this.ajax({
  649. url : 'test',
  650. data : JSON.stringify(request),
  651. contentType : 'application/json;charset=utf-8',
  652. success : function(data,json,xhr){
  653. _this.convertResult(json.code,json.message,json,xhr);
  654. },
  655. exception : function(code,message,json){
  656. return _this.convertResult(code,message,json);
  657. },
  658. error : function(){
  659. $('.button-run').removeClass('disabled');
  660. }
  661. })
  662. });
  663. },
  664. doSave : function(){
  665. if($('.button-save').hasClass('disabled')){
  666. return;
  667. }
  668. $('.button-save').addClass('disabled');
  669. var name = $('input[name=name]').val();
  670. var path = $('input[name=path]').val();
  671. var method = $('input[name=method]').val();
  672. var groupName = $('input[name=group]').val();
  673. var groupPrefix = $('input[name=prefix]').val();
  674. this.setStatusBar('准备保存接口:' + name + "(" + path + ")");
  675. var _this = this;
  676. this.ajax({
  677. url : 'save',
  678. data : {
  679. script : this.scriptEditor.getValue(),
  680. path : path,
  681. method : method,
  682. id : this.apiId,
  683. groupName : groupName,
  684. groupPrefix : groupPrefix,
  685. parameter: this.requestEditor.getValue(),
  686. option: this.optionsEditor.getValue(),
  687. name : name,
  688. output : this.outputJson
  689. },
  690. async : false,
  691. exception : function(){
  692. $('.button-save').removeClass('disabled');
  693. },
  694. error : function(){
  695. $('.button-save').removeClass('disabled');
  696. },
  697. success : function(id){
  698. $('.button-save,.button-delete').removeClass('disabled');
  699. if(_this.apiId){
  700. _this.report('script_save');
  701. for(var i=0,len = _this.apiList.length;i<len;i++){
  702. if(_this.apiList[i].id == _this.apiId){
  703. _this.apiList[i].name = name;
  704. _this.apiList[i].path = path;
  705. _this.apiList[i].method = method;
  706. _this.apiList[i].groupName = groupName;
  707. break;
  708. }
  709. }
  710. }else{
  711. _this.report('script_add');
  712. _this.apiId = id;
  713. _this.apiList.unshift({
  714. id : id,
  715. name : name,
  716. path : path,
  717. method : method,
  718. groupName : groupName || '未分组',
  719. })
  720. }
  721. _this.setStatusBar('保存成功!');
  722. _this.loadAPI();
  723. }
  724. })
  725. },
  726. convertResult : function(code,message,json,xhr){
  727. this.debugSessionId = null;
  728. this.resetDebugContent();
  729. this.debugDecorations&&this.scriptEditor&&this.scriptEditor.deltaDecorations(this.debugDecorations,[]);
  730. this.debugDecorations = null;
  731. var _this = this;
  732. var ret = undefined;
  733. if(code === -1000){
  734. MagicEditor.setStatusBar('脚本执行出错..');
  735. MagicEditor.report('script_error');
  736. $(".button-run").removeClass('disabled');
  737. $('.button-continue,.button-step-over').addClass('disabled');
  738. this.navigateTo(2);
  739. if (json.body) {
  740. var line = json.body;
  741. var range = new monaco.Range(line[0], line[2], line[1], line[3] + 1);
  742. var decorations = this.scriptEditor&&this.scriptEditor.deltaDecorations([],[{
  743. range: range,
  744. options : {
  745. hoverMessage : {
  746. value : message
  747. },
  748. inlineClassName : 'squiggly-error',
  749. }
  750. }])
  751. this.scriptEditor.revealRangeInCenter(range);
  752. this.scriptEditor.focus();
  753. setTimeout(function(){
  754. _this.scriptEditor&&_this.scriptEditor.deltaDecorations(decorations,[])
  755. },10000)
  756. }
  757. ret = false;
  758. }else if(code === 1000){ // debug断点
  759. $(".button-run").addClass('disabled');
  760. $('.button-continue,.button-step-over').removeClass('disabled');
  761. this.navigateTo(3);
  762. this.debugIn(message, json.body);
  763. return false;
  764. }
  765. MagicEditor.setStatusBar('脚本执行完毕');
  766. $(".button-run").removeClass('disabled');
  767. $('.button-continue,.button-step-over').addClass('disabled');
  768. this.navigateTo(2)
  769. var outputJson;
  770. var contentType = xhr&&xhr.getResponseHeader('ma-content-type');
  771. if(contentType == 'application/octet-stream'){ //文件下载
  772. var disposition = xhr.getResponseHeader('ma-content-disposition');
  773. var filename = 'output';
  774. if(disposition){
  775. filename = decodeURIComponent(disposition.substring(disposition.indexOf('filename=') + 9));
  776. }
  777. outputJson = this.formatJson({
  778. filename : filename
  779. });
  780. var a = document.createElement("a");
  781. a.download = filename;
  782. var bstr = atob(json.data);
  783. var n = bstr.length;
  784. var u8arr = new Uint8Array(n);
  785. while (n--) {
  786. u8arr[n] = bstr.charCodeAt(n);
  787. }
  788. a.href = window.URL.createObjectURL(new Blob([u8arr]));
  789. a.click();
  790. MagicEditor.report('output_blob');
  791. }else if(contentType && contentType.indexOf('image') == 0){ //image开头
  792. outputJson = this.formatJson(json.data);
  793. this.createDialog({
  794. title : '图片结果',
  795. content : '<p align="center"><img src="data:'+contentType+';base64,'+json.data+'"></p>',
  796. replace : false,
  797. buttons : [{name : 'OK'}]
  798. })
  799. MagicEditor.report('output_image');
  800. }else{
  801. outputJson = this.formatJson(json.data);
  802. }
  803. this.outputJson = outputJson;
  804. this.resultEditor.setValue(outputJson);
  805. return ret;
  806. },
  807. debugIn : function(id,data){
  808. MagicEditor.setStatusBar('进入断点...');
  809. MagicEditor.report('debug_in');
  810. this.debugSessionId = id;
  811. if(data.variables.length > 0){
  812. var $tbody = $('.bottom-item-body table tbody').html('');
  813. for(var i =0,len = data.variables.length;i<len;i++){
  814. var item = data.variables[i];
  815. var $tr = $('<tr/>');
  816. $tr.append($('<td/>').html(item.name))
  817. $tr.append($('<td/>').html(item.value))
  818. $tr.append($('<td/>').html(item.type))
  819. $tbody.append($tr);
  820. }
  821. }else{
  822. this.resetDebugContent();
  823. }
  824. this.debugDecorations = [this.scriptEditor&&this.scriptEditor.deltaDecorations([],[{
  825. range : new monaco.Range(data.range[0],1,data.range[0],1),
  826. options: {
  827. isWholeLine: true,
  828. inlineClassName : 'debug-line',
  829. className : 'debug-line',
  830. }
  831. }])];
  832. },
  833. backupInterval : function(){
  834. var _this = this;
  835. var info = _this.getValue('api_info');
  836. if(info){
  837. info = JSON.parse(info);
  838. _this.apiId = info.id;
  839. $('input[name=name]').val(info.name || '');
  840. $('input[name=path]').val(info.path || '');
  841. $('input[name=method]').val(info.method || '');
  842. $('input[name=group]').val(info.groupName || '');
  843. $('input[name=prefix]').val(info.groupPrefix || '');
  844. _this.scriptEditor&&_this.scriptEditor.setValue(info.script || 'return message;');
  845. _this.requestEditor&&_this.requestEditor.setValue(info.parameters || _this.defaultRequestValue);
  846. _this.options&&_this.options.setValue(info.options || '{\r\n}');
  847. _this.output&&_this.output.setValue(info.options || '');
  848. }
  849. setInterval(function(){
  850. _this.setValue('api_info',{
  851. id : _this.apiId,
  852. name : $('input[name=name]').val(),
  853. path : $('input[name=path]').val(),
  854. method : $('input[name=method]').val(),
  855. groupName : $('input[name=group]').val(),
  856. groupPrefix : $('input[name=prefix]').val(),
  857. script : _this.scriptEditor&&_this.scriptEditor.getValue(),
  858. parameters : _this.requestEditor&&_this.requestEditor.getValue(),
  859. options : _this.optionsEditor&&_this.optionsEditor.getValue(),
  860. output: _this.outputEditor&&_this.outputEditor.getValue()
  861. })
  862. },5000)
  863. },
  864. // 初始化快捷键
  865. initShortKey : function(){
  866. var _this = this;
  867. $('body').on('keydown',function(e){
  868. if(e.keyCode == 119){ //F8
  869. _this.doContinue();
  870. e.preventDefault();
  871. }else if(e.keyCode == 117){ //F6
  872. _this.doContinue(true);
  873. e.preventDefault();
  874. }else if(e.keyCode == 81 && (e.metaKey || e.ctrlKey)){ //Ctrl + Q
  875. _this.doTest();
  876. e.preventDefault();
  877. }else if(e.keyCode == 83 && (e.metaKey || e.ctrlKey)){ //Ctrl + S
  878. _this.doSave();
  879. e.preventDefault();
  880. }else if(e.keyCode == 78 && e.altKey){ //Alt + N
  881. _this.createNew();
  882. e.preventDefault();
  883. }else if(e.keyCode == 71 && e.altKey){ //Alt + G
  884. _this.createGroup();
  885. e.preventDefault();
  886. }else if(e.keyCode == 27 || e.keyCode == 13){ //Enter or Esc
  887. $('.dialog-wrapper').remove();
  888. }
  889. })
  890. },
  891. //检测更新
  892. checkUpdate : function(){
  893. var _this = this;
  894. var ignoreVersion = this.getValue('ignore-version');
  895. $.ajax({
  896. url : 'https://img.shields.io/maven-central/v/org.ssssssss/magic-api.json',
  897. dataType : 'json',
  898. success : function(data){
  899. if(data.value != 'v0.3.4'){
  900. if(ignoreVersion != data.value){
  901. _this.createDialog({
  902. title : '更新提示',
  903. content : '检测到已有新版本'+data.value+',是否更新?',
  904. buttons : [{
  905. name : '更新日志',
  906. click : function(){
  907. _this.setValue('ignore-version',data.value)
  908. window.open('http://www.ssssssss.org/changelog.html')
  909. }
  910. },{
  911. name : '残忍拒绝',
  912. click : function(){
  913. _this.setValue('ignore-version',data.value)
  914. }
  915. }]
  916. })
  917. }
  918. MagicEditor.setStatusBar('版本检测完毕,最新版本为:' + data.value+',建议更新!!');
  919. }else{
  920. MagicEditor.setStatusBar('版本检测完毕,当前已是最新版');
  921. }
  922. },
  923. error : function(){
  924. MagicEditor.setStatusBar('版本检测失败');
  925. }
  926. })
  927. },
  928. alert : function(title,content){
  929. this.createDialog({
  930. title : title,
  931. content : content,
  932. buttons : [{name : 'OK'}]
  933. });
  934. },
  935. confirm : function(title,content,callback){
  936. this.createDialog({
  937. title : title,
  938. content : content,
  939. buttons : [{name : '确定',click : function(){callback&&callback();}},{name : '取消'}]
  940. });
  941. },
  942. doShowHistory : function(){
  943. if(!this.apiId){
  944. this.alert('历史记录','请选择接口后在查看历史记录');
  945. return;
  946. }
  947. var _this = this;
  948. var apiId = this.apiId;
  949. var name = $('input[name=name]').val();
  950. var scriptModel = monaco.editor.createModel(this.scriptEditor.getValue(),'magicscript');
  951. _this.report('history_view');
  952. this.ajax({
  953. url : 'backups',
  954. data : {
  955. id : apiId
  956. },
  957. success : function(timestamps){
  958. if(timestamps.length == 0){
  959. _this.alert('历史记录','暂无历史记录信息');
  960. return;
  961. }
  962. var $ul = $('<ul class="not-select"/>')
  963. for(var i=0,len = timestamps.length;i<len;i++){
  964. var timestamp = timestamps[i];
  965. var timeStr = _this.getTimeStr(new Date(timestamp));
  966. $ul.append($('<li/>').attr('data-timestamp',timestamp).attr('data-id',apiId).append(timeStr))
  967. }
  968. var html = $ul[0].outerHTML;
  969. html+= '<div class="version"><span class="version-time"></span><span class="current">当前版本</span></div>'
  970. html += '<div class="diff-editor"></div>';
  971. _this.setStatusBar('查看历史记录:' + (name || ''));
  972. _this.createDialog({
  973. title : '历史记录:' + (name || ''),
  974. content : html,
  975. replace : false,
  976. className : 'history-list',
  977. buttons : [{
  978. name : '恢复',
  979. click : function(){
  980. _this.scriptEditor.setValue(scriptModel.getValue());
  981. _this.report('history_revert');
  982. _this.setStatusBar('恢复历史记录:' + (name || ''));
  983. }
  984. },{
  985. name : '取消'
  986. }],
  987. close : function(){
  988. _this.diffEditor = null;
  989. },
  990. onCreate : function($dom){
  991. _this.diffEditor = monaco.editor.createDiffEditor($dom.find('.diff-editor')[0], {
  992. enableSplitViewResizing: false,
  993. minimap : {
  994. enabled : false
  995. },
  996. folding : false,
  997. lineDecorationsWidth : 20,
  998. fixedOverflowWidgets :false
  999. });
  1000. _this.diffEditor.setModel({
  1001. original : scriptModel,
  1002. modified : scriptModel
  1003. });
  1004. var $version = $dom.find('.version-time');
  1005. $dom.on('click','ul li[data-timestamp]',function(){
  1006. $(this).addClass('selected').siblings().removeClass('selected');
  1007. var timestamp = $(this).data('timestamp');
  1008. $version.html($(this).text());
  1009. _this.ajax({
  1010. url : 'backup/get',
  1011. data : {
  1012. id : apiId,
  1013. timestamp : timestamp
  1014. },
  1015. success : function(info){
  1016. _this.diffEditor.setModel({
  1017. original : monaco.editor.createModel(info.script,'magicscript'),
  1018. modified : scriptModel
  1019. });
  1020. }
  1021. })
  1022. })
  1023. }
  1024. })
  1025. }
  1026. })
  1027. },
  1028. //初始化右键菜单
  1029. initContextMenu : function(){
  1030. var _this = this;
  1031. $('.api-list-container').on('contextmenu','.group-header',function(e){
  1032. _this.createContextMenu([{
  1033. name : '新建接口',
  1034. shortKey : 'Alt+N',
  1035. click : _this.createNew
  1036. },{
  1037. name : '刷新接口',
  1038. shortKey : '',
  1039. click : function (){_this.loadAPI()}
  1040. },{
  1041. name : '删除组',
  1042. shortKey : '',
  1043. click : _this.deleteGroup
  1044. },{
  1045. name : '新建分组',
  1046. shortKey : 'Alt+G',
  1047. click : _this.createGroup
  1048. },{
  1049. name : '修改分组',
  1050. shortKey : '',
  1051. click : _this.updateGroup
  1052. }],e.pageX,e.pageY,$(this));
  1053. return false;
  1054. }).on('contextmenu','.group-list li',function(e){
  1055. var $li = $(this);
  1056. _this.createContextMenu([{
  1057. name : '复制接口',
  1058. shortKey : '',
  1059. click : _this.copyApi,
  1060. },{
  1061. name : '复制路径',
  1062. shortKey : '',
  1063. click : _this.copyApiPath
  1064. },{
  1065. name : '刷新接口',
  1066. shortKey : '',
  1067. click : function (){_this.loadAPI()}
  1068. },{
  1069. name : '移动',
  1070. shortKey : 'Ctrl+M',
  1071. click : function(){
  1072. _this.alert('移动接口','功能暂未实现!');
  1073. }
  1074. },{
  1075. name : '删除接口',
  1076. shortKey : '',
  1077. click : _this.deleteApi
  1078. },{
  1079. name : '新建分组',
  1080. shortKey : 'Alt+G',
  1081. click : _this.createGroup
  1082. }],e.pageX,e.pageY,$li)
  1083. return false;
  1084. }).on('contextmenu',function(e){
  1085. _this.createContextMenu([{
  1086. name : '新建分组',
  1087. shortKey : 'Alt+G',
  1088. click : _this.createGroup
  1089. }],e.pageX,e.pageY,$(this));
  1090. return false;
  1091. })
  1092. },
  1093. initSelect : function(){
  1094. var _this = this;
  1095. $('body').on('click','.select',function(){
  1096. $('.select ul').hide();
  1097. $(this).find('ul').show();
  1098. return false;
  1099. }).on('click','.select ul li',function(){
  1100. var $this = $(this);
  1101. var prefix = $this.data('prefix');
  1102. if(prefix !== undefined){
  1103. $('input[name=prefix]').val(prefix || '');
  1104. }
  1105. $this.parent().hide().parent().find('input').val($this.text());
  1106. $this.addClass('selected').siblings().removeClass('selected');
  1107. return false;
  1108. }).on('click',function(){
  1109. $('.select ul').hide();
  1110. }).on('click','.api-list-container ul li',function(){
  1111. $('.api-list-container ul li.selected').removeClass('selected');
  1112. _this.loadAPI($(this).addClass('selected').data('id'))
  1113. }).on('click','.button-run',function(){
  1114. _this.doTest();
  1115. }).on('click','.button-history',function(){
  1116. _this.doShowHistory();
  1117. }).on('click','.button-delete',function(){
  1118. if($(this).hasClass('disabled')){
  1119. return;
  1120. }
  1121. if(_this.apiId){
  1122. var $li = $('.group-list li[data-id='+_this.apiId+']');
  1123. if($li.length > 0){
  1124. _this.deleteApi($li);
  1125. }
  1126. }
  1127. }).on('click','.button-save',function(){
  1128. _this.doSave();
  1129. }).on('click','.button-continue',function(){
  1130. _this.doContinue();
  1131. }).on('click','.button-step-over',function(){
  1132. _this.doContinue(true);
  1133. }).on('click','.button-gitee',function(){
  1134. MagicEditor.report('button-gitee');
  1135. window.open('https://gitee.com/ssssssss-team/magic-api');
  1136. }).on('click','.button-github',function(){
  1137. MagicEditor.report('button-github');
  1138. window.open('https://github.com/ssssssss-team/magic-api')
  1139. }).on('click','.button-qq',function(){
  1140. window.open('https://shang.qq.com/wpa/qunwpa?idkey=10faa4cf9743e0aa379a72f2ad12a9e576c81462742143c8f3391b52e8c3ed8d')
  1141. }).on('click','.button-help',function(){
  1142. MagicEditor.report('button-help');
  1143. window.open('https://ssssssss.org')
  1144. });
  1145. },
  1146. getValue : function(key){
  1147. return localStorage&&localStorage.getItem(key) || '';
  1148. },
  1149. setValue : function(key,value){
  1150. if(Array.isArray(value) || typeof value == 'object'){
  1151. value = JSON.stringify(value);
  1152. }
  1153. localStorage&&localStorage.setItem(key,value) || '';
  1154. },
  1155. removeValue : function(key){
  1156. localStorage&&localStorage.removeItem(key);
  1157. },
  1158. bindEditorShortKey : function(editor){
  1159. // Alt + / 代码提示
  1160. editor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.US_SLASH,function(){
  1161. editor.trigger(null, 'editor.action.triggerSuggest', {})
  1162. },'!findWidgetVisible && !inreferenceSearchEditor && !editorHasSelection');
  1163. // Ctrl + Shift + U 转大写
  1164. editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KEY_U,function(){
  1165. editor.trigger(null, 'editor.action.transformToUppercase', {})
  1166. });
  1167. // Ctrl + Shift + X 转小写
  1168. editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KEY_X,function(){
  1169. editor.trigger(null, 'editor.action.transformToLowercase', {})
  1170. });
  1171. // Ctrl + Alt + L 代码格式化
  1172. editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Alt | monaco.KeyCode.KEY_L,function(){
  1173. editor.trigger(null, 'editor.action.formatDocument', {})
  1174. },'editorHasDocumentFormattingProvider && editorTextFocus && !editorReadonly');
  1175. // Ctrl + Alt + L 选中代码格式化
  1176. editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Alt | monaco.KeyCode.KEY_L,function(){
  1177. editor.trigger(null, 'editor.action.formatSelection', {})
  1178. },'editorHasDocumentFormattingProvider && editorHasSelection && editorTextFocus && !editorReadonly');
  1179. },
  1180. // 初始化脚本编辑器
  1181. initScriptEditor : function(){
  1182. this.ajax({
  1183. url: 'classes',
  1184. async : false,
  1185. success: function (data) {
  1186. data = data || {};
  1187. Parser.scriptClass = data.classes || {};
  1188. Parser.extensions = data.extensions || {};
  1189. }
  1190. })
  1191. $.get('classes.txt',function(txt){
  1192. Parser.importClass = txt.split('\r\n');
  1193. })
  1194. monaco.editor.defineTheme('default', {
  1195. base: 'vs',
  1196. inherit: true,
  1197. rules: [
  1198. { background: '#ffffff' },
  1199. { token: 'keywords', foreground: '000080',fontStyle : 'bold'},
  1200. { token: 'number', foreground: '0000FF' },
  1201. { token: 'keyword', foreground: '000080',fontStyle : 'bold'},
  1202. { token: 'string.sql', foreground: '000000'},
  1203. { token: 'predefined.sql', foreground: '000000'},
  1204. { token: 'operator.sql', foreground: '000080',fontStyle : 'bold'},
  1205. { token: 'key', foreground: '660E7A' },
  1206. { token: 'string.key.json', foreground: '660E7A' },
  1207. { token: 'string.value.json', foreground: '008000' },
  1208. { token: 'keyword.json', foreground: '0000FF' },
  1209. { token: 'string', foreground: '008000',fontStyle : 'bold' },
  1210. { token: 'string.invalid', foreground: '008000' ,background : 'FFCCCC'},
  1211. { token: 'string.escape.invalid', foreground: '008000' ,background : 'FFCCCC'},
  1212. { token: 'string.escape', foreground: '000080',fontStyle : 'bold'},
  1213. { token: 'comment', foreground: '808080'},
  1214. { token: 'comment.doc', foreground: '808080'},
  1215. { token: 'string.escape', foreground: '000080'}
  1216. ],
  1217. colors: {
  1218. 'editor.foreground': '#000000',
  1219. 'editor.background': '#ffffff',
  1220. // 'editor.lineHighlightBorder' : '#00000000',
  1221. 'editorLineNumber.foreground': '#999999', //行号的颜色
  1222. 'editorGutter.background' : '#f0f0f0', //行号背景色
  1223. 'editor.lineHighlightBackground' : '#FFFAE3', //光标所在行的颜色
  1224. 'dropdown.background' : '#F2F2F2', //右键菜单
  1225. 'dropdown.foreground' : '#000000', //右键菜单文字颜色
  1226. 'list.activeSelectionBackground': '#1A7DC4', //右键菜单悬浮背景色
  1227. 'list.activeSelectionForeground' : '#ffffff', //右键菜单悬浮文字颜色
  1228. }
  1229. });
  1230. monaco.editor.defineTheme('dark', {
  1231. base: 'vs-dark',
  1232. inherit: true,
  1233. rules: [
  1234. { foreground: 'A9B7C6' },
  1235. { token: 'keywords', foreground: 'CC7832',fontStyle : 'bold'},
  1236. { token: 'keyword', foreground: 'CC7832',fontStyle : 'bold'},
  1237. { token: 'number', foreground: '6897BB' },
  1238. { token: 'string', foreground: '6A8759',fontStyle : 'bold' },
  1239. { token: 'string.sql', foreground: 'A9B7C6'},
  1240. { token: 'predefined.sql', foreground: 'A9B7C6'},
  1241. { token: 'key', foreground: '9876AA' },
  1242. { token: 'string.key.json', foreground: '9876AA' },
  1243. { token: 'string.value.json', foreground: '6A8759' },
  1244. { token: 'keyword.json', foreground: '6897BB' },
  1245. { token: 'operator.sql', foreground: 'CC7832',fontStyle : 'bold'},
  1246. { token: 'string.invalid', foreground: '008000' ,background : 'FFCCCC'},
  1247. { token: 'string.escape.invalid', foreground: '008000' ,background : 'FFCCCC'},
  1248. { token: 'string.escape', foreground: '000080',fontStyle : 'bold'},
  1249. { token: 'comment', foreground: '808080'},
  1250. { token: 'comment.doc', foreground: '629755'},
  1251. { token: 'string.escape', foreground: 'CC7832'}
  1252. ],
  1253. colors: {
  1254. 'editor.background': '#2B2B2B',
  1255. // 'editor.lineHighlightBorder' : '#00000000',
  1256. 'editorLineNumber.foreground': '#999999', //行号的颜色
  1257. 'editorGutter.background' : '#313335', //行号背景色
  1258. 'editor.lineHighlightBackground' : '#323232', //光标所在行的颜色
  1259. 'dropdown.background' : '#3C3F41', //右键菜单
  1260. 'dropdown.foreground' : '#BBBBBB', //右键菜单文字颜色
  1261. 'list.activeSelectionBackground': '#4B6EAF', //右键菜单悬浮背景色
  1262. 'list.activeSelectionForeground' : '#FFFFFF', //右键菜单悬浮文字颜色
  1263. }
  1264. });
  1265. var theme = this.getValue('skin') || 'default';
  1266. this.report('theme_' + theme);
  1267. this.scriptEditor = monaco.editor.create($('.editor-container')[0], {
  1268. minimap : {
  1269. enabled : false
  1270. },
  1271. language: 'magicscript',
  1272. folding : false,
  1273. lineDecorationsWidth : 35,
  1274. theme : theme,
  1275. })
  1276. this.requestEditor = monaco.editor.create($('.request-editor')[0], {
  1277. value: "{}",
  1278. minimap : {
  1279. enabled : false
  1280. },
  1281. language: 'json',
  1282. folding : false,
  1283. fixedOverflowWidgets :true,
  1284. theme : theme
  1285. })
  1286. this.optionsEditor = monaco.editor.create($('.options-editor')[0], {
  1287. value: "{}",
  1288. minimap : {
  1289. enabled : false
  1290. },
  1291. language: 'json',
  1292. folding : false,
  1293. fixedOverflowWidgets :true,
  1294. theme : theme
  1295. })
  1296. this.resultEditor = monaco.editor.create($('.result-editor')[0], {
  1297. value: "{}",
  1298. minimap : {
  1299. enabled : false
  1300. },
  1301. language: 'json',
  1302. folding : false,
  1303. readOnly : true,
  1304. fixedOverflowWidgets : true,
  1305. theme : theme
  1306. })
  1307. var _this = this;
  1308. this.scriptEditor.onMouseDown(function(e){
  1309. if (e.target.detail && e.target.detail.offsetX && e.target.detail.offsetX >= 0 && e.target.detail.offsetX <= 60) {
  1310. var line = e.target.position.lineNumber;
  1311. if (_this.scriptEditor.getModel().getLineContent(line).trim() === '') {
  1312. return
  1313. }
  1314. if(_this.hasBreakPoint(line)){
  1315. _this.removeBreakPoint(line);
  1316. }else{
  1317. _this.addBreakPoint(line);
  1318. }
  1319. }
  1320. });
  1321. this.bindEditorShortKey(this.scriptEditor);
  1322. this.bindEditorShortKey(this.requestEditor);
  1323. this.bindEditorShortKey(this.optionsEditor);
  1324. },
  1325. navigateTo : function(index){
  1326. var $parent = $('.bottom-container');
  1327. var $dom = $parent.find('.bottom-content-container').show();
  1328. $parent.find('.bottom-tab li').eq(index).addClass('selected').siblings().removeClass('selected');
  1329. $dom.find('.bottom-content-item').eq(index).show().siblings('.bottom-content-item').hide();
  1330. this.layout();
  1331. },
  1332. createDialog : function(options){
  1333. options = options || {};
  1334. var $dialog = $('<div/>').addClass('dialog');
  1335. if(options.className){
  1336. $dialog.addClass(options.className);
  1337. }
  1338. var $header = $('<div/>').addClass('dialog-header').addClass('not-select').append(options.title || '');
  1339. var $close = $('<span/>').append('<i class="iconfont icon-close"></i>');
  1340. $header.append($close);
  1341. $close.on('click',function(){
  1342. options.close&&options.close();
  1343. $wrapper.remove();
  1344. })
  1345. $dialog.append($header);
  1346. var content = options.content || '';
  1347. if(options.replace !== false){
  1348. content = content.replace(/\n/g,'<br>').replace(/ /g,'&nbsp;').replace(/\t/g,'&nbsp;&nbsp;&nbsp;&nbsp;');
  1349. }
  1350. $dialog.append('<div class="dialog-content">' + content + '</div>');
  1351. var buttons = options.buttons || [];
  1352. var $buttons = $('<div/>').addClass('dialog-buttons').addClass('not-select');
  1353. if(buttons.length > 1){
  1354. $buttons.addClass('button-align-right');
  1355. }
  1356. for(var i=0,len = buttons.length;i<len;i++){
  1357. var button = buttons[i];
  1358. $buttons.append($('<button/>').html(button.name || '').addClass(button.className || '').addClass(i == 0 ? 'active' : ''));
  1359. }
  1360. $dialog.append($buttons);
  1361. var $wrapper = $('<div/>').addClass('dialog-wrapper').append($dialog);
  1362. $buttons.on('click','button',function(){
  1363. var index = $(this).index();
  1364. if(buttons[index].click&&buttons[index].click($dialog) === false){
  1365. return;
  1366. }
  1367. options.close&&options.close();
  1368. $wrapper.remove();
  1369. })
  1370. $('body').append($wrapper);
  1371. options.onCreate&&options.onCreate($wrapper);
  1372. },
  1373. createContextMenu : function(menus,left,top,$dom){
  1374. $('.context-menu').remove();
  1375. var $ul = $('<ul/>').addClass('context-menu').addClass('not-select');
  1376. for(var i=0,len = menus.length;i<len;i++){
  1377. var menu = menus[i];
  1378. $ul.append($('<li/>').append('<label>'+menu.name+'</label>').append('<span>'+(menu.shortKey || '')+'<span>'));
  1379. }
  1380. $ul.on('click','li',function(){
  1381. var menu = menus[$(this).index()]
  1382. menu&&menu.click&&menu.click($dom);
  1383. });
  1384. $ul.css({
  1385. left : left + 'px',
  1386. top : top + 'px'
  1387. })
  1388. $('body').append($ul).on('click',function(){
  1389. $ul.remove();
  1390. });
  1391. },
  1392. // 初始化左侧工具条
  1393. initLeftToobarContainer : function(){
  1394. var $apiContainr = $('.api-list-container');
  1395. var value = this.getValue('left-toolbar-width');
  1396. if(value && !isNaN(Number(value))){
  1397. $apiContainr.width(value);
  1398. }
  1399. if('false' == this.getValue('left-toolbar-show')){
  1400. $('.left-toolbar-container li').removeClass('selected');
  1401. $apiContainr.hide();
  1402. }
  1403. var _this = this;
  1404. $('.left-toolbar-container').on('click','li',function(){
  1405. var $this = $(this);
  1406. if($this.hasClass('selected')){ //当前是选中状态
  1407. $this.removeClass('selected');
  1408. _this.setValue('left-toolbar-show',false);
  1409. $apiContainr.hide();
  1410. }else{
  1411. $this.addClass('selected');
  1412. _this.setValue('left-toolbar-show',true);
  1413. $apiContainr.show();
  1414. }
  1415. _this.layout();
  1416. })
  1417. var $middleContainer = $('.middle-container');
  1418. // 调整宽度
  1419. var resizer = $middleContainer.find('.resizer-x')[0];
  1420. resizer.onmousedown = function(){
  1421. var box = $apiContainr[0].getClientRects()[0];
  1422. document.onmousemove = function(e){
  1423. var move = e.clientX - 22;
  1424. if(move > 150 && move < 700){
  1425. _this.layout();
  1426. _this.setValue('left-toolbar-width',move);
  1427. $apiContainr.width(move);
  1428. }
  1429. }
  1430. document.onmouseup = function(evt){
  1431. document.onmousemove = null;
  1432. document.onmouseup = null;
  1433. resizer.releaseCapture && resizer.releaseCapture();
  1434. }
  1435. resizer.setCapture && resizer.setCapture();
  1436. }
  1437. $('body').on('click','.group-header',function(){
  1438. var $parent = $(this).parent();
  1439. if($parent.hasClass('opened')){
  1440. $parent.removeClass('opened');
  1441. $(this).find('.icon-arrow-bottom').removeClass('icon-arrow-bottom').addClass('icon-arrow-right');
  1442. }else{
  1443. $parent.addClass('opened');
  1444. $(this).find('.icon-arrow-right').removeClass('icon-arrow-right').addClass('icon-arrow-bottom');
  1445. }
  1446. })
  1447. },
  1448. formatJson : function (val, defaultVal) {
  1449. return (val ? JSON.stringify(val, null, 4) : defaultVal) || '';
  1450. },
  1451. // 初始化底部
  1452. initBottomContainer : function(){
  1453. var $contentContainer = $('.bottom-container .bottom-content-container');
  1454. var value = this.getValue('bottom-container-height');
  1455. if(value && !isNaN(Number(value))){
  1456. $contentContainer.height(value);
  1457. }
  1458. if('false' == this.getValue('bottom-tab-show')){
  1459. $contentContainer.hide(); //隐藏全部
  1460. $('.bottom-container .bottom-tab li').removeClass('selected');
  1461. }else{
  1462. var index = Number(this.getValue('bottom-tab-index'));
  1463. if(!isNaN(index)){
  1464. this.navigateTo(index);
  1465. }
  1466. }
  1467. var _this = this;
  1468. $('.bottom-container').on('click','.bottom-tab li',function(){
  1469. var $this = $(this);
  1470. if($this.hasClass('selected')){ //当前是选中状态
  1471. $contentContainer.hide(); //隐藏全部
  1472. $this.removeClass('selected')
  1473. _this.setValue('bottom-tab-show',true);
  1474. }else{
  1475. $this.addClass('selected').siblings().removeClass('selected'); //选中选择项,取消其他选择项
  1476. var index = $(this).index();
  1477. _this.setValue('bottom-tab-index',index);
  1478. _this.setValue('bottom-tab-show',true);
  1479. $contentContainer.show().find('.bottom-content-item').hide().eq(index).show();
  1480. }
  1481. _this.layout();
  1482. }).on('click','.button-minimize',function(){
  1483. _this.setValue('bottom-tab-show',false);
  1484. $contentContainer.hide(); //隐藏全部
  1485. $('.bottom-tab li').removeClass('selected');
  1486. _this.layout();
  1487. });
  1488. // 调整底部高度
  1489. var resizer = $contentContainer.find('.resizer-y')[0];
  1490. resizer.onmousedown = function(){
  1491. var box = $contentContainer[0].getClientRects()[0];
  1492. document.onmousemove = function(e){
  1493. if(e.clientY > 150){
  1494. var move = box.height - (e.clientY - box.y);
  1495. if(move > 30){
  1496. _this.setValue('bottom-container-height',move);
  1497. _this.layout();
  1498. $contentContainer.height(move);
  1499. }
  1500. }
  1501. }
  1502. document.onmouseup = function(evt){
  1503. document.onmousemove = null;
  1504. document.onmouseup = null;
  1505. resizer.releaseCapture && resizer.releaseCapture();
  1506. }
  1507. resizer.setCapture && resizer.setCapture();
  1508. }
  1509. $('.bottom-container').on('click','.bottom-content-item:eq(0) .button-clear',function(){
  1510. _this.requestEditor&&_this.requestEditor.setValue('{}');
  1511. }).on('click','.bottom-content-item:eq(0) .button-format',function(){
  1512. try{
  1513. _this.requestEditor.setValue(_this.formatJson(JSON.parse(_this.requestEditor.getValue()),'{\r\n}'));
  1514. }catch(e){}
  1515. }).on('click','.bottom-content-item:eq(1) .button-clear',function(){
  1516. _this.optionsEditor&&_this.optionsEditor.setValue('{}');
  1517. }).on('click','.bottom-content-item:eq(1) .button-format',function(){
  1518. try{
  1519. _this.optionsEditor.setValue(_this.formatJson(JSON.parse(_this.optionsEditor.getValue()),'{\r\n}'));
  1520. }catch(e){}
  1521. }).on('click','.bottom-content-item:eq(2) .button-clear',function(){
  1522. _this.resultEditor&&_this.resultEditor.setValue('{}');
  1523. }).on('click','.bottom-content-item:eq(2) .button-format',function(){
  1524. try{
  1525. _this.resultEditor.setValue(_this.formatJson(JSON.parse(_this.resultEditor.getValue()),'{\r\n}'));
  1526. }catch(e){}
  1527. }).on('click','.bottom-content-item:eq(4) .button-clear',function(){
  1528. $('.bottom-container .bottom-item-body.output').html('')
  1529. })
  1530. },
  1531. setSkin : function(skin){
  1532. $('body').addClass('skin-' + skin);
  1533. this.setValue('skin',skin);
  1534. monaco.editor.setTheme(skin);
  1535. MagicEditor.report('theme_' + skin);
  1536. MagicEditor.setStatusBar('切换皮肤至:' + skin);
  1537. //this.scriptEditor&&this.scriptEditor.setTheme(skin);
  1538. },
  1539. layout : function(){
  1540. this.scriptEditor&&this.scriptEditor.layout();
  1541. this.optionsEditor&&this.optionsEditor.layout();
  1542. this.requestEditor&&this.requestEditor.layout();
  1543. this.resultEditor&&this.resultEditor.layout();
  1544. this.diffEditor&&this.diffEditor.layout();
  1545. }
  1546. }
  1547. $(function(){
  1548. require(['vs/editor/editor.main'],function(){
  1549. MagicEditor.init();
  1550. $('.loading-wrapper').remove();
  1551. })
  1552. $(window).resize(function(){
  1553. MagicEditor.layout();
  1554. });
  1555. });