/** * FeHelper Json Format Tools */ // 一些全局变量 let editor = {}; let LOCAL_KEY_OF_LAYOUT = 'local-layout-key'; let JSON_LINT = 'jsonformat:json-lint-switch'; let EDIT_ON_CLICK = 'jsonformat:edit-on-click'; let AUTO_DECODE = 'jsonformat:auto-decode'; new Vue({ el: '#pageContainer', data: { defaultResultTpl: '
json-placeholder
', placeHolder: '', jsonFormattedSource: '', errorMsg: '', errorJsonCode: '', errorPos: '', jfCallbackName_start: '', jfCallbackName_end: '', jsonLintSwitch: true, autoDecode: false, fireChange: true, overrideJson: false }, mounted: function () { // 自动开关灯控制 DarkModeMgr.turnLightAuto(); this.placeHolder = this.defaultResultTpl; this.autoDecode = localStorage.getItem(AUTO_DECODE); this.autoDecode = this.autoDecode === 'true'; this.jsonLintSwitch = (localStorage.getItem(JSON_LINT) !== 'false'); this.overrideJson = (localStorage.getItem(EDIT_ON_CLICK) === 'true'); this.changeLayout(localStorage.getItem(LOCAL_KEY_OF_LAYOUT)); editor = CodeMirror.fromTextArea(this.$refs.jsonBox, { mode: "text/javascript", lineNumbers: true, matchBrackets: true, styleActiveLine: true, lineWrapping: true }); //输入框聚焦 editor.focus(); // 格式化以后的JSON,点击以后可以重置原内容 window._OnJsonItemClickByFH = (jsonTxt) => { if (this.overrideJson) { this.disableEditorChange(jsonTxt); } }; editor.on('change', (editor, changes) => { this.jsonFormattedSource = editor.getValue().replace(/\n/gm, ' '); this.fireChange && this.format(); }); // 在tab创建或者更新时候,监听事件,看看是否有参数传递过来 if (location.protocol === 'chrome-extension:') { chrome.runtime.onMessage.addListener((request, sender, callback) => { if (request.type === 'TAB_CREATED_OR_UPDATED' && request.content && request.event === location.pathname.split('/')[1]) { editor.setValue(request.content || this.defaultResultTpl); this.format(); } callback && callback(); return true; }); } }, methods: { format: function () { this.errorMsg = ''; this.placeHolder = this.defaultResultTpl; this.jfCallbackName_start = ''; this.jfCallbackName_end = ''; let source = editor.getValue().replace(/\n/gm, ' '); if (!source) { return false; } // JSONP形式下的callback name let funcName = null; // json对象 let jsonObj = null; // 下面校验给定字符串是否为一个合法的json try { // 再看看是不是jsonp的格式 let reg = /^([\w\.]+)\(\s*([\s\S]*)\s*\)$/igm; let matches = reg.exec(source); if (matches != null) { funcName = matches[1]; source = matches[2]; } // 这里可能会throw exception jsonObj = JSON.parse(source); } catch (ex) { // new Function的方式,能自动给key补全双引号,但是不支持bigint,所以是下下策,放在try-catch里搞 try { jsonObj = new Function("return " + source)(); } catch (exx) { try { // 再给你一次机会,是不是下面这种情况: "{\"ret\":\"0\", \"msg\":\"ok\"}" jsonObj = new Function("return '" + source + "'")(); if (typeof jsonObj === 'string') { try { // 确保bigint不会失真 jsonObj = JSON.parse(jsonObj); } catch (ie) { // 最后给你一次机会,是个字符串,老夫给你再转一次 jsonObj = new Function("return " + jsonObj)(); } } } catch (exxx) { this.errorMsg = exxx.message; } } } // 是json格式,可以进行JSON自动格式化 if (jsonObj != null && typeof jsonObj === "object" && !this.errorMsg.length) { try { let sortType = document.querySelectorAll('[name=jsonsort]:checked')[0].value; if (sortType !== '0') { jsonObj = JsonABC.sortObj(jsonObj, parseInt(sortType), true); } source = JSON.stringify(jsonObj); } catch (ex) { // 通过JSON反解不出来的,一定有问题 this.errorMsg = ex.message; } if (!this.errorMsg.length) { if (this.autoDecode) { (async () => { let txt = await JsonEnDecode.urlDecodeByFetch(source); source = JsonEnDecode.uniDecode(txt); Formatter.format(source); })(); } else { Formatter.format(source); } this.placeHolder = ''; this.jsonFormattedSource = source; // 如果是JSONP格式的,需要把方法名也显示出来 if (funcName != null) { this.jfCallbackName_start = funcName + '('; this.jfCallbackName_end = ')'; } else { this.jfCallbackName_start = ''; this.jfCallbackName_end = ''; } this.$nextTick(() => { this.updateWrapperHeight(); }) } } if (this.errorMsg.length) { if (this.jsonLintSwitch) { return this.lintOn(); } else { this.placeHolder = '' + this.errorMsg + ''; return false; } } return true; }, compress: function () { if (this.format()) { let jsonTxt = this.jfCallbackName_start + this.jsonFormattedSource + this.jfCallbackName_end; this.disableEditorChange(jsonTxt); } }, autoDecodeFn: function () { this.$nextTick(() => { localStorage.setItem(AUTO_DECODE, this.autoDecode); this.format(); }); }, uniEncode: function () { editor.setValue(JsonEnDecode.uniEncode(editor.getValue())); }, uniDecode: function () { editor.setValue(JsonEnDecode.uniDecode(editor.getValue())); }, urlDecode: function () { JsonEnDecode.urlDecodeByFetch(editor.getValue()).then(text => editor.setValue(text)); }, updateWrapperHeight: function () { let curLayout = localStorage.getItem(LOCAL_KEY_OF_LAYOUT); let elPc = document.querySelector('#pageContainer'); if (curLayout === 'up-down') { elPc.style.height = 'auto'; } else { elPc.style.height = Math.max(elPc.scrollHeight, document.body.scrollHeight) + 'px'; } }, changeLayout: function (type) { let elPc = document.querySelector('#pageContainer'); if (type === 'up-down') { elPc.classList.remove('layout-left-right'); elPc.classList.add('layout-up-down'); this.$refs.btnLeftRight.classList.remove('selected'); this.$refs.btnUpDown.classList.add('selected'); } else { elPc.classList.remove('layout-up-down'); elPc.classList.add('layout-left-right'); this.$refs.btnLeftRight.classList.add('selected'); this.$refs.btnUpDown.classList.remove('selected'); } localStorage.setItem(LOCAL_KEY_OF_LAYOUT, type); this.updateWrapperHeight(); }, setCache: function () { this.$nextTick(() => { localStorage.setItem(EDIT_ON_CLICK, this.overrideJson); }); }, lintOn: function () { this.$nextTick(() => { localStorage.setItem(JSON_LINT, this.jsonLintSwitch); }); if (!editor.getValue().trim()) { return true; } this.$nextTick(() => { if (!this.jsonLintSwitch) { return; } let lintResult = JsonLint.lintDetect(editor.getValue()); if (!isNaN(lintResult.line)) { this.placeHolder = '
' + '
错误位置:' + (lintResult.line + 1) + '行,' + (lintResult.col + 1) + '列;缺少字符或字符不正确
' + '
' + lintResult.dom + '
'; } }); return false; }, disableEditorChange: function (jsonTxt) { this.fireChange = false; this.$nextTick(() => { editor.setValue(jsonTxt); this.$nextTick(() => { this.fireChange = true; }) }) }, openOptionsPage: function(){ chrome.runtime.openOptionsPage(); }, setDemo: function () { 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":"阴晴之间,谨防紫外线侵扰"}]}}'; editor.setValue(demo); } } });