Browse Source

增加代码健壮性,同时兼容Firefox

zxlie 4 months ago
parent
commit
372c09c59a

+ 15 - 8
apps/background/awesome.js

@@ -113,7 +113,9 @@ let Awesome = (() => {
 
         // 删除所有静态文件
         chrome.storage.local.get(null, allDatas => {
-            StorageMgr.remove(Object.keys(allDatas).filter(key => String(key).startsWith(`../${toolName}/`)));
+            if (allDatas) {
+                StorageMgr.remove(Object.keys(allDatas).filter(key => String(key).startsWith(`../${toolName}/`)));
+            }
         });
 
         log(toolName + ' 卸载成功!');
@@ -124,11 +126,14 @@ let Awesome = (() => {
     /**
      * 有些工具其实已经卸载过了,但是本地还有冗余的静态文件,都需要统一清理一遍
      */
-    let gcLocalFiles = () => getAllTools().then(tools => Object.keys(tools).forEach(tool => {
-        if (!tools[tool] || !tools[tool]._devTool && !tools[tool].installed) {
-            offLoad(tool);
-        }
-    }));
+    let gcLocalFiles = () => getAllTools().then(tools => {
+        if (!tools) return;
+        Object.keys(tools).forEach(tool => {
+            if (!tools[tool] || !tools[tool]._devTool && !tools[tool].installed) {
+                offLoad(tool);
+            }
+        });
+    });
 
     let getAllTools = async () => {
 
@@ -163,8 +168,8 @@ let Awesome = (() => {
         let pSort = SortToolMgr.get();
 
         return Promise.all([pAll,pSort]).then(vs => {
-            let allTools = vs[0];
-            let sortTools = vs[1];
+            let allTools = vs[0] || {};
+            let sortTools = vs[1] || [];
 
             if (sortTools && sortTools.length) {
                 let map = {};
@@ -190,6 +195,7 @@ let Awesome = (() => {
      * @returns {Promise}
      */
     let getInstalledTools = () => getAllTools().then(tools => {
+        if (!tools) return {};
         let istTolls = {};
         Object.keys(tools).filter(tool => {
             if (tools[tool] && tools[tool].installed) {
@@ -367,3 +373,4 @@ let Awesome = (() => {
 })();
 
 export default Awesome;
+

+ 9 - 5
apps/background/background.js

@@ -593,11 +593,14 @@ let BgPageInstance = (function () {
      */
     let _checkUpdate = function () {
         setTimeout(() => {
-            chrome.runtime.requestUpdateCheck((status) => {
-                if (status === "update_available") {
-                    chrome.runtime.reload();
-                }
-            });
+            // 检查是否为 Firefox 浏览器,Firefox 不支持 requestUpdateCheck API
+            if (chrome.runtime.requestUpdateCheck && navigator.userAgent.indexOf("Firefox") === -1) {
+                chrome.runtime.requestUpdateCheck((status) => {
+                    if (status === "update_available") {
+                        chrome.runtime.reload();
+                    }
+                });
+            }
         }, 1000 * 30);
     };
 
@@ -667,3 +670,4 @@ let BgPageInstance = (function () {
 })();
 
 BgPageInstance.init();
+

+ 100 - 0
apps/chrome.json

@@ -0,0 +1,100 @@
+{
+  "name": "FeHelper(前端助手)-Dev",
+  "short_name": "FeHelper",
+  "version": "2025.05.2014",
+  "manifest_version": 3,
+  "description": "JSON自动格式化、手动格式化,支持排序、解码、下载等,更多功能可在配置页按需安装!",
+  "icons": {
+    "16": "static/img/fe-16.png",
+    "48": "static/img/fe-48.png",
+    "128": "static/img/fe-128.png"
+  },
+  "action": {
+    "default_icon": "static/img/fe-16.png",
+    "default_title": "FeHelper(前端助手)",
+    "default_popup": "popup/index.html"
+  },
+  "background": {
+    "service_worker": "background/background.js",
+    "type": "module"
+  },
+  "options_ui": {
+    "page": "options/index.html",
+    "open_in_tab": true
+  },
+  "permissions": [
+    "tabs",
+    "scripting",
+    "contextMenus",
+    "activeTab",
+    "storage",
+    "notifications",
+    "unlimitedStorage"
+  ],
+  "host_permissions": [
+    "http://*/*",
+    "https://*/*",
+    "file://*/*"
+    ],
+  "optional_permissions": [
+    "downloads"
+  ],
+  "commands": {
+    "_execute_action": {
+      "suggested_key": {
+        "default": "Alt+Shift+J"
+      }
+    }
+  },
+  "web_accessible_resources": [
+      {
+          "resources":[
+            "static/img/fe-16.png",
+            "static/img/fe-48.png",
+            "static/img/loading.gif",
+            "json-format/format-lib.js",
+            "json-format/json-abc.js",
+            "json-format/json-bigint.js",
+            "json-format/json-decode.js",
+            "json-format/json-worker.js",
+            "static/vendor/jquery/jquery-3.3.1.min.js",
+            "static/vendor/evalCore.min.js",
+
+            "background/awesome.js",
+            "background/tools.js",
+
+            "code-beautify/beautify.js",
+            "code-beautify/beautify-css.js",
+
+            "page-timing/timing.js"
+        ],
+        "matches": ["<all_urls>"]
+      }
+  ],
+  "content_scripts": [
+    {
+      "matches": [
+        "http://*/*",
+        "https://*/*",
+        "file://*/*"
+      ],
+      "exclude_globs": [
+        "https://chrome.google.com/*"
+      ],
+      "js": [
+        "static/vendor/jquery/jquery-3.3.1.min.js",
+        "static/vendor/evalCore.min.js"
+      ],
+      "run_at": "document_start",
+      "all_frames": true
+    }
+  ],
+  "content_security_policy": {
+    "extension_pages": "script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'self'"
+  },
+  "update_url": "https://clients2.google.com/service/update2/crx",
+  "homepage_url": "https://www.fehelper.com"
+}
+
+
+

+ 99 - 0
apps/firefox.json

@@ -0,0 +1,99 @@
+{
+  "name": "FeHelper(前端助手)-Dev",
+  "short_name": "FeHelper",
+  "version": "2025.5.2014",
+  "manifest_version": 3,
+  "description": "JSON自动格式化、手动格式化,支持排序、解码、下载等,更多功能可在配置页按需安装!",
+  "icons": {
+    "16": "static/img/fe-16.png",
+    "48": "static/img/fe-48.png",
+    "128": "static/img/fe-128.png"
+  },
+  "action": {
+    "default_icon": "static/img/fe-16.png",
+    "default_title": "FeHelper(前端助手)",
+    "default_popup": "popup/index.html"
+  },
+  "background": {
+    "scripts": ["background/background.js"],
+    "type": "module"
+  },
+  "options_ui": {
+    "page": "options/index.html",
+    "open_in_tab": true
+  },
+  "permissions": [
+    "tabs",
+    "scripting",
+    "contextMenus",
+    "activeTab",
+    "storage",
+    "notifications",
+    "unlimitedStorage"
+  ],
+  "host_permissions": [
+    "http://*/*",
+    "https://*/*",
+    "file://*/*"
+    ],
+  "optional_permissions": [
+    "downloads"
+  ],
+  "commands": {
+    "_execute_action": {
+      "suggested_key": {
+        "default": "Alt+Shift+J"
+      }
+    }
+  },
+  "web_accessible_resources": [
+      {
+          "resources":[
+            "static/img/fe-16.png",
+            "static/img/fe-48.png",
+            "static/img/loading.gif",
+            "json-format/format-lib.js",
+            "json-format/json-abc.js",
+            "json-format/json-bigint.js",
+            "json-format/json-decode.js",
+            "json-format/json-worker.js",
+            "static/vendor/jquery/jquery-3.3.1.min.js",
+            "static/vendor/evalCore.min.js",
+
+            "background/awesome.js",
+            "background/tools.js",
+
+            "code-beautify/beautify.js",
+            "code-beautify/beautify-css.js",
+
+            "page-timing/timing.js"
+        ],
+        "matches": ["<all_urls>"]
+      }
+  ],
+  "content_scripts": [
+    {
+      "matches": [
+        "http://*/*",
+        "https://*/*",
+        "file://*/*"
+      ],
+      "exclude_globs": [
+        "https://chrome.google.com/*"
+      ],
+      "js": [
+        "static/vendor/jquery/jquery-3.3.1.min.js",
+        "static/vendor/evalCore.min.js"
+      ],
+      "run_at": "document_start",
+      "all_frames": true
+    }
+  ],
+  "content_security_policy": {
+    "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; worker-src 'self' blob:; style-src 'self' 'unsafe-inline'; object-src 'self'; connect-src 'self' blob:"
+  },
+  "homepage_url": "https://www.fehelper.com"
+}
+
+
+

+ 41 - 310
apps/json-format/format-lib.js

@@ -487,289 +487,13 @@ window.Formatter = (function () {
         }
         
         try {
-            // 创建内联Worker
-            // 这个版本包含基本的JSON格式化功能
-            let workerCode = `
-                // 创建一个处理BigInt的JSON解析器
-                const JSONBigInt = {
-                    // 自定义的parse方法,处理大数字
-                    parse: function(text) {
-                        // 先尝试预处理字符串,将可能的大整数标记出来
-                        // 以更精确的方式匹配JSON中的大整数
-                        const preparedText = this._markBigInts(text);
-                        
-                        try {
-                            // 使用标准JSON解析,同时使用reviver函数还原BigInt
-                            return JSON.parse(preparedText, this._reviver);
-                        } catch (e) {
-                            // 如果处理失败,尝试原始解析方式
-                            console.error('BigInt处理失败,回退到标准解析', e);
-                            return JSON.parse(text);
-                        }
-                    },
-                    
-                    // 将JSON字符串中的大整数标记为特殊格式
-                    _markBigInts: function(text) {
-                        // 这个正则匹配JSON中的数字,但需要避免匹配到引号内的字符串
-                        // 匹配模式: 找到数字前面是冒号或左方括号的情况(表示这是个值而不是键名)
-                        return text.replace(
-                            /([:,\\[]\\s*)(-?\\d{16,})([,\\]\\}])/g, 
-                            function(match, prefix, number, suffix) {
-                                // 将大数字转换为特殊格式的字符串
-                                return prefix + '"__BigInt__' + number + '"' + suffix;
-                            }
-                        );
-                    },
-                    
-                    // 恢复函数,将标记的BigInt字符串转回BigInt类型
-                    _reviver: function(key, value) {
-                        // 检查是否是我们标记的BigInt字符串
-                        if (typeof value === 'string' && value.startsWith('__BigInt__')) {
-                            // 提取数字部分
-                            const numStr = value.substring(10);
-                            try {
-                                // 尝试转换为BigInt
-                                return BigInt(numStr);
-                            } catch (e) {
-                                // 如果转换失败,保留原始字符串
-                                console.warn('无法转换为BigInt:', numStr);
-                                return numStr;
-                            }
-                        }
-                        return value;
-                    }
-                };
-                
-                // 处理主线程消息
-                self.onmessage = function(event) {
-                    
-                    // 格式化JSON
-                    if (event.data.jsonString) {
-                        // 发送格式化中的消息
-                        self.postMessage(['FORMATTING']);
-                        
-                        try {
-                            // 先预处理JSON字符串,防止大整数丢失精度
-                            let jsonObj;
-                            
-                            try {
-                                // 尝试使用自定义的BigInt解析器
-                                jsonObj = JSONBigInt.parse(event.data.jsonString);
-                            } catch (e) {
-                                // 如果解析失败,回退到标准解析
-                                console.error('BigInt解析失败,回退到标准解析', e);
-                                jsonObj = JSON.parse(event.data.jsonString);
-                            }
-                            
-                            // 如果是简单主题,直接返回格式化的JSON
-                            if (event.data.skin && event.data.skin === 'theme-simple') {
-                                // 处理BigInt特殊情况
-                                let formatted = JSON.stringify(jsonObj, function(key, value) {
-                                    if (typeof value === 'bigint') {
-                                        // 移除n后缀,只显示数字本身
-                                        return value.toString();
-                                    }
-                                    // 处理普通数字,避免科学计数法
-                                    if (typeof value === 'number' && value.toString().includes('e')) {
-                                        // 大数字转为字符串以避免科学计数法
-                                        return value.toLocaleString('fullwide', {useGrouping: false});
-                                    }
-                                    return value;
-                                }, 4);
-                                
-                                let html = '<div id="formattedJson"><pre class="rootItem">' + 
-                                    formatted.replace(/&/g, '&amp;')
-                                        .replace(/</g, '&lt;')
-                                        .replace(/>/g, '&gt;')
-                                        .replace(/"/g, '&quot;')
-                                        .replace(/'/g, '&#039;') + 
-                                    '</pre></div>';
-                                
-                                self.postMessage(['FORMATTED', html]);
-                                return;
-                            }
-                            
-                            // 默认主题 - 创建更丰富的HTML结构
-                            let html = '<div id="formattedJson">' +
-                                formatJsonToHtml(jsonObj) +
-                                '</div>';
-                            
-                            self.postMessage(['FORMATTED', html]);
-                        } catch (e) {
-                            // 处理错误情况
-                            self.postMessage(['FORMATTED', '<div id="formattedJson"><div class="error">格式化失败: ' + e.message + '</div></div>']);
-                        }
-                    }
-                };
-                
-                // HTML特殊字符格式化
-                function htmlspecialchars(str) {
-                    str = str.replace(/&/g, '&amp;');
-                    str = str.replace(/</g, '&lt;');
-                    str = str.replace(/>/g, '&gt;');
-                    str = str.replace(/"/g, '&quot;');
-                    str = str.replace(/'/g, '&#039;');
-                    return str;
-                }
-                
-                // 格式化JSON为HTML
-                function formatJsonToHtml(json) {
-                    return createNode(json).getHTML();
-                }
-                
-                // 创建节点
-                function createNode(value) {
-                    let node = {
-                        type: getType(value),
-                        value: value,
-                        children: [],
-                        
-                        getHTML: function() {
-                            switch(this.type) {
-                                case 'string':
-                                    return '<div class="item item-line"><span class="string">"' + 
-                                        htmlspecialchars(this.value) + 
-                                        '"</span></div>';
-                                case 'number':
-                                    // 确保大数字不使用科学计数法
-                                    let numStr = typeof this.value === 'number' && this.value.toString().includes('e') 
-                                        ? this.value.toLocaleString('fullwide', {useGrouping: false})
-                                        : this.value;
-                                    return '<div class="item item-line"><span class="number">' + 
-                                        numStr + 
-                                        '</span></div>';
-                                case 'bigint':
-                                    // 对BigInt类型特殊处理,只显示数字,不添加n后缀
-                                    return '<div class="item item-line"><span class="number">' + 
-                                        this.value.toString() + 
-                                        '</span></div>';
-                                case 'boolean':
-                                    return '<div class="item item-line"><span class="bool">' + 
-                                        this.value + 
-                                        '</span></div>';
-                                case 'null':
-                                    return '<div class="item item-line"><span class="null">null</span></div>';
-                                case 'object':
-                                    return this.getObjectHTML();
-                                case 'array':
-                                    return this.getArrayHTML();
-                                default:
-                                    return '';
-                            }
-                        },
-                        
-                        getObjectHTML: function() {
-                            if (!this.value || Object.keys(this.value).length === 0) {
-                                return '<div class="item item-object"><span class="brace">{</span><span class="brace">}</span></div>';
-                            }
-                            
-                            let html = '<div class="item item-object">' +
-                                '<span class="expand"></span>' +
-                                '<span class="brace">{</span>' +
-                                '<span class="ellipsis"></span>' +
-                                '<div class="kv-list">';
-                                
-                            let keys = Object.keys(this.value);
-                            keys.forEach((key, index) => {
-                                let prop = this.value[key];
-                                let childNode = createNode(prop);
-                                
-                                html += '<div class="item">' + 
-                                    '<span class="quote">"</span>' +
-                                    '<span class="key">' + htmlspecialchars(key) + '</span>' +
-                                    '<span class="quote">"</span>' +
-                                    '<span class="colon">: </span>';
-                                
-                                // 添加值
-                                if (childNode.type === 'object' || childNode.type === 'array') {
-                                    html += childNode.getHTML();
-                                } else {
-                                    html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\\/div>$/, '');
-                                }
-                                
-                                // 如果不是最后一个属性,添加逗号
-                                if (index < keys.length - 1) {
-                                    html += '<span class="comma">,</span>';
-                                }
-                                
-                                html += '</div>';
-                            });
-                            
-                            html += '</div><span class="brace">}</span></div>';
-                            return html;
-                        },
-                        
-                        getArrayHTML: function() {
-                            if (!this.value || this.value.length === 0) {
-                                return '<div class="item item-array"><span class="brace">[</span><span class="brace">]</span></div>';
-                            }
-                            
-                            let html = '<div class="item item-array">' +
-                                '<span class="expand"></span>' +
-                                '<span class="brace">[</span>' +
-                                '<span class="ellipsis"></span>' +
-                                '<div class="kv-list">';
-                                
-                            this.value.forEach((item, index) => {
-                                let childNode = createNode(item);
-                                
-                                html += '<div class="item item-block">';
-                                
-                                // 添加值
-                                if (childNode.type === 'object' || childNode.type === 'array') {
-                                    html += childNode.getHTML();
-                                } else {
-                                    html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\\/div>$/, '');
-                                }
-                                
-                                // 如果不是最后一个元素,添加逗号
-                                if (index < this.value.length - 1) {
-                                    html += '<span class="comma">,</span>';
-                                }
-                                
-                                html += '</div>';
-                            });
-                            
-                            html += '</div><span class="brace">]</span></div>';
-                            return html;
-                        }
-                    };
-                    
-                    return node;
-                }
-                
-                // 获取值类型
-                function getType(value) {
-                    if (value === null) return 'null';
-                    if (value === undefined) return 'undefined';
-                    
-                    let type = typeof value;
-                    // 特别处理BigInt类型
-                    if (type === 'bigint') return 'bigint';
-                    if (type === 'object') {
-                        if (Array.isArray(value)) return 'array';
-                    }
-                    return type;
-                }
-            `;
-            
-            // 创建Blob URL并实例化Worker
-            let blob = new Blob([workerCode], {type: 'application/javascript'});
-            let workerUrl = URL.createObjectURL(blob);
-            
+            // 统一使用扩展内的脚本文件创建Worker
+            let workerUrl = chrome.runtime.getURL('json-format/json-worker.js');
             workerInstance = new Worker(workerUrl);
             
-            // 添加错误处理
-            workerInstance.onerror = function(e) {
-                // 如果Worker出错,清空实例允许下次重试
-                workerInstance = null;
-                
-                // 避免URL内存泄漏
-                URL.revokeObjectURL(workerUrl);
-            };
-            
             return workerInstance;
         } catch (e) {
+            console.error('创建Worker失败:', e);
             // 出现任何错误,返回null
             workerInstance = null;
             return null;
@@ -785,38 +509,44 @@ window.Formatter = (function () {
         _initElements();
         jfPre.html(htmlspecialchars(cachedJsonString));
 
-        // 获取Worker实例
-        let worker = _getWorkerInstance();
-        
-        if (worker) {
-            // 设置消息处理程序
-            worker.onmessage = function (evt) {
-                let msg = evt.data;
-                switch (msg[0]) {
-                    case 'FORMATTING':
-                        formattingMsg.show();
-                        break;
-
-                    case 'FORMATTED':
-                        formattingMsg.hide();
-                        jfContent.html(msg[1]);
-
-                        _buildOptionBar();
-                        // 事件绑定
-                        _addEvents();
-                        // 支持文件下载
-                        _downloadSupport(cachedJsonString);
-                        break;
-                }
-            };
+        try {
+            // 获取Worker实例
+            let worker = _getWorkerInstance();
             
-            // 发送格式化请求
-            worker.postMessage({
-                jsonString: jsonStr,
-                skin: skin
-            });
-        } else {
-            // Worker创建失败,回退到同步方式
+            if (worker) {
+                // 设置消息处理程序
+                worker.onmessage = function (evt) {
+                    let msg = evt.data;
+                    switch (msg[0]) {
+                        case 'FORMATTING':
+                            formattingMsg.show();
+                            break;
+
+                        case 'FORMATTED':
+                            formattingMsg.hide();
+                            jfContent.html(msg[1]);
+
+                            _buildOptionBar();
+                            // 事件绑定
+                            _addEvents();
+                            // 支持文件下载
+                            _downloadSupport(cachedJsonString);
+                            break;
+                    }
+                };
+                
+                // 发送格式化请求
+                worker.postMessage({
+                    jsonString: jsonStr,
+                    skin: skin
+                });
+            } else {
+                // Worker创建失败,回退到同步方式
+                formatSync(jsonStr, skin);
+            }
+        } catch (e) {
+            console.error('Worker处理失败:', e);
+            // 出现任何错误,回退到同步方式
             formatSync(jsonStr, skin);
         }
     };
@@ -863,3 +593,4 @@ window.Formatter = (function () {
 
 
 
+

+ 261 - 0
apps/json-format/json-worker.js

@@ -0,0 +1,261 @@
+// 创建一个处理BigInt的JSON解析器
+const JSONBigInt = {
+    // 自定义的parse方法,处理大数字
+    parse: function(text) {
+        // 先尝试预处理字符串,将可能的大整数标记出来
+        // 以更精确的方式匹配JSON中的大整数
+        const preparedText = this._markBigInts(text);
+        
+        try {
+            // 使用标准JSON解析,同时使用reviver函数还原BigInt
+            return JSON.parse(preparedText, this._reviver);
+        } catch (e) {
+            // 如果处理失败,尝试原始解析方式
+            console.error('BigInt处理失败,回退到标准解析', e);
+            return JSON.parse(text);
+        }
+    },
+    
+    // 将JSON字符串中的大整数标记为特殊格式
+    _markBigInts: function(text) {
+        // 这个正则匹配JSON中的数字,但需要避免匹配到引号内的字符串
+        // 匹配模式: 找到数字前面是冒号或左方括号的情况(表示这是个值而不是键名)
+        return text.replace(
+            /([:,\[]\s*)(-?\d{16,})([,\]\}])/g, 
+            function(match, prefix, number, suffix) {
+                // 将大数字转换为特殊格式的字符串
+                return prefix + '"__BigInt__' + number + '"' + suffix;
+            }
+        );
+    },
+    
+    // 恢复函数,将标记的BigInt字符串转回BigInt类型
+    _reviver: function(key, value) {
+        // 检查是否是我们标记的BigInt字符串
+        if (typeof value === 'string' && value.startsWith('__BigInt__')) {
+            // 提取数字部分
+            const numStr = value.substring(10);
+            try {
+                // 尝试转换为BigInt
+                return BigInt(numStr);
+            } catch (e) {
+                // 如果转换失败,保留原始字符串
+                console.warn('无法转换为BigInt:', numStr);
+                return numStr;
+            }
+        }
+        return value;
+    }
+};
+
+// 处理主线程消息
+self.onmessage = function(event) {
+    
+    // 格式化JSON
+    if (event.data.jsonString) {
+        // 发送格式化中的消息
+        self.postMessage(['FORMATTING']);
+        
+        try {
+            // 先预处理JSON字符串,防止大整数丢失精度
+            let jsonObj;
+            
+            try {
+                // 尝试使用自定义的BigInt解析器
+                jsonObj = JSONBigInt.parse(event.data.jsonString);
+            } catch (e) {
+                // 如果解析失败,回退到标准解析
+                console.error('BigInt解析失败,回退到标准解析', e);
+                jsonObj = JSON.parse(event.data.jsonString);
+            }
+            
+            // 如果是简单主题,直接返回格式化的JSON
+            if (event.data.skin && event.data.skin === 'theme-simple') {
+                // 处理BigInt特殊情况
+                let formatted = JSON.stringify(jsonObj, function(key, value) {
+                    if (typeof value === 'bigint') {
+                        // 移除n后缀,只显示数字本身
+                        return value.toString();
+                    }
+                    // 处理普通数字,避免科学计数法
+                    if (typeof value === 'number' && value.toString().includes('e')) {
+                        // 大数字转为字符串以避免科学计数法
+                        return value.toLocaleString('fullwide', {useGrouping: false});
+                    }
+                    return value;
+                }, 4);
+                
+                let html = '<div id="formattedJson"><pre class="rootItem">' + 
+                    formatted.replace(/&/g, '&amp;')
+                        .replace(/</g, '&lt;')
+                        .replace(/>/g, '&gt;')
+                        .replace(/"/g, '&quot;')
+                        .replace(/'/g, '&#039;') + 
+                    '</pre></div>';
+                
+                self.postMessage(['FORMATTED', html]);
+                return;
+            }
+            
+            // 默认主题 - 创建更丰富的HTML结构
+            let html = '<div id="formattedJson">' +
+                formatJsonToHtml(jsonObj) +
+                '</div>';
+            
+            self.postMessage(['FORMATTED', html]);
+        } catch (e) {
+            // 处理错误情况
+            self.postMessage(['FORMATTED', '<div id="formattedJson"><div class="error">格式化失败: ' + e.message + '</div></div>']);
+        }
+    }
+};
+
+// HTML特殊字符格式化
+function htmlspecialchars(str) {
+    str = str.replace(/&/g, '&amp;');
+    str = str.replace(/</g, '&lt;');
+    str = str.replace(/>/g, '&gt;');
+    str = str.replace(/"/g, '&quot;');
+    str = str.replace(/'/g, '&#039;');
+    return str;
+}
+
+// 格式化JSON为HTML
+function formatJsonToHtml(json) {
+    return createNode(json).getHTML();
+}
+
+// 创建节点
+function createNode(value) {
+    let node = {
+        type: getType(value),
+        value: value,
+        children: [],
+        
+        getHTML: function() {
+            switch(this.type) {
+                case 'string':
+                    return '<div class="item item-line"><span class="string">"' + 
+                        htmlspecialchars(this.value) + 
+                        '"</span></div>';
+                case 'number':
+                    // 确保大数字不使用科学计数法
+                    let numStr = typeof this.value === 'number' && this.value.toString().includes('e') 
+                        ? this.value.toLocaleString('fullwide', {useGrouping: false})
+                        : this.value;
+                    return '<div class="item item-line"><span class="number">' + 
+                        numStr + 
+                        '</span></div>';
+                case 'bigint':
+                    // 对BigInt类型特殊处理,只显示数字,不添加n后缀
+                    return '<div class="item item-line"><span class="number">' + 
+                        this.value.toString() + 
+                        '</span></div>';
+                case 'boolean':
+                    return '<div class="item item-line"><span class="bool">' + 
+                        this.value + 
+                        '</span></div>';
+                case 'null':
+                    return '<div class="item item-line"><span class="null">null</span></div>';
+                case 'object':
+                    return this.getObjectHTML();
+                case 'array':
+                    return this.getArrayHTML();
+                default:
+                    return '';
+            }
+        },
+        
+        getObjectHTML: function() {
+            if (!this.value || Object.keys(this.value).length === 0) {
+                return '<div class="item item-object"><span class="brace">{</span><span class="brace">}</span></div>';
+            }
+            
+            let html = '<div class="item item-object">' +
+                '<span class="expand"></span>' +
+                '<span class="brace">{</span>' +
+                '<span class="ellipsis"></span>' +
+                '<div class="kv-list">';
+                
+            let keys = Object.keys(this.value);
+            keys.forEach((key, index) => {
+                let prop = this.value[key];
+                let childNode = createNode(prop);
+                
+                html += '<div class="item">' + 
+                    '<span class="quote">"</span>' +
+                    '<span class="key">' + htmlspecialchars(key) + '</span>' +
+                    '<span class="quote">"</span>' +
+                    '<span class="colon">: </span>';
+                
+                // 添加值
+                if (childNode.type === 'object' || childNode.type === 'array') {
+                    html += childNode.getHTML();
+                } else {
+                    html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\/div>$/, '');
+                }
+                
+                // 如果不是最后一个属性,添加逗号
+                if (index < keys.length - 1) {
+                    html += '<span class="comma">,</span>';
+                }
+                
+                html += '</div>';
+            });
+            
+            html += '</div><span class="brace">}</span></div>';
+            return html;
+        },
+        
+        getArrayHTML: function() {
+            if (!this.value || this.value.length === 0) {
+                return '<div class="item item-array"><span class="brace">[</span><span class="brace">]</span></div>';
+            }
+            
+            let html = '<div class="item item-array">' +
+                '<span class="expand"></span>' +
+                '<span class="brace">[</span>' +
+                '<span class="ellipsis"></span>' +
+                '<div class="kv-list">';
+                
+            this.value.forEach((item, index) => {
+                let childNode = createNode(item);
+                
+                html += '<div class="item item-block">';
+                
+                // 添加值
+                if (childNode.type === 'object' || childNode.type === 'array') {
+                    html += childNode.getHTML();
+                } else {
+                    html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\/div>$/, '');
+                }
+                
+                // 如果不是最后一个元素,添加逗号
+                if (index < this.value.length - 1) {
+                    html += '<span class="comma">,</span>';
+                }
+                
+                html += '</div>';
+            });
+            
+            html += '</div><span class="brace">]</span></div>';
+            return html;
+        }
+    };
+    
+    return node;
+}
+
+// 获取值类型
+function getType(value) {
+    if (value === null) return 'null';
+    if (value === undefined) return 'undefined';
+    
+    let type = typeof value;
+    // 特别处理BigInt类型
+    if (type === 'bigint') return 'bigint';
+    if (type === 'object') {
+        if (Array.isArray(value)) return 'array';
+    }
+    return type;
+} 

+ 2 - 0
apps/manifest.json

@@ -56,6 +56,7 @@
             "json-format/json-abc.js",
             "json-format/json-bigint.js",
             "json-format/json-decode.js",
+            "json-format/json-worker.js",
             "static/vendor/jquery/jquery-3.3.1.min.js",
             "static/vendor/evalCore.min.js",
 
@@ -96,3 +97,4 @@
 }
 
 
+

+ 34 - 18
apps/options/settings.js

@@ -32,15 +32,20 @@ export default (() => {
     let _getOptions = function (callback) {
         let rst = {};
         chrome.storage.local.get(_getAllOpts(),(objs) => {
-            Object.keys(objs).forEach(item => {
-                let opt = objs[item];
-                if (opt !== null) {
-                    rst[item] = opt;
+            // 确保objs是一个对象
+            objs = objs || {};
+            
+            // 遍历所有配置项,确保每个配置项都有值
+            _getAllOpts().forEach(item => {
+                if (objs.hasOwnProperty(item) && objs[item] !== null) {
+                    rst[item] = objs[item];
                 } else {
+                    // 使用默认值
                     rst[item] = optionItemsWithDefaultValue[item];
                 }
             });
-            callback.call(null, rst);
+            
+            callback && callback.call(null, rst);
         });
     };
 
@@ -54,7 +59,7 @@ export default (() => {
         // 确保items是数组类型
         if (!Array.isArray(items)) {
             // 如果传入的是对象类型,转换为数组形式
-            if (typeof items === 'object') {
+            if (typeof items === 'object' && items !== null) {
                 let tempItems = [];
                 Object.keys(items).forEach(key => {
                     let obj = {};
@@ -68,19 +73,29 @@ export default (() => {
         }
 
         _getAllOpts().forEach((opt) => {
-            let found = items.some(it => {
-                if (typeof(it) === 'string' && it === opt) {
-                    chrome.storage.local.set({[opt]: 'true'});
-                    return true;
-                }
-                else if (typeof(it) === 'object' && it.hasOwnProperty(opt)) {
-                    chrome.storage.local.set({[opt]: it[opt]});
-                    return true;
+            try {
+                let found = items.some(it => {
+                    if (!it) return false;
+                    
+                    if (typeof(it) === 'string' && it === opt) {
+                        chrome.storage.local.set({[opt]: 'true'});
+                        return true;
+                    }
+                    else if (typeof(it) === 'object' && it !== null && it.hasOwnProperty(opt)) {
+                        chrome.storage.local.set({[opt]: it[opt]});
+                        return true;
+                    }
+                    return false;
+                });
+                if (!found) {
+                    chrome.storage.local.set({[opt]: 'false'});
                 }
-                return false;
-            });
-            if (!found) {
-                chrome.storage.local.set({[opt]: 'false'});
+            } catch (e) {
+                console.error('保存设置出错:', e, opt);
+                // 出错时设置为默认值
+                chrome.storage.local.set({
+                    [opt]: optionItemsWithDefaultValue[opt] === true ? 'true' : 'false'
+                });
             }
         });
 
@@ -93,3 +108,4 @@ export default (() => {
         setOptions: _setOptions
     };
 })();
+