index.js 63 KB

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