فهرست منبع

完善devtools

[email protected] 2 سال پیش
والد
کامیت
879bff82f5

+ 4 - 4
apps/background/awesome.js

@@ -129,13 +129,10 @@ let Awesome = (() => {
     let getAllTools = async () => {
 
         // 获取本地开发的插件,也拼接进来
-        // TODO ..
         try {
             const DEV_TOOLS_MY_TOOLS = 'DEV-TOOLS:MY-TOOLS';
             let _tools = await StorageMgr.getSync(DEV_TOOLS_MY_TOOLS);
-            let localDevTools = JSON.parse(_tools || '{}', (key, val) => {
-                return val //String(val).indexOf('function') > -1 ? new Function(`return ${val}`)() : val;
-            });
+            let localDevTools = JSON.parse(_tools || '{}');
             Object.keys(localDevTools).forEach(tool => {
                 toolMap[tool] = localDevTools[tool];
             });
@@ -170,6 +167,9 @@ let Awesome = (() => {
                 });
                 return map;
             }
+            Object.keys(toolMap).forEach(tool => {
+                toolMap[tool].installed = toolMap[tool].offloadForbid;
+            });
             return toolMap;
         });
     };

+ 30 - 10
apps/background/background.js

@@ -63,23 +63,43 @@ let BgPageInstance = (function () {
     // 往当前页面直接注入脚本,不再使用content-script的配置了
     let _injectContentScripts = function (tabId) {
 
-        // 其他工具注入
+        // FH工具脚本注入
         Awesome.getInstalledTools().then(tools => {
 
             // 注入样式
-            let cssFiles = Object.keys(tools).filter(tool => tools[tool].contentScriptCss)
+            let cssFiles = Object.keys(tools)
+                            .filter(tool => !tools[tool]._devTool && tools[tool].contentScriptCss)
                             .map(tool => `${tool}/content-script.css`);
             InjectTools.inject(tabId, {files: cssFiles});
 
             // 注入js
-            let jsTools = Object.keys(tools).filter(tool => tools[tool].contentScriptJs || tools[tool].contentScript);
+            let jsTools = Object.keys(tools)
+                        .filter(tool => !tools[tool]._devTool
+                                && (tools[tool].contentScriptJs || tools[tool].contentScript));
             let jsCodes = [];
             jsTools.forEach((t, i) => {
                 let func = `window['${t.replace(/-/g, '')}ContentScript']`;
                 jsCodes.push(`(()=>{let func=${func};func&&func();})()`);
             });
             let jsFiles = jsTools.map(tool => `${tool}/content-script.js`);
-            InjectTools.inject(tabId, {files: jsFiles,code: jsCodes.join(';')});
+            InjectTools.inject(tabId, {files: jsFiles,js: jsCodes.join(';')});
+        });
+
+        // 其他开发者自定义工具脚本注入======For FH DevTools
+        Awesome.getInstalledTools().then(tools => {
+            let list = Object.keys(tools).filter(tool => tools[tool]._devTool);
+
+            // 注入css样式
+            list.filter(tool => tools[tool].contentScriptCss)
+                    .map(tool => Awesome.getContentScript(tool, true).then(css => {
+                        InjectTools.inject(tabId, { css });
+                    }));
+
+            // 注入js脚本
+            list.filter(tool => (tools[tool].contentScriptJs || tools[tool].contentScript))
+                    .map(tool => Awesome.getContentScript(tool).then(js => {
+                        InjectTools.inject(tabId, { js });
+                    }));
         });
     };
 
@@ -106,7 +126,7 @@ let BgPageInstance = (function () {
                 let found = tabs.some(tab => {
                     if (/^(http(s)?|file):\/\//.test(tab.url) && blacklist.every(reg => !reg.test(tab.url))) {
                         let codes = `window['${toolFunc}NoPage'] && window['${toolFunc}NoPage'](${JSON.stringify(tab)});`;
-                        InjectTools.inject(tab.id, {code: codes});
+                        InjectTools.inject(tab.id, {js: codes});
                         return true;
                     }
                     return false;
@@ -239,11 +259,11 @@ let BgPageInstance = (function () {
     let _colorPickerCapture = function(params) {
         chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
             chrome.tabs.captureVisibleTab(null, {format: 'png'}, function (dataUrl) {
-                let code = `window.colorpickerNoPage(${JSON.stringify({
+                let js = `window.colorpickerNoPage(${JSON.stringify({
                     setPickerImage: true,
                     pickerImage: dataUrl
                 })})`;
-                InjectTools.inject(tabs[0].id, { code });
+                InjectTools.inject(tabs[0].id, { js });
             });
         });
     };
@@ -252,8 +272,8 @@ let BgPageInstance = (function () {
         if (['javascript', 'css'].includes(params.fileType)) {
             Awesome.StorageMgr.get('JS_CSS_PAGE_BEAUTIFY').then(val => {
                 if(val !== '0') {
-                    let code = `window._codebutifydetect_('${params.fileType}')`;
-                    InjectTools.inject(params.tabId, { code });
+                    let js = `window._codebutifydetect_('${params.fileType}')`;
+                    InjectTools.inject(params.tabId, { js });
                 }
             });
         }
@@ -377,7 +397,7 @@ let BgPageInstance = (function () {
             if (String(changeInfo.status).toLowerCase() === "complete") {
 
                 if(/^(http(s)?|file):\/\//.test(tab.url) && blacklist.every(reg => !reg.test(tab.url))){
-                    InjectTools.inject(tabId, { code: `window.__FH_TAB_ID__=${tabId};` });
+                    InjectTools.inject(tabId, { js: `window.__FH_TAB_ID__=${tabId};` });
                     _injectContentScripts(tabId);
                 }
             }

+ 12 - 4
apps/background/inject-tools.js

@@ -17,7 +17,7 @@ export default (() => {
                         codeConfig.allFrames = String(opts['CONTENT_SCRIPT_ALLOW_ALL_FRAMES']) === 'true';
                     }
 
-                    codeConfig.code = 'try{' + codeConfig.code + ';}catch(e){};';
+                    codeConfig.js = 'try{' + codeConfig.js + ';}catch(e){};';
                     // 有文件就注入文件
                     if(codeConfig.files && codeConfig.files.length){
                         // 注入样式
@@ -38,18 +38,26 @@ export default (() => {
                                 chrome.scripting.executeScript({
                                     target: {tabId, allFrames: codeConfig.allFrames},
                                     func: function(code){evalCore.getEvalInstance(window)(code)},
-                                    args: [codeConfig.code]
+                                    args: [codeConfig.js]
                                 }, function () {
                                     callback && callback.apply(this, arguments);
                                 });
                             });
                         }
+                    }else if(codeConfig.css){
+                        // 注入css样式
+                        chrome.scripting.executeScript({
+                            target: {tabId, allFrames: codeConfig.allFrames},
+                            css:codeConfig.css
+                        }, function () {
+                            callback && callback.apply(this, arguments);
+                        });
                     }else{
-                        // 没有文件就只注入脚本
+                        // 注入js脚本
                         chrome.scripting.executeScript({
                             target: {tabId, allFrames: codeConfig.allFrames},
                             func: function(code){evalCore.getEvalInstance(window)(code)},
-                            args: [codeConfig.code]
+                            args: [codeConfig.js]
                         }, function () {
                             callback && callback.apply(this, arguments);
                         });

+ 1 - 1
apps/background/monkey.js

@@ -66,7 +66,7 @@ export default (() => {
                                 injectFunc();
                             }
                         }).toString() + `)(${JSON.stringify(result)})`;
-                        InjectTools.inject(params.tabId, {code: scripts, allFrames: false});
+                        InjectTools.inject(params.tabId, {js: scripts, allFrames: false});
                     }
                 });
             };

+ 1 - 0
apps/background/tools.js

@@ -4,6 +4,7 @@ let toolMap = {
         tips: '页面自动检测并格式化、手动格式化、乱码解码、排序、BigInt、编辑、下载、皮肤定制等',
         contentScriptJs: true,
         contentScriptCss: true,
+        offloadForbid: true,
         menuConfig: [{
             icon: '⒥',
             text: 'JSON格式化',

+ 17 - 0
apps/devtools/hello-world/content-script.js

@@ -0,0 +1,17 @@
+/**
+ * 注意这里的方法名称,其实是:window[`${toolName.replace(/[-_]/g,'')}ContentScript`];
+ * @author 阿烈叔
+ */
+window.helloworldContentScript = function () {
+    console.log('你好,我是来自FeHelper的工具Demo:hello world!');
+};
+
+/**
+ * 如果在 fh-config.js 中指定了 noPage参数为true,则这里必须定义noPage的接口方法,如:
+ * 注意这里的方法名称,其实是:window[`${toolName.replace(/[-_]/g,'')}NoPage`];
+ * @author 阿烈叔
+ */
+window.helloworldNoPage = function (tabInfo) {
+    alert('你好,我是来自FeHelper的工具Demo:hello world!你可以打开控制台看Demo的输出!');
+    console.log('你好,我是来自FeHelper的工具Demo:', tabInfo);
+};

+ 11 - 0
apps/devtools/hello-world/fh-config.js

@@ -0,0 +1,11 @@
+{
+    "hello-world": {
+        "name": "Hello world!",
+        "tips": "这是一个FH自定义工具的入门示例!一切都从Hello world开始,大家可体验,或下载后学习!",
+        "icon": "웃",
+        "noPage": true,
+        "contentScriptJs": true,
+        "contentScriptCss": false,
+        "minVersion": "2020.02.0718"
+    }
+}

+ 0 - 0
apps/hello-world/index.css → apps/devtools/hello-world/index.css


+ 0 - 0
apps/hello-world/index.html → apps/devtools/hello-world/index.html


+ 0 - 0
apps/hello-world/index.js → apps/devtools/hello-world/index.js


+ 2 - 1
apps/devtools/index.css

@@ -72,6 +72,7 @@ ul.box-tools li .x-btns {
 
 .given-icons h3 {
     color: #48b;
+    margin:0;
 }
 
 .given-icons .the-icons i {
@@ -276,4 +277,4 @@ ul.box-files li.x-tools:hover {
 
 [v-cloak] {
     display: none;
-}
+}

+ 2 - 2
apps/devtools/index.html

@@ -23,7 +23,7 @@
                 <button class="btn btn-primary" @click="addNewTool">开始我的第一个FH工具</button>
                 <button class="btn btn-default ui-ml-10" @click="loadTool(false)">载入本地工具包(*.zip)</button>
                 <button class="btn btn-default ui-ml-10" @click="addNewTool('url')">从远程服务载入工具</button>
-                <button class="btn btn-default ui-ml-10" @click="downloadTool()">下载Hello-world示例</button>
+                <button class="btn btn-default ui-ml-10" @click="downloadDemo()">下载Hello-world示例</button>
                 <button class="btn btn-default ui-ml-10" @click="givenIcons()">获取现成的图标</button>
                 <button class="btn btn-default ui-ml-10" @click="fhDeveloperDoc">FH工具开发文档</button>
 
@@ -41,7 +41,7 @@
                             <button class="btn btn-xs btn-success ui-ml-10" @click="upgrade(tool,true)" v-if="myTools[tool].updateUrl">URL更新</button>
                             <button class="btn btn-xs btn-primary ui-ml-10" @click="downloadTool(tool)">下载zip包</button>
                             <button class="btn btn-xs btn-primary ui-ml-10" @click="toggleEditor(true,tool)">编辑</button>
-                            <button class="btn btn-xs btn-danger ui-ml-10" :disabled="tool==='hello-world'" @click="delToolConfigs(tool)">删除</button>
+                            <button class="btn btn-xs btn-danger ui-ml-10" :disabled="tool===demo.name" @click="delToolConfigs(tool)">删除</button>
                             <button class="btn btn-xs ui-fl-r" :class="myTools[tool]._enable ? 'btn-success' : 'btn-warning'" @click="toggleToolEnableStatus(tool)">{{myTools[tool]._enable ? '启用中' : '已停用'}}</button>
                         </div>
                     </li>

+ 30 - 12
apps/devtools/index.js

@@ -17,16 +17,19 @@ new Vue({
         givenIconList: [],
         model: {},
         demo: {
-            name: 'fh-dev-demo',
+            name: 'hello-world',
             files: ['fh-config.js', 'index.html', 'index.js', 'index.css', 'content-script.js']
         }
     },
     mounted: function () {
         // 本地没安装过demo,就强制再更新一遍
-        this.getContentFromLocal('hello-world', 'index.html').then(content => {
-            !content && this.loadDemo();
+        this.getContentFromLocal(this.demo.name, 'index.html').then(content => {
+            if(content) {
+                this.getToolConfigs();
+            }else{
+                this.loadDemo().then(() => this.getToolConfigs());
+            }
         });
-        this.getToolConfigs();
     },
 
     methods: {
@@ -55,7 +58,7 @@ new Vue({
                         editor.on('change', (editor, changes) => {
                             let result = this.saveContentToLocal(this.model.tool, this.model.editingFile, editor.getValue());
                             if (this.model.editingFile === 'fh-config.js' && result) {
-                                result.contentScript && !this.model.files.includes('content-script.js') && this.model.files.push('content-script.js');
+                                result.contentScriptJs && !this.model.files.includes('content-script.js') && this.model.files.push('content-script.js');
                                 result.contentScriptCss && !this.model.files.includes('content-script.css') && this.model.files.push('content-script.css');
                                 this.$forceUpdate();
                             }
@@ -272,7 +275,7 @@ new Vue({
                                     this.saveContentToLocal(toolName, fs[0], txt);
 
                                     // 保存content-script / background-script
-                                    if (toolObj.contentScript && fs[0].indexOf(toolName + '/content-script.js') !== -1) {
+                                    if (toolObj.contentScriptJs && fs[0].indexOf(toolName + '/content-script.js') !== -1) {
                                         this.saveContentToLocal(toolName, 'content-script.js', txt);
 
                                         // 存储content-script.css文件内容
@@ -304,12 +307,12 @@ new Vue({
         loadDemo() {
             let demoName = this.demo.name;
             let files = this.demo.files;
-            let site = '../';
-            if (window.chrome && chrome.runtime && chrome.runtime.getManifest) {
-                site = chrome.runtime.getManifest().homepage_url;
+            let site = '.';
+            if (window.chrome && chrome.runtime && chrome.runtime.getURL) {
+                site = chrome.runtime.getURL('devtools');
             }
             let arrPromise = files.map(file => fetch(`${site}/${demoName}/${file}`).then(resp => resp.text()));
-            Promise.all(arrPromise).then(contents => {
+            return Promise.all(arrPromise).then(contents => {
                 // fh-config.js
                 let json = JSON.parse(contents[0]);
                 this.addToolConfigs(json);
@@ -351,8 +354,19 @@ new Vue({
             });
         },
 
+        downloadDemo() {
+            // 本地没安装过demo,就强制再更新一遍
+            this.getContentFromLocal(this.demo.name, 'index.html').then(content => {
+                if(content) {
+                    this.downloadTool(this.demo.name);
+                }else{
+                    this.loadDemo().then(() => this.downloadTool(this.demo.name));
+                }
+            });
+        },
+
         upgrade(tool, urlMode) {
-            if (tool === 'hello-world') {
+            if (tool === this.demo.name) {
                 this.loadDemo();
             } else if (urlMode) {
                 // 远程下载并安装工具
@@ -450,6 +464,10 @@ new Vue({
                         this.myTools.icon = this.myTools[t].menuConfig[0].icon;
                         delete this.myTools[t].menuConfig;
                     }
+                    if(this.myTools[t].contentScript) {
+                        this.myTools[t].contentScriptJs = this.myTools[t].contentScript;
+                        delete this.myTools[t].contentScript;
+                    }
                     if(!this.myTools[t].icon) {
                         this.myTools[t].icon = '◆';
                     }
@@ -520,7 +538,7 @@ new Vue({
             return new Promise(resolve => {
                 let files = ['fh-config.js', 'index.html'];
                 let toolObj = this.myTools[toolName];
-                toolObj.contentScript && files.push('content-script.js');
+                toolObj.contentScriptJs && files.push('content-script.js');
                 toolObj.contentScriptCss && files.push('content-script.css');
 
                 chrome.storage.local.get(null, allDatas => {

+ 0 - 41
apps/hello-world/content-script.js

@@ -1,41 +0,0 @@
-/**
- * 注意这里的方法名称,其实是:window[`${toolName.replace(/[-_]/g,'')}ContentScript`];
- * @author 阿烈叔
- */
-window.helloworldContentScript = function () {
-    console.log('你好,我是来自FeHelper的工具Demo:hello world!');
-};
-
-/**
- * 如果在 fh-config.js 中指定了 noPage参数为true,则这里必须定义noPage的接口方法,如:
- * 注意这里的方法名称,其实是:window[`${toolName.replace(/[-_]/g,'')}NoPage`];
- * @author 阿烈叔
- */
-window.helloworldNoPage = function (tabInfo) {
-    alert('你好,我是来自FeHelper的工具Demo:hello world!你可以打开控制台看Demo的输出!');
-    console.log('你好,我是来自FeHelper的工具Demo:', tabInfo);
-
-    // background 示例:获取当前浏览器的所有tab
-    chrome.runtime.sendMessage({
-        type: 'fh-dynamic-any-thing',
-        params: {
-            tabId: window.__FH_TAB_ID__ // 这是FH的内置变量,表示当前Tab的id
-        },
-        func: ((params, callback) => {
-            // TODO: 这里可以调用 chrome.* 的API,随便用。。。
-
-            // Case1:获取当前窗口的全部tab
-            chrome.tabs.query({currentWindow: true}, tabs => {
-                let jsonInfo = JSON.stringify(tabs);
-
-                // 注入到页面,注意看这里如何读取外面传进来的参数
-                chrome.tabs.executeScript(params.tabId, {
-                    code: 'console.log(' + jsonInfo + ');'
-                });
-            });
-
-            callback && callback();
-            return true;
-        }).toString()
-    });
-};

+ 0 - 23
apps/hello-world/fh-config.js

@@ -1,23 +0,0 @@
-(function () {
-    return {
-        "hello-world": {
-            "name": "Hello world!",      // 工具的名称
-            "tips": "这是一个FH自定义工具的入门示例!一切都从Hello world开始,大家可体验,或下载后学习!", // 工具描述
-            "noPage": true,             // true表示此工具无独立页面
-            "contentScript": true,      // 是否有内容注入的脚本
-            "contentScriptCss": false,  // 是否注入Css
-            "minVersion": "2020.02.0718", // 工具从FeHelper的哪个版本开始支持
-            "menuConfig": [{            // 可以配置多个右键菜单
-                "icon": "웃",            // 右键菜单的icon,也是工具的默认icon
-                "text": "Hello world",  // 右键菜单中的工具名称
-                "onClick": function (info, tab) {
-                    alert('你好,我是Hello world;这是一个无独立页面的功能,我的内容已经输出到控制台了哦!');
-                    chrome.DynamicToolRunner({
-                        query: "tool=hello-world",
-                        noPage: true
-                    });
-                }
-            }]
-        }
-    };
-})();

+ 1 - 1
apps/manifest.json

@@ -89,5 +89,5 @@
       "extension_pages": "script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'self'"
   },
   "update_url": "https://clients2.google.com/service/update2/crx",
-  "homepage_url": "http://localhost/FeOnline/output/fehelper"
+  "homepage_url": "https://www.baidufe.com/fehelper"
 }

+ 3 - 2
apps/options/index.html

@@ -109,7 +109,8 @@
 
                     <span class="ui-fl-r x-btn-box">
                         <button class="btn btn-success btn-xs" @click="install(tool,$event)" v-if="!fhTools[tool].installed">安装<span class="x-progress"></span></button>
-                        <button class="btn btn-danger btn-xs" @click="offLoad(tool,$event)" v-if="fhTools[tool].installed">卸载</button>
+                        <button class="btn btn-danger btn-xs" @click="offLoad(tool,$event)" v-if="fhTools[tool].installed && !fhTools[tool].offloadForbid">卸载</button>
+                        <button class="btn btn-disabled btn-xs" v-if="fhTools[tool].installed && fhTools[tool].offloadForbid" title="系统预装,不可被卸载">卸载</button>
                         <button class="btn btn-xs" :class="fhTools[tool].menu ? 'btn-warning' : 'btn-info'" @click="menuMgr(tool,$event)" v-if="fhTools[tool].installed">{{fhTools[tool].menu ? '移出' : '加入'}}右键</button>
                     </span>
 
@@ -134,7 +135,7 @@
                     <span class="ui-fl-r x-btn-box">
                         <template v-if="tool === 'devtools'">
                             <button class="btn btn-danger btn-xs" @click="install(tool,$event)" v-if="!fhTools[tool].installed">安装<span class="x-progress"></span></button>
-                            <button class="btn btn-danger btn-xs" @click="offLoad(tool,$event)" v-if="fhTools[tool].installed && !fhTools[tool].offloadForbid">卸载</button>
+                            <button class="btn btn-danger btn-xs" @click="offLoad(tool,$event)" v-if="fhTools[tool].installed">卸载</button>
                             <button class="btn btn-xs" :class="fhTools[tool].menu ? 'btn-warning' : 'btn-info'" @click="menuMgr(tool,$event)" v-if="fhTools[tool].installed">{{fhTools[tool].menu ? '移出' : '加入'}}右键</button>
                         </template>
 

+ 1 - 1
apps/options/index.js

@@ -128,7 +128,7 @@ new Vue({
         remoteHotFix: function () {
             let hotfix = () => {
                 // 从服务器同步最新添加的一些工具,实现远程更新,无需提审FeHelper
-                let remoteHotfixUrl = `${this.manifest.homepage_url}/static/js/hotfix.js?time=${new Date().toLocaleDateString()}`;
+                let remoteHotfixUrl = `${this.manifest.homepage_url}/static/js/hotfix.js?cur_ver=${new Date().toLocaleDateString()}`;
                 fetch(remoteHotfixUrl).then(resp => resp.text()).then(jsText => {
                     try {
                         if (!jsText) return false;