index.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /**
  2. * FeHelper Json Format Tools
  3. */
  4. let editor = {};
  5. let LOCAL_KEY_OF_LAYOUT = 'local-layout-key';
  6. let JSON_LINT = 'jsonformat:json-lint-switch';
  7. let EDIT_ON_CLICK = 'jsonformat:edit-on-click';
  8. // json with bigint supported
  9. Tarp.require('../static/vendor/json-bigint/index');
  10. new Vue({
  11. el: '#pageContainer',
  12. data: {
  13. defaultResultTpl: '<div class="x-placeholder"><img src="./json-demo.jpg" alt="json-placeholder"></div>',
  14. resultContent: '',
  15. jsonFormattedSource: '',
  16. errorMsg: '',
  17. errorJsonCode: '',
  18. errorPos: '',
  19. jfCallbackName_start: '',
  20. jfCallbackName_end: '',
  21. showTips: false,
  22. jsonLintSwitch: true,
  23. fireChange: true,
  24. overrideJson: false
  25. },
  26. mounted: function () {
  27. this.resultContent = this.defaultResultTpl;
  28. this.jsonLintSwitch = (localStorage.getItem(JSON_LINT) !== 'false');
  29. this.overrideJson = (localStorage.getItem(EDIT_ON_CLICK) === 'true');
  30. this.changeLayout(localStorage.getItem(LOCAL_KEY_OF_LAYOUT));
  31. editor = CodeMirror.fromTextArea(this.$refs.jsonBox, {
  32. mode: "text/javascript",
  33. lineNumbers: true,
  34. matchBrackets: true,
  35. styleActiveLine: true,
  36. lineWrapping: true
  37. });
  38. //输入框聚焦
  39. editor.focus();
  40. // 格式化以后的JSON,点击以后可以重置原内容
  41. window._OnJsonItemClickByFH = (jsonTxt) => {
  42. if (this.overrideJson) {
  43. this.disableEditorChange(jsonTxt);
  44. }
  45. };
  46. editor.on('change', (editor, changes) => {
  47. this.jsonFormattedSource = editor.getValue().replace(/\n/gm, ' ');
  48. this.fireChange && this.format();
  49. });
  50. // 在tab创建或者更新时候,监听事件,看看是否有参数传递过来
  51. chrome.runtime.onMessage.addListener((request, sender, callback) => {
  52. let MSG_TYPE = Tarp.require('../static/js/msg_type');
  53. if (request.type === MSG_TYPE.TAB_CREATED_OR_UPDATED && request.event === MSG_TYPE.JSON_FORMAT) {
  54. if (request.content) {
  55. editor.setValue(request.content || this.defaultResultTpl);
  56. this.format();
  57. }
  58. }
  59. });
  60. },
  61. methods: {
  62. format: function () {
  63. this.showTips = false;
  64. this.errorMsg = '';
  65. this.resultContent = this.defaultResultTpl;
  66. let source = editor.getValue().replace(/\n/gm, ' ');
  67. if (!source) {
  68. return false;
  69. }
  70. // JSONP形式下的callback name
  71. let funcName = null;
  72. // json对象
  73. let jsonObj = null;
  74. // 下面校验给定字符串是否为一个合法的json
  75. try {
  76. // 再看看是不是jsonp的格式
  77. let reg = /^([\w\.]+)\(\s*([\s\S]*)\s*\)$/igm;
  78. let matches = reg.exec(source);
  79. if (matches != null) {
  80. funcName = matches[1];
  81. source = matches[2];
  82. }
  83. // 这里可能会throw exception
  84. jsonObj = JSON.parse(source);
  85. } catch (ex) {
  86. // new Function的方式,能自动给key补全双引号,但是不支持bigint,所以是下下策,放在try-catch里搞
  87. try {
  88. jsonObj = new Function("return " + source)();
  89. } catch (exx) {
  90. try {
  91. // 再给你一次机会,是不是下面这种情况: "{\"ret\":\"0\", \"msg\":\"ok\"}"
  92. jsonObj = new Function("return '" + source + "'")();
  93. if (typeof jsonObj === 'string') {
  94. // 最后给你一次机会,是个字符串,老夫给你再转一次
  95. jsonObj = new Function("return " + jsonObj)();
  96. }
  97. } catch (exxx) {
  98. this.errorMsg = exxx.message;
  99. }
  100. }
  101. }
  102. // 是json格式,可以进行JSON自动格式化
  103. if (jsonObj != null && typeof jsonObj === "object" && !this.errorMsg.length) {
  104. try {
  105. let sortType = document.querySelectorAll('[name=jsonsort]:checked')[0].value;
  106. if (sortType !== '0') {
  107. jsonObj = Tarp.require('../json-format/jsonabc').sortObj(jsonObj, parseInt(sortType), true);
  108. }
  109. source = JSON.stringify(jsonObj);
  110. } catch (ex) {
  111. // 通过JSON反解不出来的,一定有问题
  112. this.errorMsg = ex.message;
  113. }
  114. if (!this.errorMsg.length) {
  115. // 格式化
  116. Tarp.require('./format-lib').format(source);
  117. this.jsonFormattedSource = source;
  118. // 如果是JSONP格式的,需要把方法名也显示出来
  119. if (funcName != null) {
  120. this.jfCallbackName_start = funcName + '(';
  121. this.jfCallbackName_end = ')';
  122. } else {
  123. this.jfCallbackName_start = '';
  124. this.jfCallbackName_end = '';
  125. }
  126. }
  127. }
  128. if (this.errorMsg.length) {
  129. if (this.jsonLintSwitch) {
  130. return this.lintOn();
  131. } else {
  132. this.resultContent = '<span class="x-error">' + this.errorMsg + '</span>';
  133. return false;
  134. }
  135. }
  136. return true;
  137. },
  138. compress: function () {
  139. if (this.format()) {
  140. let jsonTxt = this.jfCallbackName_start + this.jsonFormattedSource + this.jfCallbackName_end;
  141. this.disableEditorChange(jsonTxt);
  142. }
  143. },
  144. changeLayout: function (type) {
  145. if (type === 'up-down') {
  146. if (this.$refs.btnUpDown.classList.contains('selected')) {
  147. return;
  148. }
  149. this.$refs.panelBody.classList.add('layout-up-down');
  150. this.$refs.btnLeftRight.classList.remove('selected');
  151. this.$refs.btnUpDown.classList.add('selected');
  152. } else {
  153. if (this.$refs.btnLeftRight.classList.contains('selected')) {
  154. return;
  155. }
  156. this.$refs.panelBody.classList.remove('layout-up-down');
  157. this.$refs.btnLeftRight.classList.add('selected');
  158. this.$refs.btnUpDown.classList.remove('selected');
  159. }
  160. localStorage.setItem(LOCAL_KEY_OF_LAYOUT, type);
  161. },
  162. setCache: function () {
  163. this.$nextTick(() => {
  164. localStorage.setItem(EDIT_ON_CLICK, this.overrideJson);
  165. });
  166. },
  167. lintOn: function () {
  168. this.$nextTick(() => {
  169. localStorage.setItem(JSON_LINT, this.jsonLintSwitch);
  170. });
  171. if (!editor.getValue().trim()) {
  172. return true;
  173. }
  174. this.$nextTick(() => {
  175. if (!this.jsonLintSwitch) {
  176. return;
  177. }
  178. let lintResult = Tarp.require('./jsonlint')(editor.getValue());
  179. if (!isNaN(lintResult.line)) {
  180. this.errorPos = '错误位置:' + (lintResult.line + 1) + '行,' + (lintResult.col + 1) + '列;缺少字符或字符不正确';
  181. this.errorJsonCode = lintResult.dom;
  182. this.showTips = true;
  183. this.$nextTick(() => {
  184. let el = document.querySelector('#errorCode .errorEm');
  185. el && el.scrollIntoView();
  186. let scrollEl = document.querySelector('#errorTips');
  187. scrollEl.scrollBy(0, el.offsetTop - scrollEl.scrollTop - 50);
  188. });
  189. }
  190. });
  191. return false;
  192. },
  193. closeTips: function () {
  194. this.showTips = false;
  195. },
  196. disableEditorChange: function (jsonTxt) {
  197. this.fireChange = false;
  198. this.$nextTick(() => {
  199. editor.setValue(jsonTxt);
  200. this.$nextTick(() => {
  201. this.fireChange = true;
  202. })
  203. })
  204. },
  205. setDemo: function () {
  206. let demo = '{"BigIntSupported":995815895020119788889,"date":"20180322","message":"Success !","status":200,"city":"北京","count":632,"data":{"shidu":"34%","pm25":73,"pm10":91,"quality":"良","wendu":"5","ganmao":"极少数敏感人群应减少户外活动","yesterday":{"date":"21日星期三","sunrise":"06:19","high":"高温 11.0℃","low":"低温 1.0℃","sunset":"18:26","aqi":85,"fx":"南风","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"},"forecast":[{"date":"22日星期四","sunrise":"06:17","high":"高温 17.0℃","low":"低温 1.0℃","sunset":"18:27","aqi":98,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"23日星期五","sunrise":"06:16","high":"高温 18.0℃","low":"低温 5.0℃","sunset":"18:28","aqi":118,"fx":"无持续风向","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"},{"date":"24日星期六","sunrise":"06:14","high":"高温 21.0℃","low":"低温 7.0℃","sunset":"18:29","aqi":52,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"25日星期日","sunrise":"06:13","high":"高温 22.0℃","low":"低温 7.0℃","sunset":"18:30","aqi":71,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"26日星期一","sunrise":"06:11","high":"高温 21.0℃","low":"低温 8.0℃","sunset":"18:31","aqi":97,"fx":"西南风","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"}]}}';
  207. editor.setValue(demo);
  208. }
  209. }
  210. });