[add] first
This commit is contained in:
		
							
								
								
									
										60
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					# Cocos Creater OutputComponent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 插件 安裝方式
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. 安裝在 **項目** 底下
 | 
				
			||||||
 | 
					> 把插件資料夾放到項目的packages(跟assets同層)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. 安裝在 **全局** 底下
 | 
				
			||||||
 | 
					> 把插件資料夾放到C:\Users\%USERNAME%\.CocosCreator\packages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 插件稍微說明(都是搬過來的資料  XD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					剩下沒寫的可以到參考資料裡面看看😀
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. 定義你的包描述文件:**package.json**
 | 
				
			||||||
 | 
					> **name** String - 定義了包的名字,包的名字是全局唯一的,他關係到你今後在官網服務器上登錄時的名字。
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> **version** String - 版本號,我們推薦使用semver格式管理你的包版本。
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> **description** String(可选) - 一句話描述你的包是做什麼的。
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> **author** String(可选) - 擴展包的作者
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> **main** String (可选) - 入口程序
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> **scene-script** String (可选) - 調用引擎API 和項目腳本
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> **main-menu** Object (可选) - 主菜單定義
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> **有要使用介面的話:**
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> **panel** Object (可选) - 定義的面板在package裡的描述
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> **注意panel的type有兩種:**
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> dockable:可停靠面板,打開該面板後,可以通過拖拽面板標籤到編輯器裡,實現擴展面板嵌入到編輯器中。下面我們介紹的面板入口程序都是按照可停靠面板的要求聲明的。
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> simple:簡單Web面板,不可停靠到編輯器主窗口,相當於一份通用的HTML前端頁面。詳細情況請見定義簡單面板。
 | 
				
			||||||
 | 
					> 
 | 
				
			||||||
 | 
					> 在simple-package文件夾下面創建一個panel文件夾,然後在panel文件夾下創建一個index.js或者一個html文件都可以
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. 入口程序:**main.js**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. 定義介面以及按鈕綁定的方法,和主進程的通信:**index.js**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. 可以使用包括全部引擎API 和用戶組件腳本里聲明的方法和屬性:**scene-obtain..js**
 | 
				
			||||||
 | 
					> 可以在擴展包中獲取到場景裡的Canvas根節點有多少子節點,當然還可以用來對場景節點進行更多的查詢和操作。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 參考資料
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* 你的第一個擴展包
 | 
				
			||||||
 | 
					> https://docs.cocos.com/creator/manual/zh/extension/your-first-extension.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* CocosCreator拓展编辑器
 | 
				
			||||||
 | 
					> https://blog.csdn.net/qq_34772097/category_9577457.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Cocos Creator Editor 編輯器擴展API記錄
 | 
				
			||||||
 | 
					> https://blog.csdn.net/kingbook928/article/details/108659319
 | 
				
			||||||
 | 
					> https://blog.csdn.net/qq_17209641/article/details/106822296
 | 
				
			||||||
 | 
					> https://forum.cocos.org/t/creator-api/92605
 | 
				
			||||||
							
								
								
									
										136
									
								
								core/FileUtil.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								core/FileUtil.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
				
			|||||||
 | 
					let fs = require("fire-fs");
 | 
				
			||||||
 | 
					let path = require("fire-path");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let self = module.exports = {
 | 
				
			||||||
 | 
					    getDirAllFiles(dirPath, result) {
 | 
				
			||||||
 | 
					        let files = fs.readdirSync(dirPath);
 | 
				
			||||||
 | 
					        files.forEach((val, index) => {
 | 
				
			||||||
 | 
					            let fPath = path.join(dirPath, val);
 | 
				
			||||||
 | 
					            let stats = fs.statSync(fPath);
 | 
				
			||||||
 | 
					            if (stats.isDirectory()) {
 | 
				
			||||||
 | 
					                this.getDirAllFiles(fPath, result);
 | 
				
			||||||
 | 
					            } else if (stats.isFile()) {
 | 
				
			||||||
 | 
					                result.push(fPath);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    getFileString(fileList, options) {
 | 
				
			||||||
 | 
					        let curIndex = 0;
 | 
				
			||||||
 | 
					        let totalIndex = fileList.length;
 | 
				
			||||||
 | 
					        let str = {};
 | 
				
			||||||
 | 
					        for (let key in  fileList) {
 | 
				
			||||||
 | 
					            let filePath = fileList[key];
 | 
				
			||||||
 | 
					            let b = this._isFileExit(filePath);
 | 
				
			||||||
 | 
					            if (b) {
 | 
				
			||||||
 | 
					                fs.readFile(filePath, 'utf-8', function (err, data) {
 | 
				
			||||||
 | 
					                    if (!err) {
 | 
				
			||||||
 | 
					                        self._collectString(data, str);
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        console.log("error: " + filePath);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    self._onCollectStep(filePath, ++curIndex, totalIndex, str, options);
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                self._onCollectStep(filePath, ++curIndex, totalIndex, str, options);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    _onCollectStep(filePath, cur, total, str, data) {
 | 
				
			||||||
 | 
					        if (data && data.stepCb) {
 | 
				
			||||||
 | 
					            data.stepCb(filePath, cur, total);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (cur >= total) {
 | 
				
			||||||
 | 
					            self._onCollectOver(str, data);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    _onCollectOver(collectObjArr, data) {
 | 
				
			||||||
 | 
					        let strArr = [];
 | 
				
			||||||
 | 
					        let str = "";
 | 
				
			||||||
 | 
					        for (let k in collectObjArr) {
 | 
				
			||||||
 | 
					            str += k;
 | 
				
			||||||
 | 
					            strArr.push(k);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // console.log("一共有" + strArr.length + "个字符, " + strArr);
 | 
				
			||||||
 | 
					        console.log("一共有" + strArr.length + "个字符");
 | 
				
			||||||
 | 
					        if (data && data.compCb) {
 | 
				
			||||||
 | 
					            data.compCb(str);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    mkDir(path) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            fs.mkdirSync(path);
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					            if (e.code !== 'EEXIST') throw e;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    isFileExit(file) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            fs.accessSync(file, fs.F_OK);
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    _collectString(data, collectObject) {
 | 
				
			||||||
 | 
					        for (let i in data) {
 | 
				
			||||||
 | 
					            let char = data.charAt(i);
 | 
				
			||||||
 | 
					            if (collectObject[char]) {
 | 
				
			||||||
 | 
					                collectObject[char]++;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                collectObject[char] = 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    emptyDir(rootFile) {
 | 
				
			||||||
 | 
					        //删除所有的文件(将所有文件夹置空)
 | 
				
			||||||
 | 
					        let emptyDir = function (fileUrl) {
 | 
				
			||||||
 | 
					            let files = fs.readdirSync(fileUrl);//读取该文件夹
 | 
				
			||||||
 | 
					            for (let k in files) {
 | 
				
			||||||
 | 
					                let filePath = path.join(fileUrl, files[k]);
 | 
				
			||||||
 | 
					                let stats = fs.statSync(filePath);
 | 
				
			||||||
 | 
					                if (stats.isDirectory()) {
 | 
				
			||||||
 | 
					                    emptyDir(filePath);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    fs.unlinkSync(filePath);
 | 
				
			||||||
 | 
					                    console.log("删除文件:" + filePath);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        //删除所有的空文件夹
 | 
				
			||||||
 | 
					        let rmEmptyDir = function (fileUrl) {
 | 
				
			||||||
 | 
					            let files = fs.readdirSync(fileUrl);
 | 
				
			||||||
 | 
					            if (files.length > 0) {
 | 
				
			||||||
 | 
					                for (let k in files) {
 | 
				
			||||||
 | 
					                    let rmDir = path.join(fileUrl, files[k]);
 | 
				
			||||||
 | 
					                    rmEmptyDir(rmDir);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (fileUrl !== rootFile) {// 不删除根目录
 | 
				
			||||||
 | 
					                    fs.rmdirSync(fileUrl);
 | 
				
			||||||
 | 
					                    console.log('删除空文件夹' + fileUrl);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                if (fileUrl !== rootFile) {// 不删除根目录
 | 
				
			||||||
 | 
					                    fs.rmdirSync(fileUrl);
 | 
				
			||||||
 | 
					                    console.log('删除空文件夹' + fileUrl);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        emptyDir(rootFile);
 | 
				
			||||||
 | 
					        rmEmptyDir(rootFile);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					        is_fileType($('#uploadfile').val(), 'doc,pdf,txt,wps,odf,md,png,gif,jpg')
 | 
				
			||||||
 | 
					    * */
 | 
				
			||||||
 | 
					    is_fileType(filename, types) {
 | 
				
			||||||
 | 
					        types = types.split(',');
 | 
				
			||||||
 | 
					        let pattern = '\.(';
 | 
				
			||||||
 | 
					        for (let i = 0; i < types.length; i++) {
 | 
				
			||||||
 | 
					            if (0 !== i) {
 | 
				
			||||||
 | 
					                pattern += '|';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            pattern += types[i].trim();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        pattern += ')$';
 | 
				
			||||||
 | 
					        return new RegExp(pattern, 'i').test(filename);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										55
									
								
								i18n/en.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								i18n/en.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    'name': 'References Finder',
 | 
				
			||||||
 | 
					    'find': 'Find Current Selected',
 | 
				
			||||||
 | 
					    'find-panel': 'Find Panel',
 | 
				
			||||||
 | 
					    'settings': 'Settings',
 | 
				
			||||||
 | 
					    'check-update': 'Check Update',
 | 
				
			||||||
 | 
					    // update
 | 
				
			||||||
 | 
					    'current-latest': 'Currently the latest version!',
 | 
				
			||||||
 | 
					    'has-new-version': 'New version found!',
 | 
				
			||||||
 | 
					    'local-version': 'Local version: ',
 | 
				
			||||||
 | 
					    'latest-version': 'Latest version: ',
 | 
				
			||||||
 | 
					    'git-releases': 'Releases: https://gitee.com/ifaswind/ccc-references-finder/releases',
 | 
				
			||||||
 | 
					    'cocos-store': 'Cocos Store: https://store.cocos.com/app/detail/2531',
 | 
				
			||||||
 | 
					    // main
 | 
				
			||||||
 | 
					    'please-select-assets': 'Please select asset(s) in Asset Panel first',
 | 
				
			||||||
 | 
					    'invalid-uuid': 'Invalid uuid',
 | 
				
			||||||
 | 
					    'not-support-folder': 'Does not support folder',
 | 
				
			||||||
 | 
					    'find-asset-refs': 'Find references',
 | 
				
			||||||
 | 
					    'no-refs': 'No references found',
 | 
				
			||||||
 | 
					    'scene': 'Scene',
 | 
				
			||||||
 | 
					    'prefab': 'Prefab',
 | 
				
			||||||
 | 
					    'animation': 'Animation',
 | 
				
			||||||
 | 
					    'material': 'Material',
 | 
				
			||||||
 | 
					    'font': 'Font',
 | 
				
			||||||
 | 
					    'node': 'Node',
 | 
				
			||||||
 | 
					    'component': 'Component',
 | 
				
			||||||
 | 
					    'property': 'Property',
 | 
				
			||||||
 | 
					    'result': 'Reference result',
 | 
				
			||||||
 | 
					    'node-refs': 'Node References',
 | 
				
			||||||
 | 
					    'asset-refs': 'Asset References',
 | 
				
			||||||
 | 
					    'asset-info': 'Asset Info',
 | 
				
			||||||
 | 
					    'asset-type': 'Type: ',
 | 
				
			||||||
 | 
					    'asset-uuid': 'Uuid: ',
 | 
				
			||||||
 | 
					    'asset-url': 'Url: ',
 | 
				
			||||||
 | 
					    'asset-path': 'Path: ',
 | 
				
			||||||
 | 
					    // settings
 | 
				
			||||||
 | 
					    'none': 'None',
 | 
				
			||||||
 | 
					    'select-key': 'Hotkey',
 | 
				
			||||||
 | 
					    'select-key-tooltip': 'Chose a hotkey to open the search bar quickly',
 | 
				
			||||||
 | 
					    'custom-key': 'Custom',
 | 
				
			||||||
 | 
					    'custom-key-placeholder': 'Choose a hotkey above or customize one by yourself',
 | 
				
			||||||
 | 
					    'custom-key-tooltip': 'You can also customize your own hotkey',
 | 
				
			||||||
 | 
					    'auto-check-update': 'Auto Check Update',
 | 
				
			||||||
 | 
					    'auto-check-update-tooltip': 'Check if there is a new version when the extension is loaded',
 | 
				
			||||||
 | 
					    'reference': '· Hotkey customization reference: ',
 | 
				
			||||||
 | 
					    'accelerator': 'Keyboard Shortcuts',
 | 
				
			||||||
 | 
					    'repository': '· Git repository of this extension: ',
 | 
				
			||||||
 | 
					    'apply': 'Apply',
 | 
				
			||||||
 | 
					    'quote-error': 'Do not use double quotes!',
 | 
				
			||||||
 | 
					    'custom-key-error': 'Please specify a hotkey!',
 | 
				
			||||||
 | 
					    'print-details': 'Show Details',
 | 
				
			||||||
 | 
					    'print-details-tooltip': 'Show more details(node, component, property)',
 | 
				
			||||||
 | 
					    'print-folding': 'Fold Result',
 | 
				
			||||||
 | 
					    'print-folding-tooltip': 'Fold result in one log',
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										55
									
								
								i18n/zh.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								i18n/zh.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    'name': '引用查找器',
 | 
				
			||||||
 | 
					    'find': '查找当前选中资源',
 | 
				
			||||||
 | 
					    'find-panel': '查找面板',
 | 
				
			||||||
 | 
					    'settings': '设置',
 | 
				
			||||||
 | 
					    'check-update': '检查更新',
 | 
				
			||||||
 | 
					    // update
 | 
				
			||||||
 | 
					    'current-latest': '当前已是最新版本!',
 | 
				
			||||||
 | 
					    'has-new-version': '发现新版本!',
 | 
				
			||||||
 | 
					    'local-version': '本地版本:',
 | 
				
			||||||
 | 
					    'latest-version': '最新版本:',
 | 
				
			||||||
 | 
					    'git-releases': '发行版:https://gitee.com/ifaswind/ccc-references-finder/releases',
 | 
				
			||||||
 | 
					    'cocos-store': 'Cocos 商店:https://store.cocos.com/app/detail/2531',
 | 
				
			||||||
 | 
					    // main
 | 
				
			||||||
 | 
					    'please-select-assets': '请先在资源管理器中选择需要查找引用的资源',
 | 
				
			||||||
 | 
					    'invalid-uuid': '无效的 uuid',
 | 
				
			||||||
 | 
					    'not-support-folder': '暂不支持查找文件夹',
 | 
				
			||||||
 | 
					    'find-asset-refs': '查找资源引用',
 | 
				
			||||||
 | 
					    'no-refs': '没有找到该资源的引用',
 | 
				
			||||||
 | 
					    'scene': '场景',
 | 
				
			||||||
 | 
					    'prefab': '预制体',
 | 
				
			||||||
 | 
					    'animation': '动画',
 | 
				
			||||||
 | 
					    'material': '材质',
 | 
				
			||||||
 | 
					    'font': '字体',
 | 
				
			||||||
 | 
					    'node': '节点',
 | 
				
			||||||
 | 
					    'component': '组件',
 | 
				
			||||||
 | 
					    'property': '属性',
 | 
				
			||||||
 | 
					    'result': '引用查找结果',
 | 
				
			||||||
 | 
					    'node-refs': '节点引用',
 | 
				
			||||||
 | 
					    'asset-refs': '资源引用',
 | 
				
			||||||
 | 
					    'asset-info': '资源信息',
 | 
				
			||||||
 | 
					    'asset-type': 'Type:',
 | 
				
			||||||
 | 
					    'asset-uuid': 'Uuid:',
 | 
				
			||||||
 | 
					    'asset-url': 'Url:',
 | 
				
			||||||
 | 
					    'asset-path': 'Path:',
 | 
				
			||||||
 | 
					    // settings
 | 
				
			||||||
 | 
					    'none': '无',
 | 
				
			||||||
 | 
					    'select-key': '快捷键',
 | 
				
			||||||
 | 
					    'select-key-tooltip': '选择一个快速打开搜索栏的快捷键',
 | 
				
			||||||
 | 
					    'custom-key': '自定义',
 | 
				
			||||||
 | 
					    'custom-key-placeholder': '在上方选择一个快捷键或自定义一个快捷键',
 | 
				
			||||||
 | 
					    'custom-key-tooltip': '自定义快速打开搜索栏的快捷键',
 | 
				
			||||||
 | 
					    'auto-check-update': '自动检查更新',
 | 
				
			||||||
 | 
					    'auto-check-update-tooltip': '扩展启动时自动检查是否有新版本',
 | 
				
			||||||
 | 
					    'reference': '· 快捷键自定义请参考:',
 | 
				
			||||||
 | 
					    'accelerator': '键盘快捷键',
 | 
				
			||||||
 | 
					    'repository': '· 本扩展的 Git 仓库:',
 | 
				
			||||||
 | 
					    'apply': '应用',
 | 
				
			||||||
 | 
					    'quote-error': '请勿使用双引号!',
 | 
				
			||||||
 | 
					    'custom-key-error': '请指定一个快捷键!',
 | 
				
			||||||
 | 
					    'print-details': '展示详情',
 | 
				
			||||||
 | 
					    'print-details-tooltip': '引用查找结果精确到节点、组件和属性',
 | 
				
			||||||
 | 
					    'print-folding': '折叠结果',
 | 
				
			||||||
 | 
					    'print-folding-tooltip': '引用查找结果将需要手动展开,拯救你的控制台',
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										1649
									
								
								lib/node-fetch.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1649
									
								
								lib/node-fetch.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										7
									
								
								lib/vue.global.prod.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								lib/vue.global.prod.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										174
									
								
								main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								main.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
				
			|||||||
 | 
					"use strict";
 | 
				
			||||||
 | 
					let fs = require("fs");
 | 
				
			||||||
 | 
					let path = require("path");
 | 
				
			||||||
 | 
					const FileUtil = require('./core/FileUtil');
 | 
				
			||||||
 | 
					const { print, translate } = require('./src/eazax/editor-main-util');
 | 
				
			||||||
 | 
					const EditorAPI = require('./src/main/editor-api');
 | 
				
			||||||
 | 
					const Parser = require('./src/main/parser');
 | 
				
			||||||
 | 
					const Finder = require('./src/main/finder');
 | 
				
			||||||
 | 
					const Printer = require('./src/main//printer');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    load() {
 | 
				
			||||||
 | 
					        this.init();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    unload() {
 | 
				
			||||||
 | 
					        // Editor.log("卸載執行");
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    /** 初始化 */
 | 
				
			||||||
 | 
					    init() {
 | 
				
			||||||
 | 
					        // this.createDirectory();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    /** 創建Spine節點 */
 | 
				
			||||||
 | 
					    sourcecheck(...args) {
 | 
				
			||||||
 | 
					        let self = this;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // Editor.log("文件1: " + JSON.stringify(args[0]._value));
 | 
				
			||||||
 | 
					            Editor.Scene.callSceneScript("sourcecheck", "getFsPath", { args: args }, async function (err, response) {
 | 
				
			||||||
 | 
					                // Editor.log("getFsPath response: " + response);
 | 
				
			||||||
 | 
					                let res = JSON.parse(response);
 | 
				
			||||||
 | 
					                if (!FileUtil.isFileExit(res.fsPath)) {
 | 
				
			||||||
 | 
					                    Editor.error(`路徑錯誤: ${res.fsPath}`);
 | 
				
			||||||
 | 
					                    Editor.log(`檢查停止`);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Editor.log(`檢查路徑: ${res.url}`);
 | 
				
			||||||
 | 
					                let files = [];
 | 
				
			||||||
 | 
					                files = self.fileSearch(res.fsPath, res.url, files);
 | 
				
			||||||
 | 
					                // Editor.log(`總共有${files.length}個物件`);
 | 
				
			||||||
 | 
					                for (let i = 0; i < files.length; i++) {
 | 
				
			||||||
 | 
					                    // for (let i = 0; i < 1; i++) {
 | 
				
			||||||
 | 
					                    await self.checkreq(files[i][0], files[i][1]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Editor.log(`檢查完畢`);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        } catch (error) {
 | 
				
			||||||
 | 
					            Editor.log(`sourcecheck error: ${error}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @param fsPath fsPath
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fileSearch(fsPath, url, files) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // Editor.log(`fsPath: ${fsPath}`);
 | 
				
			||||||
 | 
					            if (FileUtil.isFileExit(fsPath)) {
 | 
				
			||||||
 | 
					                fs.readdirSync(fsPath).forEach(file => {
 | 
				
			||||||
 | 
					                    // Editor.log(`file: ${file}`);
 | 
				
			||||||
 | 
					                    let path = `${fsPath}\\${file}`
 | 
				
			||||||
 | 
					                    if (this.checkfile(path)) {
 | 
				
			||||||
 | 
					                        files = this.fileSearch(path, url, files);
 | 
				
			||||||
 | 
					                    } else if (this.checkusefile(path)) {
 | 
				
			||||||
 | 
					                        // this.checkreq(path, url);
 | 
				
			||||||
 | 
					                        files.push([path, url])
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                return files;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // Editor.error(`fsPath error: ${fsPath}`);
 | 
				
			||||||
 | 
					                return files;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (error) {
 | 
				
			||||||
 | 
					            Editor.error(`fileSearch error: ${error}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 檢查引用
 | 
				
			||||||
 | 
					     * @param fsPath fsPath
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async checkreq(fsPath, myurl) {
 | 
				
			||||||
 | 
					        // Editor.log(`file: ${fsPath}`);
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            let uuid = EditorAPI.fspathToUuid(fsPath);
 | 
				
			||||||
 | 
					            // Editor.log(`uuid: ${uuid}, file: ${fsPath}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const assetInfo = EditorAPI.assetInfoByUuid(uuid),
 | 
				
			||||||
 | 
					                shortUrl = assetInfo.url.replace('db://', '');
 | 
				
			||||||
 | 
					            // 查找引用
 | 
				
			||||||
 | 
					            // print('log', '🔍', `${translate('find-asset-refs')} ${shortUrl}`);
 | 
				
			||||||
 | 
					            let refs = null;
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                refs = await Finder.findByUuid(uuid);
 | 
				
			||||||
 | 
					            } catch (error) {
 | 
				
			||||||
 | 
					                Editor.error(`findByUuid error: ${error}, fsPath: ${fsPath}`);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // Editor.log(`refs: ${JSON.stringify(refs)}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let newrefs = [];
 | 
				
			||||||
 | 
					            for (let i = 0; i < refs.length; i++) {
 | 
				
			||||||
 | 
					                let ref = refs[i];
 | 
				
			||||||
 | 
					                let url = ref.url;
 | 
				
			||||||
 | 
					                if (url.indexOf(myurl) === -1) {
 | 
				
			||||||
 | 
					                    // Editor.log(`url: ${url}, myurl: ${myurl}, fsPath: ${EditorAPI.fspathToUrl(fsPath)}`);
 | 
				
			||||||
 | 
					                    newrefs.push(ref);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (newrefs.length > 0) {
 | 
				
			||||||
 | 
					                // 打印结果
 | 
				
			||||||
 | 
					                Printer.printResult({
 | 
				
			||||||
 | 
					                    type: assetInfo.type,
 | 
				
			||||||
 | 
					                    uuid: uuid,
 | 
				
			||||||
 | 
					                    url: assetInfo.url,
 | 
				
			||||||
 | 
					                    path: assetInfo.path,
 | 
				
			||||||
 | 
					                    refs: newrefs,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (error) {
 | 
				
			||||||
 | 
					            Editor.error(`checkreq error: ${error}, fsPath: ${fsPath}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 檢查副檔名
 | 
				
			||||||
 | 
					     * @param fsPath fsPath
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    checkusefile(fsPath) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            if ((fsPath.indexOf(".PNG") !== -1 || fsPath.indexOf(".png") !== -1 || fsPath.indexOf(".jpg") !== -1 || fsPath.indexOf(".anim") !== -1 || fsPath.indexOf(".fnt") !== -1) && fsPath.indexOf(".meta") === -1) {
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        } catch (error) {
 | 
				
			||||||
 | 
					            Editor.error(`checkfile error: ${error}`);
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 檢查副檔名
 | 
				
			||||||
 | 
					     * @param fsPath fsPath
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    checkfile(fsPath) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            if (fsPath.indexOf(".fire") === -1 && fsPath.indexOf(".fnt") === -1 && fsPath.indexOf(".anim") === -1 && fsPath.indexOf(".prefab") === -1 && fsPath.indexOf(".meta") === -1 && fsPath.indexOf(".pac") === -1 && fsPath.indexOf(".PNG") === -1 && fsPath.indexOf(".png") === -1 && fsPath.indexOf(".jpg") === -1) {
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        } catch (error) {
 | 
				
			||||||
 | 
					            Editor.error(`checkfile error: ${error}`);
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    messages: {
 | 
				
			||||||
 | 
					        /** 打開面板 */
 | 
				
			||||||
 | 
					        "open-panel"() {
 | 
				
			||||||
 | 
					            Editor.Panel.open("sourcecheck");
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        /** 保存按鈕點擊 */
 | 
				
			||||||
 | 
					        "run-click"(event, ...args) {
 | 
				
			||||||
 | 
					            this.sourcecheck(...args);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        // /** 面板加載完成 */
 | 
				
			||||||
 | 
					        // "panel-load-finish"(evnet, ...args) {
 | 
				
			||||||
 | 
					        // Editor.Scene.callSceneScript("sourcecheck", "get-default-info", { args: args }, function (err, response) {
 | 
				
			||||||
 | 
					        //     // Editor.log("callSceneScript: " + response);
 | 
				
			||||||
 | 
					        //     Editor.Ipc.sendToPanel("sourcecheck", "setDefault", response);
 | 
				
			||||||
 | 
					        // });
 | 
				
			||||||
 | 
					        // },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "sourcecheck",
 | 
				
			||||||
 | 
					  "version": "0.0.1",
 | 
				
			||||||
 | 
					  "description": "Sample-Package",
 | 
				
			||||||
 | 
					  "author": "Sample",
 | 
				
			||||||
 | 
					  "main": "main.js",
 | 
				
			||||||
 | 
					  "scene-script": "scene-obtain.js",
 | 
				
			||||||
 | 
					  "engineSupport": true,
 | 
				
			||||||
 | 
					  "main-menu": {
 | 
				
			||||||
 | 
					    "扩展/Source Check": {
 | 
				
			||||||
 | 
					      "message": "sourcecheck:open-panel"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "panel": {
 | 
				
			||||||
 | 
					    "main": "panel/index.js",
 | 
				
			||||||
 | 
					    "type": "dockable",
 | 
				
			||||||
 | 
					    "title": "Source Check",
 | 
				
			||||||
 | 
					    "width": 400,
 | 
				
			||||||
 | 
					    "height": 350
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										62
									
								
								panel/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								panel/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					Editor.Panel.extend({
 | 
				
			||||||
 | 
					    style: `
 | 
				
			||||||
 | 
					    :host { margin: 5px; }
 | 
				
			||||||
 | 
					    h2 { color: #f90; }
 | 
				
			||||||
 | 
					    .bottom {
 | 
				
			||||||
 | 
					      height: 30px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  `,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template: `
 | 
				
			||||||
 | 
					    <h2 style="text-align:center">Source Check</h2>
 | 
				
			||||||
 | 
					    <hr />
 | 
				
			||||||
 | 
					        <div>
 | 
				
			||||||
 | 
					            <!-- 1. 把要檢查的資料夾拉進來<br> -->
 | 
				
			||||||
 | 
					            1. 填入要檢查的資料夾(從assets開始算)<br>
 | 
				
			||||||
 | 
					            2. 執行<br>
 | 
				
			||||||
 | 
					            PS. 目前只有檢查png、jpg、anim、fnt
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    <hr />
 | 
				
			||||||
 | 
					        <div>
 | 
				
			||||||
 | 
					            要檢查的資料夾 db://asstes/
 | 
				
			||||||
 | 
					            <ui-input placeholder="UIScenes/Backpack" id="filepath"></ui-input>  
 | 
				
			||||||
 | 
					            <!-- <ui-asset class="flex-1" type="native-asset" droppable="asset" id="node"></ui-asset> -->
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    <hr />
 | 
				
			||||||
 | 
					    <hr />
 | 
				
			||||||
 | 
					         <div style="text-align:right">
 | 
				
			||||||
 | 
					             <ui-button id="run" class="blue">執行</ui-button>
 | 
				
			||||||
 | 
					         </div>      
 | 
				
			||||||
 | 
					  `,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $: {
 | 
				
			||||||
 | 
					        /** filepath */
 | 
				
			||||||
 | 
					        filepath: "#filepath",
 | 
				
			||||||
 | 
					        /** 生成按鈕 */
 | 
				
			||||||
 | 
					        run: "#run",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ready() {
 | 
				
			||||||
 | 
					        // Editor.Ipc.sendToMain("sourcecheck:panel-load-finish");
 | 
				
			||||||
 | 
					        this.onClickRun();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    /** 保存按鈕點擊事件 */
 | 
				
			||||||
 | 
					    onClickRun() {
 | 
				
			||||||
 | 
					        this.$run.addEventListener("confirm", () => {
 | 
				
			||||||
 | 
					            if (!this.$filepath._value) {
 | 
				
			||||||
 | 
					                Editor.error("請輸入要檢查的資料夾");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Editor.Ipc.sendToMain("sourcecheck:run-click", this.$filepath);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    messages: {
 | 
				
			||||||
 | 
					        // "setDefault": function (event, ...agrs) {
 | 
				
			||||||
 | 
					        //     if (event.reply) {
 | 
				
			||||||
 | 
					        //         //if no error, the first argument should be null
 | 
				
			||||||
 | 
					        //         event.reply(null, "Fine, thank you!");
 | 
				
			||||||
 | 
					        //     }
 | 
				
			||||||
 | 
					        // }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										37
									
								
								scene-obtain.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								scene-obtain.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					"use strict";
 | 
				
			||||||
 | 
					let fs = require("fs");
 | 
				
			||||||
 | 
					let path = require("path");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 獲取場景節點下的配置信息
 | 
				
			||||||
 | 
					     * @param event event
 | 
				
			||||||
 | 
					     * @param data 這邊把panel的Node帶進來
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    "getFsPath": function (event, request) {
 | 
				
			||||||
 | 
					        let self = this;
 | 
				
			||||||
 | 
					        var response = null;
 | 
				
			||||||
 | 
					        var args = request.args;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            let url = `db://assets/${args[0]._value}`;
 | 
				
			||||||
 | 
					            url = url.replace(/\\/g, "/");
 | 
				
			||||||
 | 
					            // let url = `db://assets/=SceneLobby`;
 | 
				
			||||||
 | 
					            // Editor.log(`url: ${url}`);
 | 
				
			||||||
 | 
					            let fsPath = Editor.remote.assetdb.urlToFspath(url);
 | 
				
			||||||
 | 
					            // Editor.log(`fsPath: ${fsPath}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // this.fileSearch(fsPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let res = {
 | 
				
			||||||
 | 
					                url: url,
 | 
				
			||||||
 | 
					                fsPath, fsPath
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            response = JSON.stringify(res);
 | 
				
			||||||
 | 
					        } catch (error) {
 | 
				
			||||||
 | 
					            Editor.log(`getFsPath error: ${error}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (event.reply) {
 | 
				
			||||||
 | 
					            event.reply(null, response);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										104
									
								
								src/common/config-manager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/common/config-manager.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
				
			|||||||
 | 
					const Path = require('path');
 | 
				
			||||||
 | 
					const Fs = require('fs');
 | 
				
			||||||
 | 
					const PackageUtil = require('../eazax/package-util');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 配置文件路径 */
 | 
				
			||||||
 | 
					const CONFIG_PATH = Path.join(__dirname, '../../config.json');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** package.json 的路径 */
 | 
				
			||||||
 | 
					const PACKAGE_PATH = Path.join(__dirname, '../../package.json');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 包名 */
 | 
				
			||||||
 | 
					const PACKAGE_NAME = PackageUtil.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 快捷键行为 */
 | 
				
			||||||
 | 
					const ACTION_NAME = 'find';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** package.json 中的菜单项 key */
 | 
				
			||||||
 | 
					const MENU_ITEM_KEY = `i18n:MAIN_MENU.package.title/i18n:${PACKAGE_NAME}.name/i18n:${PACKAGE_NAME}.${ACTION_NAME}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 配置管理器
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const ConfigManager = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 默认配置
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get defaultConfig() {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            version: '1.1',
 | 
				
			||||||
 | 
					            printDetails: true,
 | 
				
			||||||
 | 
					            printFolding: true,
 | 
				
			||||||
 | 
					            autoCheckUpdate: true,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 读取配置
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get() {
 | 
				
			||||||
 | 
					        // 配置
 | 
				
			||||||
 | 
					        const config = ConfigManager.defaultConfig;
 | 
				
			||||||
 | 
					        if (Fs.existsSync(CONFIG_PATH)) {
 | 
				
			||||||
 | 
					            const localConfig = JSON.parse(Fs.readFileSync(CONFIG_PATH));
 | 
				
			||||||
 | 
					            for (const key in config) {
 | 
				
			||||||
 | 
					                if (localConfig[key] !== undefined) {
 | 
				
			||||||
 | 
					                    config[key] = localConfig[key];
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // // 快捷键
 | 
				
			||||||
 | 
					        // config.hotkey = ConfigManager.getAccelerator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Done
 | 
				
			||||||
 | 
					        return config;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 保存配置
 | 
				
			||||||
 | 
					     * @param {*} value 配置
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    set(value) {
 | 
				
			||||||
 | 
					        // 配置
 | 
				
			||||||
 | 
					        const config = ConfigManager.defaultConfig;
 | 
				
			||||||
 | 
					        for (const key in config) {
 | 
				
			||||||
 | 
					            if (value[key] !== undefined) {
 | 
				
			||||||
 | 
					                config[key] = value[key];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 快捷键
 | 
				
			||||||
 | 
					        ConfigManager.setAccelerator(value.hotkey);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取快捷键
 | 
				
			||||||
 | 
					     * @returns {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getAccelerator() {
 | 
				
			||||||
 | 
					        const package = JSON.parse(Fs.readFileSync(PACKAGE_PATH)),
 | 
				
			||||||
 | 
					            item = package['main-menu'][MENU_ITEM_KEY];
 | 
				
			||||||
 | 
					        return item['accelerator'] || '';
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 设置快捷键
 | 
				
			||||||
 | 
					     * @param {string} value 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    setAccelerator(value) {
 | 
				
			||||||
 | 
					        const package = JSON.parse(Fs.readFileSync(PACKAGE_PATH)),
 | 
				
			||||||
 | 
					            item = package['main-menu'][MENU_ITEM_KEY];
 | 
				
			||||||
 | 
					        if (value != undefined && value !== '') {
 | 
				
			||||||
 | 
					            item['accelerator'] = value;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            delete item['accelerator'];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Fs.writeFileSync(PACKAGE_PATH, JSON.stringify(package, null, 2));
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = ConfigManager;
 | 
				
			||||||
							
								
								
									
										61
									
								
								src/eazax/browser-util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/eazax/browser-util.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 浏览器工具
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210729
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const BrowserUtil = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取当前 Url 中的参数
 | 
				
			||||||
 | 
					     * @param {string} key 键
 | 
				
			||||||
 | 
					     * @returns {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getUrlParam(key) {
 | 
				
			||||||
 | 
					        if (!window || !window.location) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const query = window.location.search.replace('?', '');
 | 
				
			||||||
 | 
					        if (query === '') {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const substrings = query.split('&');
 | 
				
			||||||
 | 
					        for (let i = 0; i < substrings.length; i++) {
 | 
				
			||||||
 | 
					            const keyValue = substrings[i].split('=');
 | 
				
			||||||
 | 
					            if (decodeURIComponent(keyValue[0]) === key) {
 | 
				
			||||||
 | 
					                return decodeURIComponent(keyValue[1]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取 Cookie 值
 | 
				
			||||||
 | 
					     * @param {string} key 键
 | 
				
			||||||
 | 
					     * @returns {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getCookie(key) {
 | 
				
			||||||
 | 
					        const regExp = new RegExp(`(^| )${key}=([^;]*)(;|$)`),
 | 
				
			||||||
 | 
					            values = document.cookie.match(regExp);
 | 
				
			||||||
 | 
					        if (values !== null) {
 | 
				
			||||||
 | 
					            return values[2];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 设置 Cookie
 | 
				
			||||||
 | 
					     * @param {string} key 键
 | 
				
			||||||
 | 
					     * @param {string | number | boolean} value 值
 | 
				
			||||||
 | 
					     * @param {string} expires 过期时间(GMT)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    setCookie(key, value, expires) {
 | 
				
			||||||
 | 
					        let keyValues = `${key}=${encodeURIComponent(value)};`;
 | 
				
			||||||
 | 
					        if (expires) {
 | 
				
			||||||
 | 
					            keyValues += `expires=${expires};`;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        document.cookie = keyValues;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = BrowserUtil;
 | 
				
			||||||
							
								
								
									
										37
									
								
								src/eazax/color-util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/eazax/color-util.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 颜色工具
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210725
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const ColorUtil = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将十六进制颜色值转为 RGB 格式
 | 
				
			||||||
 | 
					     * @param {string} hex 
 | 
				
			||||||
 | 
					     * @returns {{ r: number, g: number, b: number }}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    hexToRGB(hex) {
 | 
				
			||||||
 | 
					        // 是否为 HEX 格式
 | 
				
			||||||
 | 
					        const regExp = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
 | 
				
			||||||
 | 
					        if (!regExp.test(hex)) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 四位
 | 
				
			||||||
 | 
					        if (hex.length === 4) {
 | 
				
			||||||
 | 
					            const r = hex.slice(1, 2),
 | 
				
			||||||
 | 
					                g = hex.slice(2, 3),
 | 
				
			||||||
 | 
					                b = hex.slice(3, 4);
 | 
				
			||||||
 | 
					            hex = `#${r}${r}${g}${g}${b}${b}`;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 转换进制
 | 
				
			||||||
 | 
					        const rgb = {
 | 
				
			||||||
 | 
					            r: parseInt(`0x${hex.slice(1, 3)}`),
 | 
				
			||||||
 | 
					            g: parseInt(`0x${hex.slice(3, 5)}`),
 | 
				
			||||||
 | 
					            b: parseInt(`0x${hex.slice(5, 7)}`),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return rgb;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = ColorUtil;
 | 
				
			||||||
							
								
								
									
										201
									
								
								src/eazax/css/cocos-class.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								src/eazax/css/cocos-class.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,201 @@
 | 
				
			|||||||
 | 
					/* 
 | 
				
			||||||
 | 
					  Cocos Creator 风格样式
 | 
				
			||||||
 | 
					  版本: 20210911
 | 
				
			||||||
 | 
					  作者: 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					  主页: https://gitee.com/ifaswind
 | 
				
			||||||
 | 
					  公众号: 菜鸟小栈
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 属性容器 */
 | 
				
			||||||
 | 
					.properties {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  border: 1px solid #666;
 | 
				
			||||||
 | 
					  border-radius: 3px;
 | 
				
			||||||
 | 
					  padding: 5px;
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					  outline: 0;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					  overflow: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.properties > * {
 | 
				
			||||||
 | 
					  margin: 2px 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.properties:first-child {
 | 
				
			||||||
 | 
					  margin-top: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.properties:last-child {
 | 
				
			||||||
 | 
					  margin-bottom: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 属性 */
 | 
				
			||||||
 | 
					.property {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  min-height: 23px;
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: row;
 | 
				
			||||||
 | 
					  flex-wrap: nowrap;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: flex-start;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 属性标签 */
 | 
				
			||||||
 | 
					.property > .label {
 | 
				
			||||||
 | 
					  width: 38%;
 | 
				
			||||||
 | 
					  min-width: 70px;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  margin-left: 5px;
 | 
				
			||||||
 | 
					  line-height: 23px;
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  white-space: nowrap;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: row;
 | 
				
			||||||
 | 
					  flex-wrap: nowrap;
 | 
				
			||||||
 | 
					  flex-shrink: 0;
 | 
				
			||||||
 | 
					  align-items: baseline;
 | 
				
			||||||
 | 
					  justify-content: flex-start;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 属性标签文本:虚指 */
 | 
				
			||||||
 | 
					.property:hover > .label > .text {
 | 
				
			||||||
 | 
					  color: #09f;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 属性标签文本:聚焦内部 */
 | 
				
			||||||
 | 
					.property:focus-within > .label > .text {
 | 
				
			||||||
 | 
					  color: #fd942b;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 属性标签内容:聚焦内部 */
 | 
				
			||||||
 | 
					.property:focus-within > .content > * {
 | 
				
			||||||
 | 
					  border-color: #fd942b;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* tooltip */
 | 
				
			||||||
 | 
					.tooltip {
 | 
				
			||||||
 | 
					  background-color: #333333;
 | 
				
			||||||
 | 
					  padding: 5px 8px;
 | 
				
			||||||
 | 
					  border: 1px solid #646464;
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: -38px;
 | 
				
			||||||
 | 
					  left: -5px;
 | 
				
			||||||
 | 
					  visibility: hidden;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  z-index: 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* tooltip 三角形 */
 | 
				
			||||||
 | 
					.tooltip::before,
 | 
				
			||||||
 | 
					.tooltip::after {
 | 
				
			||||||
 | 
					  content: '';
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					  width: 0;
 | 
				
			||||||
 | 
					  height: 0;
 | 
				
			||||||
 | 
					  border: 6px solid transparent;
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  left: 10px;
 | 
				
			||||||
 | 
					  transform: rotate(-90deg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* tooltip 三角形 */
 | 
				
			||||||
 | 
					.tooltip::before {
 | 
				
			||||||
 | 
					  border-right: 6px solid #333333;
 | 
				
			||||||
 | 
					  top: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* tooltip 三角形边框 */
 | 
				
			||||||
 | 
					.tooltip::after {
 | 
				
			||||||
 | 
					  border-right: 6px solid #646464;
 | 
				
			||||||
 | 
					  top: calc(100% + 1px);
 | 
				
			||||||
 | 
					  z-index: -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 前一个元素虚指时的 tooltip */
 | 
				
			||||||
 | 
					*:hover + .tooltip {
 | 
				
			||||||
 | 
					  visibility: visible;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 属性内容 */
 | 
				
			||||||
 | 
					.property > .content {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					  flex-direction: row;
 | 
				
			||||||
 | 
					  flex-wrap: nowrap;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: flex-start;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.property > .content > * {
 | 
				
			||||||
 | 
					  width: auto;
 | 
				
			||||||
 | 
					  min-width: 20px;
 | 
				
			||||||
 | 
					  height: 21px;
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.property > .content > *:focus {
 | 
				
			||||||
 | 
					  border-color: #fd942b;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 提示 */
 | 
				
			||||||
 | 
					.tip {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  min-height: 45px;
 | 
				
			||||||
 | 
					  background: #333;
 | 
				
			||||||
 | 
					  border: 1px solid #666;
 | 
				
			||||||
 | 
					  border-radius: 3px;
 | 
				
			||||||
 | 
					  padding: 12px 8px;
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: left;
 | 
				
			||||||
 | 
					  color: #bdbdbd;
 | 
				
			||||||
 | 
					  line-height: 17px;
 | 
				
			||||||
 | 
					  font-size: 13px;
 | 
				
			||||||
 | 
					  white-space: pre-line;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tip > * {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *::滚动条 */
 | 
				
			||||||
 | 
					*::-webkit-scrollbar {
 | 
				
			||||||
 | 
					  width: 11px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *::滚动条-按钮 */
 | 
				
			||||||
 | 
					*::-webkit-scrollbar-button {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *::滚动条-横竖交汇处 */
 | 
				
			||||||
 | 
					*::-webkit-scrollbar-corner {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *::滚动条-轨道 */
 | 
				
			||||||
 | 
					*::-webkit-scrollbar-track {
 | 
				
			||||||
 | 
					  /* background: rgba(0, 0, 0, 0.5); */
 | 
				
			||||||
 | 
					  background: none !important;
 | 
				
			||||||
 | 
					  background-clip: content-box;
 | 
				
			||||||
 | 
					  border: 5px solid transparent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *::滚动条-滑块 */
 | 
				
			||||||
 | 
					*::-webkit-scrollbar-thumb {
 | 
				
			||||||
 | 
					  background: #7d7d7d;
 | 
				
			||||||
 | 
					  background-clip: content-box;
 | 
				
			||||||
 | 
					  border: 4px solid transparent;
 | 
				
			||||||
 | 
					  border-radius: 6px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* *::滚动条-滑块:虚指 */
 | 
				
			||||||
 | 
					*::-webkit-scrollbar-thumb:hover {
 | 
				
			||||||
 | 
					  background-color: #fd942b;
 | 
				
			||||||
 | 
					  border: 3px solid transparent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										197
									
								
								src/eazax/css/cocos-tag.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								src/eazax/css/cocos-tag.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,197 @@
 | 
				
			|||||||
 | 
					/* 
 | 
				
			||||||
 | 
					  Cocos Creator 风格标签 (橙黑)
 | 
				
			||||||
 | 
					  版本: 20210725
 | 
				
			||||||
 | 
					  作者: 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					  主页: https://gitee.com/ifaswind
 | 
				
			||||||
 | 
					  公众号: 菜鸟小栈
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 下拉选择器 */
 | 
				
			||||||
 | 
					select {
 | 
				
			||||||
 | 
					  background-color: #262626;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					  border: 1px solid #171717;
 | 
				
			||||||
 | 
					  border-radius: 100px;
 | 
				
			||||||
 | 
					  padding: 0 8px;
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  color: #bdbdbd;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  /* 替换默认的箭头 */
 | 
				
			||||||
 | 
					  appearance: none;
 | 
				
			||||||
 | 
					  -webkit-appearance: none;
 | 
				
			||||||
 | 
					  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA+ElEQVRYR+2VXw6CMAzGV3YUjSZ6CsI4l3gutnALH/xzEB8spokSQphbiwkv5RHafb9+awuYlR9YWd8ogDqgDqgDPx3w3h8A4FlV1UOysLz3O2stlmV5j+VHAbqu2yLijRIR8VzXdcOBaNu2KYriRDl93x+dc5e5/ChACGFjjBnIORBj8Q/A3jl3ZQFQcAiBKhgqz4GYiqdyklPAgeCKU5FJgFwnJOLZACkIqTgLgILnhOj9t9slE5N1BePunUKMv6Uajj0Fsbmfg5CIs68g5oRUfBEAJdOqBYCXdFUvBuCsZva/4B+H55zBnoKcQzkxCqAOqAOrO/AGwnWWIa30xvoAAAAASUVORK5CYII=);
 | 
				
			||||||
 | 
					  background-size: 16px;
 | 
				
			||||||
 | 
					  background-repeat: no-repeat;
 | 
				
			||||||
 | 
					  background-position: right 3px center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 下拉选择器:虚指 */
 | 
				
			||||||
 | 
					select:hover {
 | 
				
			||||||
 | 
					  border-color: #888888;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 输入框,文本区域 */
 | 
				
			||||||
 | 
					input,
 | 
				
			||||||
 | 
					textarea {
 | 
				
			||||||
 | 
					  background-color: #262626;
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					  padding: 0 5px;
 | 
				
			||||||
 | 
					  border: 1px solid #171717;
 | 
				
			||||||
 | 
					  border-radius: 3px;
 | 
				
			||||||
 | 
					  color: #fd942b;
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 文本区域 */
 | 
				
			||||||
 | 
					textarea {
 | 
				
			||||||
 | 
					  min-height: 40px;
 | 
				
			||||||
 | 
					  resize: vertical;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 输入框,文本区域::占位符 */
 | 
				
			||||||
 | 
					input::placeholder,
 | 
				
			||||||
 | 
					textarea::placeholder {
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  font-style: normal;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 数字输入框 */
 | 
				
			||||||
 | 
					input[type='number'] {
 | 
				
			||||||
 | 
					  width: 50px !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 数字输入框::增减按钮 */
 | 
				
			||||||
 | 
					input[type='number']::-webkit-outer-spin-button,
 | 
				
			||||||
 | 
					input[type='number']::-webkit-inner-spin-button {
 | 
				
			||||||
 | 
					  /* appearance: none; */
 | 
				
			||||||
 | 
					  /* -webkit-appearance: none; */
 | 
				
			||||||
 | 
					  /* margin: 0; */
 | 
				
			||||||
 | 
					  margin-right: -2px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 复选框 */
 | 
				
			||||||
 | 
					input[type='checkbox'] {
 | 
				
			||||||
 | 
					  appearance: none;
 | 
				
			||||||
 | 
					  -webkit-appearance: none;
 | 
				
			||||||
 | 
					  width: 16px !important;
 | 
				
			||||||
 | 
					  height: 16px !important;
 | 
				
			||||||
 | 
					  min-width: 16px !important;
 | 
				
			||||||
 | 
					  background-image: none;
 | 
				
			||||||
 | 
					  background-color: #262626;
 | 
				
			||||||
 | 
					  border: 1px solid #171717;
 | 
				
			||||||
 | 
					  border-radius: 3px;
 | 
				
			||||||
 | 
					  padding-left: 0;
 | 
				
			||||||
 | 
					  position: relative !important;
 | 
				
			||||||
 | 
					  flex: 0 !important;
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  color: #fd942b;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 复选框:勾选 */
 | 
				
			||||||
 | 
					input[type='checkbox']:checked::after {
 | 
				
			||||||
 | 
					  width: 12px;
 | 
				
			||||||
 | 
					  height: 12px;
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  content: '';
 | 
				
			||||||
 | 
					  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABKUlEQVRYR+2W2w2DMAxF41ZdBnWzqjMQZkBdjWUqkiqUgCHOO4Ef+EECwTlO7AvATj7gZD67BA5bgW/fcLXdj/cwnfVxiMD4aVomYQILKTssUV0Aw3XVWKKqgFr2G0BLTZqWqCbggq8NIHkVgSD43A/FBag9J8MOJL+/hq6oQGjlbIYrMUNAVSAEg/28+iI7BW4IuObVJZAK3wj45tUmkANfBFyNs08uLBIKd70DgroWNY0WKAGfVmBUHwlLWuFqcRWl4OsWREioh2zxuukTYtWoPlrGcOyfnIEkc9s3gsb9QLg5hiUkIuB0EOVIRMJJAXUxaTsS4FaBaIlEuFMgWCID7hXwSmTCgwSsEgXgwQJ/CZSYheBRAlpCEP/20UGFHij6R5Qicgn8AIQ23JRIyuB1AAAAAElFTkSuQmCC);
 | 
				
			||||||
 | 
					  background-size: 12px;
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 50%;
 | 
				
			||||||
 | 
					  left: 50%;
 | 
				
			||||||
 | 
					  transform: translate(-50%, -50%);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 输入框:虚指 */
 | 
				
			||||||
 | 
					input:hover {
 | 
				
			||||||
 | 
					  border-color: #888888;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 滑动条 */
 | 
				
			||||||
 | 
					input[type='range'] {
 | 
				
			||||||
 | 
					  appearance: none;
 | 
				
			||||||
 | 
					  -webkit-appearance: none;
 | 
				
			||||||
 | 
					  height: 4px !important;
 | 
				
			||||||
 | 
					  background-color: #262626;
 | 
				
			||||||
 | 
					  border: 1px solid #171717;
 | 
				
			||||||
 | 
					  padding-left: 0;
 | 
				
			||||||
 | 
					  padding-right: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 滑动条:虚指|聚焦 */
 | 
				
			||||||
 | 
					input[type='range']:hover,
 | 
				
			||||||
 | 
					input[type='range']:focus,
 | 
				
			||||||
 | 
					*:focus-within input[type='range'] {
 | 
				
			||||||
 | 
					  border-color: #171717 !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 滑动条::把手 */
 | 
				
			||||||
 | 
					input[type='range']::-webkit-slider-thumb {
 | 
				
			||||||
 | 
					  appearance: none;
 | 
				
			||||||
 | 
					  -webkit-appearance: none;
 | 
				
			||||||
 | 
					  width: 12px;
 | 
				
			||||||
 | 
					  height: 12px;
 | 
				
			||||||
 | 
					  top: 2px;
 | 
				
			||||||
 | 
					  background: #333;
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					  border: 2px solid #949494;
 | 
				
			||||||
 | 
					  box-shadow: 0 1px 3px 1px #000 inset, 0 1px 1px 0 rgba(0, 0, 0, 0.9);
 | 
				
			||||||
 | 
					  border-radius: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 滑动条::把手:虚指 */
 | 
				
			||||||
 | 
					input[type='range']::-webkit-slider-thumb:hover {
 | 
				
			||||||
 | 
					  border-color: #bcbcbc;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 滑动条::把手:激活 */
 | 
				
			||||||
 | 
					input[type='range']::-webkit-slider-thumb:active,
 | 
				
			||||||
 | 
					*:focus-within > input[type='range']::-webkit-slider-thumb {
 | 
				
			||||||
 | 
					  color: #bdbdbd;
 | 
				
			||||||
 | 
					  border-color: #fd942b !important;
 | 
				
			||||||
 | 
					  cursor: ew-resize;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 取色器 */
 | 
				
			||||||
 | 
					input[type='color'] {
 | 
				
			||||||
 | 
					  width: 16px;
 | 
				
			||||||
 | 
					  height: 16px;
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					  border-radius: 1px;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 取色器::色板容器 */
 | 
				
			||||||
 | 
					input[type='color']::-webkit-color-swatch-wrapper {
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 取色器::色板 */
 | 
				
			||||||
 | 
					input[type='color']::-webkit-color-swatch {
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 超链接 */
 | 
				
			||||||
 | 
					a {
 | 
				
			||||||
 | 
					  color: #fd942b;
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 超链接:虚指 */
 | 
				
			||||||
 | 
					a:hover {
 | 
				
			||||||
 | 
					  text-decoration: underline;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 分割线 */
 | 
				
			||||||
 | 
					hr {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  height: 1px;
 | 
				
			||||||
 | 
					  background-color: #666;
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  margin: 10px 0 !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/eazax/css/eazax-colors.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/eazax/css/eazax-colors.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					:root {
 | 
				
			||||||
 | 
					  /* 背景颜色 */
 | 
				
			||||||
 | 
					  --eazax-bg-color: #454545;
 | 
				
			||||||
 | 
					  /* 主颜色 */
 | 
				
			||||||
 | 
					  --eazax-main-color: #262626;
 | 
				
			||||||
 | 
					  /* 强调色 */
 | 
				
			||||||
 | 
					  --eazax-accent-color: #2e88fb;
 | 
				
			||||||
 | 
					  /* 聚焦色 */
 | 
				
			||||||
 | 
					  --eazax-focus-color: #fd942b;
 | 
				
			||||||
 | 
					  /* 边框调色 */
 | 
				
			||||||
 | 
					  --eazax-border-color: #171717;
 | 
				
			||||||
 | 
					  /* 边框虚指调色 */
 | 
				
			||||||
 | 
					  --eazax-border-hover-color: #888888;
 | 
				
			||||||
 | 
					  /* 文本颜色 */
 | 
				
			||||||
 | 
					  --eazax-font-color: #bdbdbd;
 | 
				
			||||||
 | 
					  /* 内容颜色 */
 | 
				
			||||||
 | 
					  --eazax-content-color: #fd942b;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										53
									
								
								src/eazax/editor-main-kit.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/eazax/editor-main-kit.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					const MainEvent = require('./main-event');
 | 
				
			||||||
 | 
					const { print, checkUpdate } = require('./editor-main-util');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * (渲染进程)检查更新回调
 | 
				
			||||||
 | 
					 * @param {Electron.IpcMainEvent} event 
 | 
				
			||||||
 | 
					 * @param {boolean} logWhatever 无论有无更新都打印提示
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function onCheckUpdateEvent(event, logWhatever) {
 | 
				
			||||||
 | 
					    checkUpdate(logWhatever);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * (渲染进程)打印事件回调
 | 
				
			||||||
 | 
					 * @param {Electron.IpcMainEvent} event 
 | 
				
			||||||
 | 
					 * @param {'log' | 'info' | 'warn' | 'error' | any} type 
 | 
				
			||||||
 | 
					 * @param {any[]?} args 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function onPrintEvent(event, type) {
 | 
				
			||||||
 | 
					    // print(type, ...args);
 | 
				
			||||||
 | 
					    const args = [type];
 | 
				
			||||||
 | 
					    for (let i = 2, l = arguments.length; i < l; i++) {
 | 
				
			||||||
 | 
					        args.push(arguments[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    print.apply(null, args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 编辑器主进程套件 (依赖 Cocos Creator 编辑器)
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210818
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const EditorMainKit = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 注册
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    register() {
 | 
				
			||||||
 | 
					        MainEvent.on('check-update', onCheckUpdateEvent);
 | 
				
			||||||
 | 
					        MainEvent.on('print', onPrintEvent);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 取消注册
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    unregister() {
 | 
				
			||||||
 | 
					        MainEvent.removeListener('check-update', onCheckUpdateEvent);
 | 
				
			||||||
 | 
					        MainEvent.removeListener('print', onPrintEvent);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = EditorMainKit;
 | 
				
			||||||
							
								
								
									
										147
									
								
								src/eazax/editor-main-util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								src/eazax/editor-main-util.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
				
			|||||||
 | 
					const I18n = require('./i18n');
 | 
				
			||||||
 | 
					const PackageUtil = require('./package-util');
 | 
				
			||||||
 | 
					const Updater = require('./updater');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 编辑器语言 */
 | 
				
			||||||
 | 
					const LANG = Editor.lang || Editor.I18n.getLanguage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 包名 */
 | 
				
			||||||
 | 
					const PACKAGE_NAME = PackageUtil.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 扩展名称 */
 | 
				
			||||||
 | 
					const EXTENSION_NAME = I18n.get(LANG, 'name');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 编辑器主进程工具 (依赖 Cocos Creator 编辑器)
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210929
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const EditorMainUtil = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 语言
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get language() {
 | 
				
			||||||
 | 
					        return LANG;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * i18n
 | 
				
			||||||
 | 
					     * @param {string} key 关键词
 | 
				
			||||||
 | 
					     * @returns {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    translate(key) {
 | 
				
			||||||
 | 
					        return I18n.get(LANG, key);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 打印信息到控制台(带标题)
 | 
				
			||||||
 | 
					     * @param {'log' | 'info' | 'warn' | 'error' | any} type
 | 
				
			||||||
 | 
					     * @param {any[]?} args 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    print(type) {
 | 
				
			||||||
 | 
					        const args = [`[${EXTENSION_NAME}]`];
 | 
				
			||||||
 | 
					        for (let i = 1, l = arguments.length; i < l; i++) {
 | 
				
			||||||
 | 
					            args.push(arguments[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const object = Editor.log ? Editor : console;
 | 
				
			||||||
 | 
					        switch (type) {
 | 
				
			||||||
 | 
					            case 'log': {
 | 
				
			||||||
 | 
					                object.log.apply(object, args);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            case 'info': {
 | 
				
			||||||
 | 
					                object.info.apply(object, args);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            case 'warn': {
 | 
				
			||||||
 | 
					                object.warn.apply(object, args);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            case 'error': {
 | 
				
			||||||
 | 
					                object.error.apply(object, args);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            default: {
 | 
				
			||||||
 | 
					                args.splice(1, 0, type);
 | 
				
			||||||
 | 
					                object.log.apply(object, args);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 打印信息到控制台(不带标题)
 | 
				
			||||||
 | 
					     * @param {'log' | 'info' | 'warn' | 'error' | any} type
 | 
				
			||||||
 | 
					     * @param {any[]?} args 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    pureWithoutTitle(type) {
 | 
				
			||||||
 | 
					        const args = [];
 | 
				
			||||||
 | 
					        for (let i = 1, l = arguments.length; i < l; i++) {
 | 
				
			||||||
 | 
					            args.push(arguments[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const object = Editor.log ? Editor : console;
 | 
				
			||||||
 | 
					        switch (type) {
 | 
				
			||||||
 | 
					            case 'log': {
 | 
				
			||||||
 | 
					                object.log.apply(object, args);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            case 'info': {
 | 
				
			||||||
 | 
					                object.info.apply(object, args);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            case 'warn': {
 | 
				
			||||||
 | 
					                object.warn.apply(object, args);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            case 'error': {
 | 
				
			||||||
 | 
					                object.error.apply(object, args);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            default: {
 | 
				
			||||||
 | 
					                args.splice(1, 0, type);
 | 
				
			||||||
 | 
					                object.log.apply(object, args);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 检查更新
 | 
				
			||||||
 | 
					     * @param {boolean} logWhatever 无论有无更新都打印提示
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async checkUpdate(logWhatever) {
 | 
				
			||||||
 | 
					        // 编辑器本次启动是否已经检查过了
 | 
				
			||||||
 | 
					        if (!logWhatever && (Editor[PACKAGE_NAME] && Editor[PACKAGE_NAME].hasCheckUpdate)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Editor[PACKAGE_NAME] = { hasCheckUpdate: true };
 | 
				
			||||||
 | 
					        // 是否有新版本
 | 
				
			||||||
 | 
					        const hasNewVersion = await Updater.check();
 | 
				
			||||||
 | 
					        // 打印到控制台
 | 
				
			||||||
 | 
					        const { print, translate } = EditorMainUtil;
 | 
				
			||||||
 | 
					        const localVersion = Updater.getLocalVersion();
 | 
				
			||||||
 | 
					        if (hasNewVersion) {
 | 
				
			||||||
 | 
					            const remoteVersion = await Updater.getRemoteVersion();
 | 
				
			||||||
 | 
					            print('info', translate('has-new-version'));
 | 
				
			||||||
 | 
					            print('info', `${translate('local-version')}${localVersion}`);
 | 
				
			||||||
 | 
					            print('info', `${translate('latest-version')}${remoteVersion}`);
 | 
				
			||||||
 | 
					            print('info', translate('git-releases'));
 | 
				
			||||||
 | 
					            print('info', translate('cocos-store'));
 | 
				
			||||||
 | 
					        } else if (logWhatever) {
 | 
				
			||||||
 | 
					            print('info', translate('current-latest'));
 | 
				
			||||||
 | 
					            print('info', `${translate('local-version')}${localVersion}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * (3.x)重新加载扩展
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async reload() {
 | 
				
			||||||
 | 
					        const path = await Editor.Package.getPath(PACKAGE_NAME);
 | 
				
			||||||
 | 
					        await Editor.Package.unregister(path);
 | 
				
			||||||
 | 
					        await Editor.Package.register(path);
 | 
				
			||||||
 | 
					        await Editor.Package.enable(path);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = EditorMainUtil;
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/eazax/editor-renderer-kit.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/eazax/editor-renderer-kit.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					const RendererEvent = require("./renderer-event");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 编辑器渲染进程套件 (依赖 Cocos Creator 编辑器)
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210818
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const EditorRendererKit = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 打印信息到 Creator 编辑器控制台
 | 
				
			||||||
 | 
					     * @param {'log' | 'info' | 'warn' | 'error' | any} type 
 | 
				
			||||||
 | 
					     * @param {any[]?} args 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    print(type) {
 | 
				
			||||||
 | 
					        // return RendererEvent.send('print', type, ...args);
 | 
				
			||||||
 | 
					        const args = ['print', type];
 | 
				
			||||||
 | 
					        for (let i = 1, l = arguments.length; i < l; i++) {
 | 
				
			||||||
 | 
					            args.push(arguments[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return RendererEvent.send.apply(RendererEvent, args);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = EditorRendererKit;
 | 
				
			||||||
							
								
								
									
										158
									
								
								src/eazax/file-util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/eazax/file-util.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,158 @@
 | 
				
			|||||||
 | 
					const Fs = require('fs');
 | 
				
			||||||
 | 
					const Path = require('path');
 | 
				
			||||||
 | 
					const { promisify } = require('util');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 文件工具 (Promise 化)
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210818
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const FileUtil = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取文件状态
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     * @returns {Promise<Fs.stats>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    stat: promisify(Fs.stat),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建文件夹
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     * @param {Fs.MakeDirectoryOptions?} options 选项
 | 
				
			||||||
 | 
					     * @returns {Promise<void>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    mkdir: promisify(Fs.mkdir),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 读取文件夹
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     * @param {any} options 选项
 | 
				
			||||||
 | 
					     * @returns {Promise<string[]>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    readdir: promisify(Fs.readdir),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 移除文件夹
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     * @param {Fs.RmDirOptions?} options 选项
 | 
				
			||||||
 | 
					     * @returns {Promise<void>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    rmdir: promisify(Fs.rmdir),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 读取文件
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     * @param {any} options 选项
 | 
				
			||||||
 | 
					     * @returns {Promise<Buffer>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    readFile: promisify(Fs.readFile),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建文件
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     * @param {string | NodeJS.ArrayBufferView} data 数据
 | 
				
			||||||
 | 
					     * @param {Fs.WriteFileOptions?} options 选项
 | 
				
			||||||
 | 
					     * @returns {Promise<void>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    writeFile: promisify(Fs.writeFile),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 移除文件
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     * @returns {Promise<void>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    unlink: promisify(Fs.unlink),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 测试路径是否存在 (同步)
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    existsSync: Fs.existsSync,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 复制文件/文件夹
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} srcPath 源路径
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} destPath 目标路径
 | 
				
			||||||
 | 
					     * @returns {Promise<boolean>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async copy(srcPath, destPath) {
 | 
				
			||||||
 | 
					        if (!FileUtil.existsSync(srcPath)) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const stats = await FileUtil.stat(srcPath);
 | 
				
			||||||
 | 
					        if (stats.isDirectory()) {
 | 
				
			||||||
 | 
					            if (!FileUtil.existsSync(destPath)) {
 | 
				
			||||||
 | 
					                await FileUtil.createDir(destPath);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const names = await FileUtil.readdir(srcPath);
 | 
				
			||||||
 | 
					            for (const name of names) {
 | 
				
			||||||
 | 
					                await FileUtil.copy(Path.join(srcPath, name), Path.join(destPath, name));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            await FileUtil.writeFile(destPath, await FileUtil.readFile(srcPath));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建文件夹 (递归)
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     * @returns {Promise<boolean>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async createDir(path) {
 | 
				
			||||||
 | 
					        if (FileUtil.existsSync(path)) {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            const dir = Path.dirname(path);
 | 
				
			||||||
 | 
					            if (await FileUtil.createDir(dir)) {
 | 
				
			||||||
 | 
					                await FileUtil.mkdir(path);
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 移除文件/文件夹 (递归)
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async remove(path) {
 | 
				
			||||||
 | 
					        if (!FileUtil.existsSync(path)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const stats = await FileUtil.stat(path);
 | 
				
			||||||
 | 
					        if (stats.isDirectory()) {
 | 
				
			||||||
 | 
					            const names = await FileUtil.readdir(path);
 | 
				
			||||||
 | 
					            for (const name of names) {
 | 
				
			||||||
 | 
					                await FileUtil.remove(Path.join(path, name));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            await FileUtil.rmdir(path);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            await FileUtil.unlink(path);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 遍历文件/文件夹并执行函数
 | 
				
			||||||
 | 
					     * @param {Fs.PathLike} path 路径
 | 
				
			||||||
 | 
					     * @param {(filePath: Fs.PathLike, stat: Fs.Stats) => void | Promise<void>} handler 处理函数
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async map(path, handler) {
 | 
				
			||||||
 | 
					        if (!FileUtil.existsSync(path)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const stats = await FileUtil.stat(path);
 | 
				
			||||||
 | 
					        if (stats.isDirectory()) {
 | 
				
			||||||
 | 
					            const names = await FileUtil.readdir(path);
 | 
				
			||||||
 | 
					            for (const name of names) {
 | 
				
			||||||
 | 
					                await FileUtil.map(Path.join(path, name), handler);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					           await handler(path, stats);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = FileUtil;
 | 
				
			||||||
							
								
								
									
										36
									
								
								src/eazax/i18n.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/eazax/i18n.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					const zh = require('../../i18n/zh');
 | 
				
			||||||
 | 
					const en = require('../../i18n/en');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 多语言
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210929
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const I18n = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 中文
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    zh,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 英文
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    en,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取多语言文本
 | 
				
			||||||
 | 
					     * @param {string} lang 语言
 | 
				
			||||||
 | 
					     * @param {string} key 关键字
 | 
				
			||||||
 | 
					     * @returns {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get(lang, key) {
 | 
				
			||||||
 | 
					        if (I18n[lang] && I18n[lang][key]) {
 | 
				
			||||||
 | 
					            return I18n[lang][key];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return key;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = I18n;
 | 
				
			||||||
							
								
								
									
										81
									
								
								src/eazax/main-event.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/eazax/main-event.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					const { ipcMain } = require('electron');
 | 
				
			||||||
 | 
					const PackageUtil = require('./package-util');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 包名 */
 | 
				
			||||||
 | 
					const PACKAGE_NAME = PackageUtil.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 主进程 IPC 事件
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210818
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const MainEvent = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 监听事件(一次性)
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     * @param {Function} callback 回调
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    once(channel, callback) {
 | 
				
			||||||
 | 
					        return ipcMain.once(`${PACKAGE_NAME}:${channel}`, callback);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 监听事件
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     * @param {Function} callback 回调
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    on(channel, callback) {
 | 
				
			||||||
 | 
					        return ipcMain.on(`${PACKAGE_NAME}:${channel}`, callback);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 取消事件监听
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     * @param {Function} callback 回调
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    removeListener(channel, callback) {
 | 
				
			||||||
 | 
					        return ipcMain.removeListener(`${PACKAGE_NAME}:${channel}`, callback);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 取消事件的所有监听
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    removeAllListeners(channel) {
 | 
				
			||||||
 | 
					        return ipcMain.removeAllListeners(`${PACKAGE_NAME}:${channel}`);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 发送事件到指定渲染进程
 | 
				
			||||||
 | 
					     * @param {Electron.WebContents} webContents 渲染进程事件对象
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     * @param {any[]?} args 参数
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    send(webContents, channel) {
 | 
				
			||||||
 | 
					        // return webContents.send(`${PACKAGE_NAME}:${channel}`, ...args);
 | 
				
			||||||
 | 
					        const args = [`${PACKAGE_NAME}:${channel}`];
 | 
				
			||||||
 | 
					        for (let i = 2, l = arguments.length; i < l; i++) {
 | 
				
			||||||
 | 
					            args.push(arguments[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return webContents.send.apply(webContents, args);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 回复事件给渲染进程
 | 
				
			||||||
 | 
					     * @param {Electron.IpcMainEvent} ipcMainEvent 事件对象
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     * @param {any[]?} args 参数
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    reply(ipcMainEvent, channel) {
 | 
				
			||||||
 | 
					        // return ipcMainEvent.reply(`${PACKAGE_NAME}:${channel}`, ...args);
 | 
				
			||||||
 | 
					        const args = [`${PACKAGE_NAME}:${channel}`];
 | 
				
			||||||
 | 
					        for (let i = 2, l = arguments.length; i < l; i++) {
 | 
				
			||||||
 | 
					            args.push(arguments[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return ipcMainEvent.reply.apply(ipcMainEvent, args);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = MainEvent;
 | 
				
			||||||
							
								
								
									
										47
									
								
								src/eazax/package-util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/eazax/package-util.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					const { shell } = require('electron');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 包信息 */
 | 
				
			||||||
 | 
					const PACKAGE_JSON = require('../../package.json');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 包工具
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210908
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const PackageUtil = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 包名
 | 
				
			||||||
 | 
					     * @type {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get name() {
 | 
				
			||||||
 | 
					        return PACKAGE_JSON.name;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 版本
 | 
				
			||||||
 | 
					     * @type {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get version() {
 | 
				
			||||||
 | 
					        return PACKAGE_JSON.version;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 仓库地址
 | 
				
			||||||
 | 
					     * @type {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get repository() {
 | 
				
			||||||
 | 
					        return PACKAGE_JSON.repository;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 打开仓库页面
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    openRepository() {
 | 
				
			||||||
 | 
					        const url = PackageUtil.repository;
 | 
				
			||||||
 | 
					        shell.openExternal(url);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = PackageUtil;
 | 
				
			||||||
							
								
								
									
										80
									
								
								src/eazax/renderer-event.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/eazax/renderer-event.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					const { ipcRenderer } = require('electron');
 | 
				
			||||||
 | 
					const PackageUtil = require('./package-util');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 包名 */
 | 
				
			||||||
 | 
					const PACKAGE_NAME = PackageUtil.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 渲染进程 IPC 事件
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210818
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const RendererEvent = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 监听事件(一次性)
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     * @param {Function} callback 回调
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    once(channel, callback) {
 | 
				
			||||||
 | 
					        return ipcRenderer.once(`${PACKAGE_NAME}:${channel}`, callback);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 监听事件
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     * @param {Function} callback 回调
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    on(channel, callback) {
 | 
				
			||||||
 | 
					        return ipcRenderer.on(`${PACKAGE_NAME}:${channel}`, callback);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 取消事件监听
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     * @param {Function} callback 回调
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    removeListener(channel, callback) {
 | 
				
			||||||
 | 
					        return ipcRenderer.removeListener(`${PACKAGE_NAME}:${channel}`, callback);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 取消事件的所有监听
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    removeAllListeners(channel) {
 | 
				
			||||||
 | 
					        return ipcRenderer.removeAllListeners(`${PACKAGE_NAME}:${channel}`);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 发送事件到主进程
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     * @param {...any} args 参数
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    send(channel) {
 | 
				
			||||||
 | 
					        // return ipcRenderer.send(`${PACKAGE_NAME}:${channel}`, ...args);
 | 
				
			||||||
 | 
					        const args = [`${PACKAGE_NAME}:${channel}`];
 | 
				
			||||||
 | 
					        for (let i = 1, l = arguments.length; i < l; i++) {
 | 
				
			||||||
 | 
					            args.push(arguments[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return ipcRenderer.send.apply(ipcRenderer, args);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 发送事件到主进程(同步)
 | 
				
			||||||
 | 
					     * @param {string} channel 频道
 | 
				
			||||||
 | 
					     * @param {...any} args 参数
 | 
				
			||||||
 | 
					     * @returns {Promise<any>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    sendSync(channel) {
 | 
				
			||||||
 | 
					        // return ipcRenderer.sendSync(`${PACKAGE_NAME}:${channel}`, ...args);
 | 
				
			||||||
 | 
					        const args = [`${PACKAGE_NAME}:${channel}`];
 | 
				
			||||||
 | 
					        for (let i = 1, l = arguments.length; i < l; i++) {
 | 
				
			||||||
 | 
					            args.push(arguments[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return ipcRenderer.sendSync.apply(ipcRenderer, args);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = RendererEvent;
 | 
				
			||||||
							
								
								
									
										92
									
								
								src/eazax/updater.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/eazax/updater.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					const fetch = require('../../lib/node-fetch');
 | 
				
			||||||
 | 
					const PackageUtil = require('./package-util');
 | 
				
			||||||
 | 
					const { compareVersion } = require('./version-util');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 本地版本 */
 | 
				
			||||||
 | 
					const LOCAL_VERSION = PackageUtil.version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 远程仓库地址 */
 | 
				
			||||||
 | 
					const REMOTE_URL = PackageUtil.repository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 更新器
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210804
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const Updater = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 远程仓库地址
 | 
				
			||||||
 | 
					     * @type {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get remote() {
 | 
				
			||||||
 | 
					        return REMOTE_URL;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 分支
 | 
				
			||||||
 | 
					     * @type {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    branch: 'master',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取远端的 package.json
 | 
				
			||||||
 | 
					     * @returns {Promise<object>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async getRemotePackageJson() {
 | 
				
			||||||
 | 
					        const packageJsonUrl = `${Updater.remote}/raw/${Updater.branch}/package.json`;
 | 
				
			||||||
 | 
					        // 发起网络请求
 | 
				
			||||||
 | 
					        const response = await fetch(packageJsonUrl, {
 | 
				
			||||||
 | 
					            method: 'GET',
 | 
				
			||||||
 | 
					            cache: 'no-cache',
 | 
				
			||||||
 | 
					            mode: 'no-cors',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        // 请求结果
 | 
				
			||||||
 | 
					        if (response.status !== 200) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 读取 json
 | 
				
			||||||
 | 
					        const json = response.json();
 | 
				
			||||||
 | 
					        return json;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取远端版本号
 | 
				
			||||||
 | 
					     * @returns {Promise<string>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async getRemoteVersion() {
 | 
				
			||||||
 | 
					        const package = await Updater.getRemotePackageJson();
 | 
				
			||||||
 | 
					        if (package && package.version) {
 | 
				
			||||||
 | 
					            return package.version;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取本地版本号
 | 
				
			||||||
 | 
					     * @returns {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getLocalVersion() {
 | 
				
			||||||
 | 
					        return LOCAL_VERSION;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 检查远端是否有新版本
 | 
				
			||||||
 | 
					     * @returns {Promise<boolean>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async check() {
 | 
				
			||||||
 | 
					        // 远端版本号
 | 
				
			||||||
 | 
					        const remoteVersion = await Updater.getRemoteVersion();
 | 
				
			||||||
 | 
					        if (!remoteVersion) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 本地版本号
 | 
				
			||||||
 | 
					        const localVersion = Updater.getLocalVersion();
 | 
				
			||||||
 | 
					        // 对比版本号
 | 
				
			||||||
 | 
					        const result = compareVersion(localVersion, remoteVersion);
 | 
				
			||||||
 | 
					        return (result < 0);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = Updater;
 | 
				
			||||||
							
								
								
									
										61
									
								
								src/eazax/version-util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/eazax/version-util.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 版本工具
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210814
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const VersionUtil = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 拆分版本号
 | 
				
			||||||
 | 
					     * @param {string | number} version 版本号文本
 | 
				
			||||||
 | 
					     * @returns {number[]}
 | 
				
			||||||
 | 
					     * @example
 | 
				
			||||||
 | 
					     * splitVersionString('1.2.0');  // [1, 2, 0]
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    splitVersionString(version) {
 | 
				
			||||||
 | 
					        if (typeof version === 'number') {
 | 
				
			||||||
 | 
					            return [version];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (typeof version === 'string') {
 | 
				
			||||||
 | 
					            return (
 | 
				
			||||||
 | 
					                version.replace(/-/g, '.')
 | 
				
			||||||
 | 
					                    .split('.')
 | 
				
			||||||
 | 
					                    .map(v => (parseInt(v) || 0))
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return [0];
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 对比版本号
 | 
				
			||||||
 | 
					     * @param {string | number} a 版本 a
 | 
				
			||||||
 | 
					     * @param {string | number} b 版本 b
 | 
				
			||||||
 | 
					     * @returns {-1 | 0 | 1}
 | 
				
			||||||
 | 
					     * @example
 | 
				
			||||||
 | 
					     * compareVersion('1.0.0', '1.0.1');    // -1
 | 
				
			||||||
 | 
					     * compareVersion('1.1.0', '1.1.0');    // 0
 | 
				
			||||||
 | 
					     * compareVersion('1.2.1', '1.2.0');    // 1
 | 
				
			||||||
 | 
					     * compareVersion('1.2.0.1', '1.2.0');  // 1
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    compareVersion(a, b) {
 | 
				
			||||||
 | 
					        const acs = VersionUtil.splitVersionString(a),
 | 
				
			||||||
 | 
					            bcs = VersionUtil.splitVersionString(b);
 | 
				
			||||||
 | 
					        const count = Math.max(acs.length, bcs.length);
 | 
				
			||||||
 | 
					        for (let i = 0; i < count; i++) {
 | 
				
			||||||
 | 
					            const ac = acs[i],
 | 
				
			||||||
 | 
					                bc = bcs[i];
 | 
				
			||||||
 | 
					            // 前者缺少分量或前者小于后者
 | 
				
			||||||
 | 
					            if (ac == undefined || ac < bc) {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // 后者缺少分量或前者大于后者
 | 
				
			||||||
 | 
					            if (bc == undefined || ac > bc) {
 | 
				
			||||||
 | 
					                return 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = VersionUtil;
 | 
				
			||||||
							
								
								
									
										80
									
								
								src/eazax/window-util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/eazax/window-util.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					const { BrowserWindow } = require('electron');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 窗口工具(主进程)
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210825
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const WindowUtil = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 最先打开的窗口
 | 
				
			||||||
 | 
					     * @returns {BrowserWindow}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getFirstWindow() {
 | 
				
			||||||
 | 
					        const wins = BrowserWindow.getAllWindows();
 | 
				
			||||||
 | 
					        return wins[wins.length - 1];
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取当前聚焦的窗口
 | 
				
			||||||
 | 
					     * @returns {BrowserWindow}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getFocusedWindow() {
 | 
				
			||||||
 | 
					        return BrowserWindow.getFocusedWindow();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 计算窗口位置(相对于最先打开的窗口)
 | 
				
			||||||
 | 
					     * @param {[number, number]} size 窗口尺寸
 | 
				
			||||||
 | 
					     * @param {'top' | 'center'} anchor 锚点
 | 
				
			||||||
 | 
					     * @returns {[number, number]}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    calcWindowPosition(size, anchor) {
 | 
				
			||||||
 | 
					        const win = WindowUtil.getFirstWindow();
 | 
				
			||||||
 | 
					        return WindowUtil.calcWindowPositionByTarget(size, anchor, win);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 计算窗口位置(相对于当前聚焦的窗口)
 | 
				
			||||||
 | 
					     * @param {[number, number]} size 窗口尺寸
 | 
				
			||||||
 | 
					     * @param {'top' | 'center'} anchor 锚点
 | 
				
			||||||
 | 
					     * @returns {[number, number]}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    calcWindowPositionByFocused(size, anchor) {
 | 
				
			||||||
 | 
					        const win = WindowUtil.getFocusedWindow();
 | 
				
			||||||
 | 
					        return WindowUtil.calcWindowPositionByTarget(size, anchor, win);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 计算窗口位置(相对于当前聚焦的窗口)
 | 
				
			||||||
 | 
					     * @param {[number, number]} size 窗口尺寸
 | 
				
			||||||
 | 
					     * @param {'top' | 'center'} anchor 锚点
 | 
				
			||||||
 | 
					     * @param {BrowserWindow} win 目标窗口
 | 
				
			||||||
 | 
					     * @returns {[number, number]}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    calcWindowPositionByTarget(size, anchor, win) {
 | 
				
			||||||
 | 
					        // 根据目标窗口的位置和尺寸来计算
 | 
				
			||||||
 | 
					        const winSize = win.getSize(),
 | 
				
			||||||
 | 
					            winPos = win.getPosition();
 | 
				
			||||||
 | 
					        // 注意:原点 (0, 0) 在屏幕左上角
 | 
				
			||||||
 | 
					        // 另外,窗口的位置值必须是整数,否则修改无效(像素的最小粒度为 1)
 | 
				
			||||||
 | 
					        const x = Math.floor(winPos[0] + (winSize[0] / 2) - (size[0] / 2));
 | 
				
			||||||
 | 
					        let y;
 | 
				
			||||||
 | 
					        switch (anchor) {
 | 
				
			||||||
 | 
					            case 'top': {
 | 
				
			||||||
 | 
					                y = Math.floor(winPos[1]);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					            case 'center': {
 | 
				
			||||||
 | 
					                y = Math.floor(winPos[1] + (winSize[1] / 2) - (size[1] / 2));
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return [x, y];
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = WindowUtil;
 | 
				
			||||||
							
								
								
									
										98
									
								
								src/main/editor-api.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/main/editor-api.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 编辑器 API(用于抹平不同版本编辑器之间的差异)
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210830
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const EditorAPI = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 当前语言
 | 
				
			||||||
 | 
					     * @returns {string}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getLanguage() {
 | 
				
			||||||
 | 
					        return Editor.lang || Editor.I18n.getLanguage();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 绝对路径转为UUID
 | 
				
			||||||
 | 
					     * @param {string} fspath 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fspathToUuid(fspath) {
 | 
				
			||||||
 | 
					        return Editor.assetdb.fspathToUuid(fspath);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 绝对路径转为编辑器资源路径
 | 
				
			||||||
 | 
					     * @param {string} fspath 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fspathToUrl(fspath) {
 | 
				
			||||||
 | 
					        return Editor.assetdb.fspathToUrl(fspath);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 编辑器资源路径转为绝对路径
 | 
				
			||||||
 | 
					     * @param {string} url 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    urlToFspath(url) {
 | 
				
			||||||
 | 
					        return Editor.assetdb.urlToFspath(url);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 通过 uuid 获取资源信息
 | 
				
			||||||
 | 
					     * @param {string} uuid 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    assetInfoByUuid(uuid) {
 | 
				
			||||||
 | 
					        return Editor.assetdb.assetInfoByUuid(uuid);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 通过 uuid 获取子资源信息
 | 
				
			||||||
 | 
					     * @param {string} uuid 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    subAssetInfosByUuid(uuid) {
 | 
				
			||||||
 | 
					        return Editor.assetdb.subAssetInfosByUuid(uuid);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取当前选中的资源 uuid
 | 
				
			||||||
 | 
					     * @returns {string[]}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getCurrentSelectedAssets() {
 | 
				
			||||||
 | 
					        return Editor.Selection.curSelection('asset');
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取当前选中的节点 uuid
 | 
				
			||||||
 | 
					     * @returns {string[]}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getCurrentSelectedNodes() {
 | 
				
			||||||
 | 
					        return Editor.Selection.curSelection('node');
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 是否为 uuid
 | 
				
			||||||
 | 
					     * @param {string} uuid 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isUuid(uuid) {
 | 
				
			||||||
 | 
					        return Editor.Utils.UuidUtils.isUuid(uuid);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 压缩 uuid
 | 
				
			||||||
 | 
					     * @param {string} uuid 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    compressUuid(uuid) {
 | 
				
			||||||
 | 
					        return Editor.Utils.UuidUtils.compressUuid(uuid);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 反压缩 uuid
 | 
				
			||||||
 | 
					     * @param {string} uuid 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    decompressUuid(uuid) {
 | 
				
			||||||
 | 
					        return Editor.Utils.UuidUtils.decompressUuid(uuid);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = EditorAPI;
 | 
				
			||||||
							
								
								
									
										248
									
								
								src/main/finder.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								src/main/finder.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,248 @@
 | 
				
			|||||||
 | 
					const { extname, basename } = require("path");
 | 
				
			||||||
 | 
					const EditorAPI = require("./editor-api");
 | 
				
			||||||
 | 
					const { print, translate } = require("../eazax/editor-main-util");
 | 
				
			||||||
 | 
					const FileUtil = require("../eazax/file-util");
 | 
				
			||||||
 | 
					const { containsValue } = require("./object-util");
 | 
				
			||||||
 | 
					const Parser = require("./parser");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 扩展名对应文件类型 */
 | 
				
			||||||
 | 
					const ASSET_TYPE_MAP = {
 | 
				
			||||||
 | 
					    // 场景
 | 
				
			||||||
 | 
					    '.fire': 'scene',
 | 
				
			||||||
 | 
					    '.scene': 'scene',
 | 
				
			||||||
 | 
					    // 预制体
 | 
				
			||||||
 | 
					    '.prefab': 'prefab',
 | 
				
			||||||
 | 
					    // 动画
 | 
				
			||||||
 | 
					    '.anim': 'animation',
 | 
				
			||||||
 | 
					    // 材质
 | 
				
			||||||
 | 
					    '.mtl': 'material',
 | 
				
			||||||
 | 
					    // 字体
 | 
				
			||||||
 | 
					    '.fnt.meta': 'font',
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 查找器
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const Finder = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 使用 uuid 进行查找
 | 
				
			||||||
 | 
					     * @param {string} uuid 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async findByUuid(uuid) {
 | 
				
			||||||
 | 
					        // 是否为有效 uuid
 | 
				
			||||||
 | 
					        if (!EditorAPI.isUuid(uuid)) {
 | 
				
			||||||
 | 
					            print('log', translate('invalid-uuid'), uuid);
 | 
				
			||||||
 | 
					            return [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 获取资源信息
 | 
				
			||||||
 | 
					        const assetInfo = EditorAPI.assetInfoByUuid(uuid);
 | 
				
			||||||
 | 
					        if (assetInfo) {
 | 
				
			||||||
 | 
					            // 记录子资源 uuid
 | 
				
			||||||
 | 
					            const subAssetUuids = [];
 | 
				
			||||||
 | 
					            // 资源类型检查
 | 
				
			||||||
 | 
					            if (assetInfo.type === 'texture') {
 | 
				
			||||||
 | 
					                // 纹理子资源
 | 
				
			||||||
 | 
					                const subAssetInfos = EditorAPI.subAssetInfosByUuid(uuid);
 | 
				
			||||||
 | 
					                if (subAssetInfos && subAssetInfos.length > 0) {
 | 
				
			||||||
 | 
					                    for (let i = 0; i < subAssetInfos.length; i++) {
 | 
				
			||||||
 | 
					                        subAssetUuids.push(subAssetInfos[i].uuid);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (assetInfo.type === 'typescript' || assetInfo.type === 'javascript') {
 | 
				
			||||||
 | 
					                // 脚本资源
 | 
				
			||||||
 | 
					                uuid = EditorAPI.compressUuid(uuid);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // 查找资源引用
 | 
				
			||||||
 | 
					            const results = [],
 | 
				
			||||||
 | 
					                selfResults = await Finder.findRefs(uuid);
 | 
				
			||||||
 | 
					            for (let i = 0, l = selfResults.length; i < l; i++) {
 | 
				
			||||||
 | 
					                results.push(selfResults[i]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // 查找子资源的引用
 | 
				
			||||||
 | 
					            if (subAssetUuids.length > 0) {
 | 
				
			||||||
 | 
					                for (let i = 0, l = subAssetUuids.length; i < l; i++) {
 | 
				
			||||||
 | 
					                    const subResults = await Finder.findRefs(subAssetUuids[i]);
 | 
				
			||||||
 | 
					                    for (let j = 0, l = subResults.length; j < l; j++) {
 | 
				
			||||||
 | 
					                        results.push(subResults[j]);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return results;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // 不存在的资源,直接查找 uuid
 | 
				
			||||||
 | 
					            print('log', translate('find-asset-refs'), uuid);
 | 
				
			||||||
 | 
					            return (await Finder.findRefs(uuid));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 查找引用
 | 
				
			||||||
 | 
					     * @param {string} uuid 
 | 
				
			||||||
 | 
					     * @returns {Promise<{ type: string, url: string, refs?: object[]}[]>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async findRefs(uuid) {
 | 
				
			||||||
 | 
					        const result = [];
 | 
				
			||||||
 | 
					        // 文件处理函数
 | 
				
			||||||
 | 
					        const handler = async (path, stats) => {
 | 
				
			||||||
 | 
					            const ext = extname(path);
 | 
				
			||||||
 | 
					            if (ext === '.fire' || ext === '.scene' || ext === '.prefab') {
 | 
				
			||||||
 | 
					                // 场景和预制体资源(转为节点树)
 | 
				
			||||||
 | 
					                const tree = await Parser.getNodeTree(path);
 | 
				
			||||||
 | 
					                if (!tree) {
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // 遍历第一层节点查找引用
 | 
				
			||||||
 | 
					                const refs = [];
 | 
				
			||||||
 | 
					                for (let children = tree.children, i = 0, l = children.length; i < l; i++) {
 | 
				
			||||||
 | 
					                    Finder.findRefsInNode(tree, children[i], uuid, refs);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // 保存当前文件引用结果
 | 
				
			||||||
 | 
					                if (refs.length > 0) {
 | 
				
			||||||
 | 
					                    result.push({
 | 
				
			||||||
 | 
					                        type: ASSET_TYPE_MAP[ext],
 | 
				
			||||||
 | 
					                        url: EditorAPI.fspathToUrl(path),
 | 
				
			||||||
 | 
					                        refs: refs,
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (ext === '.anim') {
 | 
				
			||||||
 | 
					                // 动画资源
 | 
				
			||||||
 | 
					                const data = JSON.parse(await FileUtil.readFile(path)),
 | 
				
			||||||
 | 
					                    curveData = data['curveData'],
 | 
				
			||||||
 | 
					                    contains = containsValue(curveData, uuid);
 | 
				
			||||||
 | 
					                if (contains) {
 | 
				
			||||||
 | 
					                    result.push({
 | 
				
			||||||
 | 
					                        type: ASSET_TYPE_MAP[ext],
 | 
				
			||||||
 | 
					                        url: EditorAPI.fspathToUrl(path),
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (ext === '.mtl' || path.endsWith('.fnt.meta')) {
 | 
				
			||||||
 | 
					                // 材质和字体资源
 | 
				
			||||||
 | 
					                const data = JSON.parse(await FileUtil.readFile(path));
 | 
				
			||||||
 | 
					                // 需排除自己
 | 
				
			||||||
 | 
					                if ((data['uuid'] === uuid)) {
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // 是否引用
 | 
				
			||||||
 | 
					                const contains = containsValue(data, uuid);
 | 
				
			||||||
 | 
					                if (contains) {
 | 
				
			||||||
 | 
					                    const _ext = (ext === '.mtl') ? '.mtl' : '.fnt.meta';
 | 
				
			||||||
 | 
					                    result.push({
 | 
				
			||||||
 | 
					                        type: ASSET_TYPE_MAP[_ext],
 | 
				
			||||||
 | 
					                        url: EditorAPI.fspathToUrl(path),
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        // 遍历资源目录下的文件
 | 
				
			||||||
 | 
					        const assetsPath = EditorAPI.urlToFspath('db://assets');
 | 
				
			||||||
 | 
					        await FileUtil.map(assetsPath, handler);
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 查找节点中的引用
 | 
				
			||||||
 | 
					     * @param {object} tree 节点树
 | 
				
			||||||
 | 
					     * @param {object} node 目标节点
 | 
				
			||||||
 | 
					     * @param {string} uuid 查找的 uuid
 | 
				
			||||||
 | 
					     * @param {object[]} result 结果
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    findRefsInNode(tree, node, uuid, result) {
 | 
				
			||||||
 | 
					        // 检查节点上的组件是否有引用
 | 
				
			||||||
 | 
					        const components = node.components;
 | 
				
			||||||
 | 
					        if (components && components.length > 0) {
 | 
				
			||||||
 | 
					            for (let i = 0, l = components.length; i < l; i++) {
 | 
				
			||||||
 | 
					                const properties = Finder.getContainsUuidProperties(components[i], uuid);
 | 
				
			||||||
 | 
					                if (properties.length === 0) {
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // 资源类型
 | 
				
			||||||
 | 
					                let type = components[i]['__type__'];
 | 
				
			||||||
 | 
					                // 是否为脚本资源
 | 
				
			||||||
 | 
					                if (EditorAPI.isUuid(type)) {
 | 
				
			||||||
 | 
					                    const scriptUuid = EditorAPI.decompressUuid(type),
 | 
				
			||||||
 | 
					                        assetInfo = EditorAPI.assetInfoByUuid(scriptUuid);
 | 
				
			||||||
 | 
					                    type = basename(assetInfo.url);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // 遍历相关属性名
 | 
				
			||||||
 | 
					                for (let i = 0; i < properties.length; i++) {
 | 
				
			||||||
 | 
					                    let property = properties[i];
 | 
				
			||||||
 | 
					                    if (property === '__type__') {
 | 
				
			||||||
 | 
					                        property = null;
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        // 处理属性名称(Label 组件需要特殊处理)
 | 
				
			||||||
 | 
					                        if (type === 'cc.Label' && property === '_N$file') {
 | 
				
			||||||
 | 
					                            property = 'font';
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        // 去除属性名的前缀
 | 
				
			||||||
 | 
					                        if (property.startsWith('_N$')) {
 | 
				
			||||||
 | 
					                            property = property.replace('_N$', '');
 | 
				
			||||||
 | 
					                        } else if (property[0] === '_') {
 | 
				
			||||||
 | 
					                            property = property.substring(1);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    // 保存结果
 | 
				
			||||||
 | 
					                    result.push({
 | 
				
			||||||
 | 
					                        node: node.path,
 | 
				
			||||||
 | 
					                        component: type,
 | 
				
			||||||
 | 
					                        property: property,
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 检查预制体是否有引用
 | 
				
			||||||
 | 
					        const prefab = node.prefab;
 | 
				
			||||||
 | 
					        if (prefab) {
 | 
				
			||||||
 | 
					            // 排除预制体自己
 | 
				
			||||||
 | 
					            if (uuid !== tree.uuid) {
 | 
				
			||||||
 | 
					                const contains = containsValue(prefab, uuid);
 | 
				
			||||||
 | 
					                if (contains) {
 | 
				
			||||||
 | 
					                    result.push({
 | 
				
			||||||
 | 
					                        node: node.path,
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 遍历子节点
 | 
				
			||||||
 | 
					        const children = node.children;
 | 
				
			||||||
 | 
					        if (children && children.length > 0) {
 | 
				
			||||||
 | 
					            for (let i = 0, l = children.length; i < l; i++) {
 | 
				
			||||||
 | 
					                Finder.findRefsInNode(tree, children[i], uuid, result);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取对象包含指定 uuid 的属性
 | 
				
			||||||
 | 
					     * @param {object} object 对象
 | 
				
			||||||
 | 
					     * @param {string} uuid 值
 | 
				
			||||||
 | 
					     * @returns {string[]}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getContainsUuidProperties(object, uuid) {
 | 
				
			||||||
 | 
					        const properties = [];
 | 
				
			||||||
 | 
					        const search = (target, path) => {
 | 
				
			||||||
 | 
					            if (Object.prototype.toString.call(target) === '[object Object]') {
 | 
				
			||||||
 | 
					                for (const key in target) {
 | 
				
			||||||
 | 
					                    const curPath = (path != null) ? `${path}.${key}` : key;
 | 
				
			||||||
 | 
					                    if (target[key] === uuid) {
 | 
				
			||||||
 | 
					                        properties.push(path || key);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    search(target[key], curPath);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (Array.isArray(target)) {
 | 
				
			||||||
 | 
					                for (let i = 0, l = target.length; i < l; i++) {
 | 
				
			||||||
 | 
					                    const curPath = (path != null) ? `${path}[${i}]` : `[${i}]`;
 | 
				
			||||||
 | 
					                    if (target[i] === uuid) {
 | 
				
			||||||
 | 
					                        properties.push(path || `[${i}]`);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    search(target[i], curPath);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        search(object, null);
 | 
				
			||||||
 | 
					        return properties;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = Finder;
 | 
				
			||||||
							
								
								
									
										155
									
								
								src/main/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/main/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
				
			|||||||
 | 
					const PanelManager = require('./panel-manager');
 | 
				
			||||||
 | 
					const ConfigManager = require('../common/config-manager');
 | 
				
			||||||
 | 
					const EditorMainKit = require('../eazax/editor-main-kit');
 | 
				
			||||||
 | 
					const { checkUpdate, print, translate } = require('../eazax/editor-main-util');
 | 
				
			||||||
 | 
					const { openRepository } = require('../eazax/package-util');
 | 
				
			||||||
 | 
					const EditorAPI = require('./editor-api');
 | 
				
			||||||
 | 
					const Parser = require('./parser');
 | 
				
			||||||
 | 
					const Finder = require('./finder');
 | 
				
			||||||
 | 
					const Printer = require('./printer');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 生命周期:加载
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function load() {
 | 
				
			||||||
 | 
					    // 监听事件
 | 
				
			||||||
 | 
					    EditorMainKit.register();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 生命周期:卸载
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function unload() {
 | 
				
			||||||
 | 
					    // 取消事件监听
 | 
				
			||||||
 | 
					    EditorMainKit.unregister();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 查找当前选中资源
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					async function findCurrentSelection() {
 | 
				
			||||||
 | 
					    // 过滤选中的资源 uuid
 | 
				
			||||||
 | 
					    const uuids = EditorAPI.getCurrentSelectedAssets();
 | 
				
			||||||
 | 
					    for (let i = 0; i < uuids.length; i++) {
 | 
				
			||||||
 | 
					        const assetInfo = EditorAPI.assetInfoByUuid(uuids[i]);
 | 
				
			||||||
 | 
					        if (assetInfo.type === 'folder') {
 | 
				
			||||||
 | 
					            uuids.splice(i--);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 未选择资源
 | 
				
			||||||
 | 
					    if (uuids.length === 0) {
 | 
				
			||||||
 | 
					        print('log', translate('please-select-assets'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 遍历查找
 | 
				
			||||||
 | 
					    for (let i = 0; i < uuids.length; i++) {
 | 
				
			||||||
 | 
					        const uuid = uuids[i],
 | 
				
			||||||
 | 
					            assetInfo = EditorAPI.assetInfoByUuid(uuid),
 | 
				
			||||||
 | 
					            shortUrl = assetInfo.url.replace('db://', '');
 | 
				
			||||||
 | 
					        // 查找引用
 | 
				
			||||||
 | 
					        print('log', '🔍', `${translate('find-asset-refs')} ${shortUrl}`);
 | 
				
			||||||
 | 
					        const refs = await Finder.findByUuid(uuid);
 | 
				
			||||||
 | 
					        if (refs.length === 0) {
 | 
				
			||||||
 | 
					            print('log', '📂', `${translate('no-refs')} ${shortUrl}`);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 打印结果
 | 
				
			||||||
 | 
					        Printer.printResult({
 | 
				
			||||||
 | 
					            type: assetInfo.type,
 | 
				
			||||||
 | 
					            uuid: uuid,
 | 
				
			||||||
 | 
					            url: assetInfo.url,
 | 
				
			||||||
 | 
					            path: assetInfo.path,
 | 
				
			||||||
 | 
					            refs: refs,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getSelection() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 资源变化回调
 | 
				
			||||||
 | 
					 * @param {{ type: string, uuid: string }} info 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function onAssetChanged(info) {
 | 
				
			||||||
 | 
					    const { type, uuid } = info;
 | 
				
			||||||
 | 
					    // 场景和预制体
 | 
				
			||||||
 | 
					    if (type === 'scene' || type === 'prefab') {
 | 
				
			||||||
 | 
					        const { url, path } = EditorAPI.assetInfoByUuid(uuid);
 | 
				
			||||||
 | 
					        // 排除内置资源
 | 
				
			||||||
 | 
					        if (url.indexOf('db://internal') !== -1) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 更新节点树
 | 
				
			||||||
 | 
					        Parser.updateCache(path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 扩展消息
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    messages: {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 查找当前选中资源
 | 
				
			||||||
 | 
					         * @param {*} event 
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        'find-current-selection'(event) {
 | 
				
			||||||
 | 
					            findCurrentSelection();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 打开设置面板
 | 
				
			||||||
 | 
					         * @param {*} event 
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        'open-settings-panel'(event) {
 | 
				
			||||||
 | 
					            PanelManager.openSettingsPanel();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 检查更新
 | 
				
			||||||
 | 
					         * @param {*} event 
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        'menu-check-update'(event) {
 | 
				
			||||||
 | 
					            checkUpdate(true);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 版本
 | 
				
			||||||
 | 
					         * @param {*} event 
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        'menu-version'(event) {
 | 
				
			||||||
 | 
					            openRepository();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 场景面板加载完成后
 | 
				
			||||||
 | 
					         * @param {*} event 
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        'scene:ready'(event) {
 | 
				
			||||||
 | 
					            // 自动检查更新
 | 
				
			||||||
 | 
					            const config = ConfigManager.get();
 | 
				
			||||||
 | 
					            if (config.autoCheckUpdate) {
 | 
				
			||||||
 | 
					                checkUpdate(false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 资源变化
 | 
				
			||||||
 | 
					         * @param {*} event 
 | 
				
			||||||
 | 
					         * @param {{ type: string, uuid: string }} info 
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        'asset-db:asset-changed'(event, info) {
 | 
				
			||||||
 | 
					            onAssetChanged(info);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    load,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unload,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										70
									
								
								src/main/object-util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/main/object-util.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 对象工具
 | 
				
			||||||
 | 
					 * @author 陈皮皮 (ifaswind)
 | 
				
			||||||
 | 
					 * @version 20210929
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const ObjectUtil = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 判断指定值是否是一个对象
 | 
				
			||||||
 | 
					     * @param {any} arg 参数
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isObject(arg) {
 | 
				
			||||||
 | 
					        return Object.prototype.toString.call(arg) === '[object Object]';
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 对象中是否包含指定的属性
 | 
				
			||||||
 | 
					     * @param {object} object 对象
 | 
				
			||||||
 | 
					     * @param {string} name 属性名
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    containsProperty(object, name) {
 | 
				
			||||||
 | 
					        let result = false;
 | 
				
			||||||
 | 
					        const search = (_object) => {
 | 
				
			||||||
 | 
					            if (ObjectUtil.isObject(_object)) {
 | 
				
			||||||
 | 
					                for (const key in _object) {
 | 
				
			||||||
 | 
					                    if (key == name) {
 | 
				
			||||||
 | 
					                        result = true;
 | 
				
			||||||
 | 
					                        return;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    search(_object[key]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (Array.isArray(_object)) {
 | 
				
			||||||
 | 
					                for (let i = 0, l = _object.length; i < l; i++) {
 | 
				
			||||||
 | 
					                    search(_object[i]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        search(object);
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 对象中是否包含指定的值
 | 
				
			||||||
 | 
					     * @param {object} object 对象
 | 
				
			||||||
 | 
					     * @param {any} value 值
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    containsValue(object, value) {
 | 
				
			||||||
 | 
					        let result = false;
 | 
				
			||||||
 | 
					        const search = (_object) => {
 | 
				
			||||||
 | 
					            if (ObjectUtil.isObject(_object)) {
 | 
				
			||||||
 | 
					                for (const key in _object) {
 | 
				
			||||||
 | 
					                    if (_object[key] === value) {
 | 
				
			||||||
 | 
					                        result = true;
 | 
				
			||||||
 | 
					                        return;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    search(_object[key]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (Array.isArray(_object)) {
 | 
				
			||||||
 | 
					                for (let i = 0, l = _object.length; i < l; i++) {
 | 
				
			||||||
 | 
					                    search(_object[i]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        search(object);
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = ObjectUtil;
 | 
				
			||||||
							
								
								
									
										86
									
								
								src/main/panel-manager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/main/panel-manager.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					const { BrowserWindow } = require('electron');
 | 
				
			||||||
 | 
					const { join } = require('path');
 | 
				
			||||||
 | 
					const { language, translate } = require('../eazax/editor-main-util');
 | 
				
			||||||
 | 
					const { calcWindowPosition } = require('../eazax/window-util');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 扩展名称 */
 | 
				
			||||||
 | 
					const EXTENSION_NAME = translate('name');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 面板管理器 (主进程)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const PanelManager = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 面板实例
 | 
				
			||||||
 | 
					     * @type {BrowserWindow}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    settings: null,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 打开设置面板
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    openSettingsPanel() {
 | 
				
			||||||
 | 
					        // 已打开则直接展示
 | 
				
			||||||
 | 
					        if (PanelManager.settings) {
 | 
				
			||||||
 | 
					            PanelManager.settings.show();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 窗口尺寸和位置
 | 
				
			||||||
 | 
					        const winSize = [500, 346],
 | 
				
			||||||
 | 
					            winPos = calcWindowPosition(winSize, 'center');
 | 
				
			||||||
 | 
					        // 创建窗口
 | 
				
			||||||
 | 
					        const win = PanelManager.settings = new BrowserWindow({
 | 
				
			||||||
 | 
					            width: winSize[0],
 | 
				
			||||||
 | 
					            height: winSize[1],
 | 
				
			||||||
 | 
					            minWidth: winSize[0],
 | 
				
			||||||
 | 
					            minHeight: winSize[1],
 | 
				
			||||||
 | 
					            x: winPos[0],
 | 
				
			||||||
 | 
					            y: winPos[1] - 100,
 | 
				
			||||||
 | 
					            useContentSize: true,
 | 
				
			||||||
 | 
					            frame: true,
 | 
				
			||||||
 | 
					            title: `${EXTENSION_NAME} | Cocos Creator`,
 | 
				
			||||||
 | 
					            autoHideMenuBar: true,
 | 
				
			||||||
 | 
					            resizable: true,
 | 
				
			||||||
 | 
					            minimizable: false,
 | 
				
			||||||
 | 
					            maximizable: false,
 | 
				
			||||||
 | 
					            fullscreenable: false,
 | 
				
			||||||
 | 
					            skipTaskbar: false,
 | 
				
			||||||
 | 
					            alwaysOnTop: true,
 | 
				
			||||||
 | 
					            hasShadow: true,
 | 
				
			||||||
 | 
					            show: false,
 | 
				
			||||||
 | 
					            webPreferences: {
 | 
				
			||||||
 | 
					                nodeIntegration: true,
 | 
				
			||||||
 | 
					                contextIsolation: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        // 就绪后(展示,避免闪烁)
 | 
				
			||||||
 | 
					        win.on('ready-to-show', () => win.show());
 | 
				
			||||||
 | 
					        // 关闭后
 | 
				
			||||||
 | 
					        win.on('closed', () => (PanelManager.settings = null));
 | 
				
			||||||
 | 
					        // 监听按键
 | 
				
			||||||
 | 
					        win.webContents.on('before-input-event', (event, input) => {
 | 
				
			||||||
 | 
					            if (input.key === 'Escape') PanelManager.closeSettingsPanel();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        // 调试用的 devtools
 | 
				
			||||||
 | 
					        // win.webContents.openDevTools({ mode: 'detach' });
 | 
				
			||||||
 | 
					        // 加载页面
 | 
				
			||||||
 | 
					        const path = join(__dirname, '../renderer/settings/index.html');
 | 
				
			||||||
 | 
					        win.loadURL(`file://${path}?lang=${language}`);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 关闭面板
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    closeSettingsPanel() {
 | 
				
			||||||
 | 
					        if (!PanelManager.settings) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        PanelManager.settings.hide();
 | 
				
			||||||
 | 
					        PanelManager.settings.close();
 | 
				
			||||||
 | 
					        PanelManager.settings = null;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = PanelManager;
 | 
				
			||||||
							
								
								
									
										161
									
								
								src/main/parser.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								src/main/parser.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
				
			|||||||
 | 
					const { print } = require("../eazax/editor-main-util");
 | 
				
			||||||
 | 
					const FileUtil = require("../eazax/file-util");
 | 
				
			||||||
 | 
					const { containsProperty } = require("./object-util");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 解析器
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const Parser = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 节点树缓存
 | 
				
			||||||
 | 
					     * @type {{ [key: string]: object }}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    caches: Object.create(null),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取节点树
 | 
				
			||||||
 | 
					     * @param {string} path 路径
 | 
				
			||||||
 | 
					     * @returns {Promise<object>}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async getNodeTree(path) {
 | 
				
			||||||
 | 
					        if (!Parser.caches[path]) {
 | 
				
			||||||
 | 
					            const file = await FileUtil.readFile(path);
 | 
				
			||||||
 | 
					            let data = null;
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                data = JSON.parse(file);
 | 
				
			||||||
 | 
					            } catch (error) {
 | 
				
			||||||
 | 
					                print('warn', '文件解析失败', path);
 | 
				
			||||||
 | 
					                print('warn', error);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (!data) {
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Parser.caches[path] = Parser.convert(data);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return Parser.caches[path];
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 更新缓存
 | 
				
			||||||
 | 
					     * @param {string} path 路径
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async updateCache(path) {
 | 
				
			||||||
 | 
					        Parser.caches[path] = null;
 | 
				
			||||||
 | 
					        await Parser.getNodeTree(path);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 将资源解析为节点树
 | 
				
			||||||
 | 
					     * @param {object} source 源数据
 | 
				
			||||||
 | 
					     * @returns {object}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    convert(source) {
 | 
				
			||||||
 | 
					        const tree = Object.create(null),
 | 
				
			||||||
 | 
					            type = source[0]['__type__'];
 | 
				
			||||||
 | 
					        if (type === 'cc.SceneAsset') {
 | 
				
			||||||
 | 
					            // 场景资源
 | 
				
			||||||
 | 
					            const sceneId = source[0]['scene']['__id__'],
 | 
				
			||||||
 | 
					                children = source[sceneId]['_children'];
 | 
				
			||||||
 | 
					            tree.type = 'cc.Scene';  // 类型
 | 
				
			||||||
 | 
					            tree.id = sceneId;       // ID
 | 
				
			||||||
 | 
					            // 场景下可以有多个一级节点
 | 
				
			||||||
 | 
					            tree.children = [];
 | 
				
			||||||
 | 
					            for (let i = 0, l = children.length; i < l; i++) {
 | 
				
			||||||
 | 
					                const nodeId = children[i]['__id__'];
 | 
				
			||||||
 | 
					                Parser.convertNode(source, nodeId, tree);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else if (type === 'cc.Prefab') {
 | 
				
			||||||
 | 
					            // 预制体资源 
 | 
				
			||||||
 | 
					            const uuid = source[source.length - 1]['asset']['__uuid__'];
 | 
				
			||||||
 | 
					            tree.type = 'cc.Prefab';  // 类型
 | 
				
			||||||
 | 
					            tree.uuid = uuid;         // uuid
 | 
				
			||||||
 | 
					            // 预制体本身就是一个节点
 | 
				
			||||||
 | 
					            tree.children = [];
 | 
				
			||||||
 | 
					            const nodeId = source[0]['data']['__id__'];
 | 
				
			||||||
 | 
					            Parser.convertNode(source, nodeId, tree);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return tree;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 解析节点
 | 
				
			||||||
 | 
					     * @param {object} source 源数据
 | 
				
			||||||
 | 
					     * @param {number} nodeId 节点 ID
 | 
				
			||||||
 | 
					     * @param {object} parent 父节点
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    convertNode(source, nodeId, parent) {
 | 
				
			||||||
 | 
					        const srcNode = source[nodeId],
 | 
				
			||||||
 | 
					            node = Object.create(null);
 | 
				
			||||||
 | 
					        // 基本信息
 | 
				
			||||||
 | 
					        node.name = srcNode['_name'];
 | 
				
			||||||
 | 
					        node.id = nodeId;
 | 
				
			||||||
 | 
					        node.type = srcNode['__type__'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 路径
 | 
				
			||||||
 | 
					        const parentPath = parent.path || null;
 | 
				
			||||||
 | 
					        node.path = parentPath ? `${parentPath}/${node.name}` : node.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 预制体引用
 | 
				
			||||||
 | 
					        const srcPrefab = srcNode['_prefab'];
 | 
				
			||||||
 | 
					        if (srcPrefab) {
 | 
				
			||||||
 | 
					            const id = srcPrefab['__id__'];
 | 
				
			||||||
 | 
					            node.prefab = Parser.extractValidInfo(source[id]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 组件
 | 
				
			||||||
 | 
					        node.components = [];
 | 
				
			||||||
 | 
					        const srcComponents = srcNode['_components'];
 | 
				
			||||||
 | 
					        if (srcComponents && srcComponents.length > 0) {
 | 
				
			||||||
 | 
					            for (let i = 0, l = srcComponents.length; i < l; i++) {
 | 
				
			||||||
 | 
					                const compId = srcComponents[i]['__id__'],
 | 
				
			||||||
 | 
					                    component = Parser.extractValidInfo(source[compId]);
 | 
				
			||||||
 | 
					                node.components.push(component);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 子节点
 | 
				
			||||||
 | 
					        node.children = [];
 | 
				
			||||||
 | 
					        const srcChildren = srcNode['_children'];
 | 
				
			||||||
 | 
					        if (srcChildren && srcChildren.length > 0) {
 | 
				
			||||||
 | 
					            for (let i = 0, l = srcChildren.length; i < l; i++) {
 | 
				
			||||||
 | 
					                const nodeId = srcChildren[i]['__id__'];
 | 
				
			||||||
 | 
					                Parser.convertNode(source, nodeId, node);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 保存到父节点
 | 
				
			||||||
 | 
					        parent.children.push(node);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 提取有效信息(含有 uuid)
 | 
				
			||||||
 | 
					     * @param {object} source 源数据
 | 
				
			||||||
 | 
					     * @returns {{ __type__: string, _name: string, fileId?: string }}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    extractValidInfo(source) {
 | 
				
			||||||
 | 
					        const result = Object.create(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 记录有用的属性
 | 
				
			||||||
 | 
					        const keys = ['__type__', '_name', 'fileId'];
 | 
				
			||||||
 | 
					        for (let i = 0, l = keys.length; i < l; i++) {
 | 
				
			||||||
 | 
					            const key = keys[i];
 | 
				
			||||||
 | 
					            if (source[key] !== undefined) {
 | 
				
			||||||
 | 
					                result[key] = source[key];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 记录包含 uuid 的属性
 | 
				
			||||||
 | 
					        for (const key in source) {
 | 
				
			||||||
 | 
					            const contains = containsProperty(source[key], '__uuid__');
 | 
				
			||||||
 | 
					            if (contains) {
 | 
				
			||||||
 | 
					                result[key] = source[key];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = Parser;
 | 
				
			||||||
							
								
								
									
										108
									
								
								src/main/printer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/main/printer.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
				
			|||||||
 | 
					const { translate, print, pureWithoutTitle } = require('../eazax/editor-main-util');
 | 
				
			||||||
 | 
					const ConfigManager = require('../common/config-manager');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 图标表 */
 | 
				
			||||||
 | 
					const ICON_MAP = {
 | 
				
			||||||
 | 
					    'scene': '🔥',
 | 
				
			||||||
 | 
					    'prefab': '💠',
 | 
				
			||||||
 | 
					    'node': '🎲',
 | 
				
			||||||
 | 
					    'component': '🧩',
 | 
				
			||||||
 | 
					    'property': '📄',
 | 
				
			||||||
 | 
					    'asset': '📦',
 | 
				
			||||||
 | 
					    'asset-info': '📋',
 | 
				
			||||||
 | 
					    'node-refs': '📙',
 | 
				
			||||||
 | 
					    'asset-refs': '📗',
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 打印机
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const Printer = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 打印结果至控制台
 | 
				
			||||||
 | 
					     * @param {object} result 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    printResult(result) {
 | 
				
			||||||
 | 
					        if (!result) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const { printDetails, printFolding } = ConfigManager.get();
 | 
				
			||||||
 | 
					        // 标志位
 | 
				
			||||||
 | 
					        const nodeRefs = [], assetRefs = [];
 | 
				
			||||||
 | 
					        let nodeRefsCount = 0, assetRefsCount = 0;
 | 
				
			||||||
 | 
					        // 遍历引用信息
 | 
				
			||||||
 | 
					        for (let refs = result.refs, i = 0, l = refs.length; i < l; i++) {
 | 
				
			||||||
 | 
					            const ref = refs[i],
 | 
				
			||||||
 | 
					                type = ref.type,
 | 
				
			||||||
 | 
					                url = ref.url.replace('db://', '').replace('.meta', '');
 | 
				
			||||||
 | 
					            if (type === 'scene' || type === 'prefab') {
 | 
				
			||||||
 | 
					                // 场景或预制体
 | 
				
			||||||
 | 
					                nodeRefs.push(`  ${ICON_MAP[type]} [${translate(type)}] ${url}`);
 | 
				
			||||||
 | 
					                // 节点引用
 | 
				
			||||||
 | 
					                for (let details = ref.refs, j = 0, l = details.length; j < l; j++) {
 | 
				
			||||||
 | 
					                    nodeRefsCount++;
 | 
				
			||||||
 | 
					                    // 详情
 | 
				
			||||||
 | 
					                    if (printDetails) {
 | 
				
			||||||
 | 
					                        const detail = details[j];
 | 
				
			||||||
 | 
					                        let item = `    ${ICON_MAP['node']} [${translate('node')}] ${detail.node}`;
 | 
				
			||||||
 | 
					                        if (detail.component) {
 | 
				
			||||||
 | 
					                            item += `  →  ${ICON_MAP['component']} [${translate('component')}] ${detail.component}`;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (detail.property) {
 | 
				
			||||||
 | 
					                            item += `  →  ${ICON_MAP['property']} [${translate('property')}] ${detail.property}`;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        nodeRefs.push(item);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // 资源引用
 | 
				
			||||||
 | 
					                assetRefsCount++;
 | 
				
			||||||
 | 
					                assetRefs.push(`  ${ICON_MAP['asset']} [${translate(type)}] ${url}`);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 组装文本
 | 
				
			||||||
 | 
					        const texts = [];
 | 
				
			||||||
 | 
					        // 分割线
 | 
				
			||||||
 | 
					        texts.push(`${'- - '.repeat(36)}`);
 | 
				
			||||||
 | 
					        // 基础信息
 | 
				
			||||||
 | 
					        texts.push(`${ICON_MAP['asset-info']} ${translate('asset-info')}`);
 | 
				
			||||||
 | 
					        texts.push(`  - ${translate('asset-type')}${result.type}`);
 | 
				
			||||||
 | 
					        texts.push(`  - ${translate('asset-uuid')}${result.uuid}`);
 | 
				
			||||||
 | 
					        texts.push(`  - ${translate('asset-url')}${result.url}`);
 | 
				
			||||||
 | 
					        texts.push(`  - ${translate('asset-path')}${result.path}`);
 | 
				
			||||||
 | 
					        // 分割线
 | 
				
			||||||
 | 
					        texts.push(`${'- - '.repeat(36)}`);
 | 
				
			||||||
 | 
					        // 节点引用
 | 
				
			||||||
 | 
					        if (nodeRefs.length > 0) {
 | 
				
			||||||
 | 
					            texts.push(`${ICON_MAP['node-refs']} ${translate('node-refs')} x ${nodeRefsCount}`);
 | 
				
			||||||
 | 
					            for (let i = 0, l = nodeRefs.length; i < l; i++) {
 | 
				
			||||||
 | 
					                texts.push(nodeRefs[i]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 资源引用
 | 
				
			||||||
 | 
					        if (assetRefs.length > 0) {
 | 
				
			||||||
 | 
					            texts.push(`${ICON_MAP['asset-refs']} ${translate('asset-refs')} x ${assetRefsCount}`);
 | 
				
			||||||
 | 
					            for (let i = 0, l = assetRefs.length; i < l; i++) {
 | 
				
			||||||
 | 
					                texts.push(assetRefs[i]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 结尾分割线
 | 
				
			||||||
 | 
					        texts.push(`${'- - '.repeat(36)}`);
 | 
				
			||||||
 | 
					        // 打印到控制台
 | 
				
			||||||
 | 
					        if (printFolding) {
 | 
				
			||||||
 | 
					            // 单行打印
 | 
				
			||||||
 | 
					            texts.unshift(`🗂 ${translate('result')} >>>`);
 | 
				
			||||||
 | 
					            print('log', texts.join('\n'));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // 逐行打印
 | 
				
			||||||
 | 
					            print('log', translate('result'));
 | 
				
			||||||
 | 
					            for (let i = 0, l = texts.length; i < l; i++) {
 | 
				
			||||||
 | 
					                pureWithoutTitle(`  ${texts[i]}`);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = Printer;
 | 
				
			||||||
							
								
								
									
										61
									
								
								src/renderer/settings/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/renderer/settings/index.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					* {
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					body {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  padding: 0 12px;
 | 
				
			||||||
 | 
					  background-color: #454545;
 | 
				
			||||||
 | 
					  color: #bdbdbd;
 | 
				
			||||||
 | 
					  user-select: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#app {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 标题 */
 | 
				
			||||||
 | 
					.title {
 | 
				
			||||||
 | 
					  font-size: 20px;
 | 
				
			||||||
 | 
					  font-weight: 800;
 | 
				
			||||||
 | 
					  padding: 10px 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 属性容器 */
 | 
				
			||||||
 | 
					.properties {
 | 
				
			||||||
 | 
					  overflow: visible;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 应用按钮 */
 | 
				
			||||||
 | 
					.apply-btn {
 | 
				
			||||||
 | 
					  min-width: 20px;
 | 
				
			||||||
 | 
					  height: 33px;
 | 
				
			||||||
 | 
					  background-image: linear-gradient(#4281b6, #4281b6);
 | 
				
			||||||
 | 
					  border: 1px solid #171717;
 | 
				
			||||||
 | 
					  border-radius: 3px;
 | 
				
			||||||
 | 
					  color: #fff;
 | 
				
			||||||
 | 
					  font-size: 16px;
 | 
				
			||||||
 | 
					  font-weight: 800;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.apply-btn:hover {
 | 
				
			||||||
 | 
					  background-image: none;
 | 
				
			||||||
 | 
					  background-color: #4c87b6;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.apply-btn:active {
 | 
				
			||||||
 | 
					  background-image: none;
 | 
				
			||||||
 | 
					  background-color: #2e6da2;
 | 
				
			||||||
 | 
					  border-color: #fd942b;
 | 
				
			||||||
 | 
					  color: #cdcdcd;
 | 
				
			||||||
 | 
					  box-shadow: 1px 1px 10px #262626 inset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[v-cloak] {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										90
									
								
								src/renderer/settings/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/renderer/settings/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="utf-8">
 | 
				
			||||||
 | 
					    <!-- 样式 -->
 | 
				
			||||||
 | 
					    <link rel="stylesheet" type="text/css" href="../../eazax/css/cocos-tag.css">
 | 
				
			||||||
 | 
					    <link rel="stylesheet" type="text/css" href="../../eazax/css/cocos-class.css">
 | 
				
			||||||
 | 
					    <link rel="stylesheet" type="text/css" href="index.css">
 | 
				
			||||||
 | 
					    <!-- 脚本 -->
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="../../../lib/vue.global.prod.js" defer></script>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="index.js" defer></script>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					    <div id="app" v-cloak>
 | 
				
			||||||
 | 
					        <!-- 标题 -->
 | 
				
			||||||
 | 
					        <div class="title">{{ t('settings') }}</div>
 | 
				
			||||||
 | 
					        <!-- 配置 -->
 | 
				
			||||||
 | 
					        <div class="properties">
 | 
				
			||||||
 | 
					            <!-- 选择快捷键 -->
 | 
				
			||||||
 | 
					            <div class="property">
 | 
				
			||||||
 | 
					                <div class="label">
 | 
				
			||||||
 | 
					                    <span class="text">{{ t('select-key') }}</span>
 | 
				
			||||||
 | 
					                    <span class="tooltip">{{ t('select-key-tooltip') }}</span>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="content">
 | 
				
			||||||
 | 
					                    <select v-model="selectKey">
 | 
				
			||||||
 | 
					                        <option v-for="item in presets" :key="item.key" :value="item.key">{{ item.name }}</option>
 | 
				
			||||||
 | 
					                    </select>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <!-- 自定义快捷键 -->
 | 
				
			||||||
 | 
					            <div class="property">
 | 
				
			||||||
 | 
					                <div class="label">
 | 
				
			||||||
 | 
					                    <span class="text">{{ t('custom-key') }}</span>
 | 
				
			||||||
 | 
					                    <span class="tooltip">{{ t('custom-key-tooltip') }}</span>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="content">
 | 
				
			||||||
 | 
					                    <input v-model="customKey" :placeholder="t('custom-key-placeholder')" />
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <!-- 展示详情 -->
 | 
				
			||||||
 | 
					            <div class="property">
 | 
				
			||||||
 | 
					                <div class="label">
 | 
				
			||||||
 | 
					                    <span class="text">{{ t('print-details') }}</span>
 | 
				
			||||||
 | 
					                    <span class="tooltip">{{ t('print-details-tooltip') }}</span>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="content">
 | 
				
			||||||
 | 
					                    <input type="checkbox" v-model="printDetails" />
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <!-- 折叠结果 -->
 | 
				
			||||||
 | 
					            <div class="property">
 | 
				
			||||||
 | 
					                <div class="label">
 | 
				
			||||||
 | 
					                    <span class="text">{{ t('print-folding') }}</span>
 | 
				
			||||||
 | 
					                    <span class="tooltip">{{ t('print-folding-tooltip') }}</span>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="content">
 | 
				
			||||||
 | 
					                    <input type="checkbox" v-model="printFolding" />
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <!-- 自动检查更新 -->
 | 
				
			||||||
 | 
					            <div class="property">
 | 
				
			||||||
 | 
					                <div class="label">
 | 
				
			||||||
 | 
					                    <span class="text">{{ t('auto-check-update') }}</span>
 | 
				
			||||||
 | 
					                    <span class="tooltip">{{ t('auto-check-update-tooltip') }}</span>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="content">
 | 
				
			||||||
 | 
					                    <input type="checkbox" v-model="autoCheckUpdate" />
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <!-- 快捷键参考 -->
 | 
				
			||||||
 | 
					            <div class="tip">
 | 
				
			||||||
 | 
					                <span>{{ t('reference') }}</span>
 | 
				
			||||||
 | 
					                <a href="https://www.electronjs.org/docs/api/accelerator" target="_blank">{{ t('accelerator') }}</a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <!-- Git 仓库 -->
 | 
				
			||||||
 | 
					            <div class="tip">
 | 
				
			||||||
 | 
					                <span>{{ t('repository') }}</span>
 | 
				
			||||||
 | 
					                <a :href="repositoryUrl" target="_blank">{{ packageName }}</a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="line"></div>
 | 
				
			||||||
 | 
					            <!-- 应用按钮 -->
 | 
				
			||||||
 | 
					            <button class="apply-btn" @click="onApplyBtnClick">{{ t('apply') }}</button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										191
									
								
								src/renderer/settings/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								src/renderer/settings/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
				
			|||||||
 | 
					const { shell } = require('electron');
 | 
				
			||||||
 | 
					const { getUrlParam } = require('../../eazax/browser-util');
 | 
				
			||||||
 | 
					const I18n = require('../../eazax/i18n');
 | 
				
			||||||
 | 
					const RendererEvent = require('../../eazax/renderer-event');
 | 
				
			||||||
 | 
					const PackageUtil = require('../../eazax/package-util');
 | 
				
			||||||
 | 
					const EditorRendererKit = require('../../eazax/editor-renderer-kit');
 | 
				
			||||||
 | 
					const ConfigManager = require('../../common/config-manager');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 导入 Vue 工具函数
 | 
				
			||||||
 | 
					const { ref, watch, onMounted, onBeforeUnmount, createApp } = Vue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 当前语言 */
 | 
				
			||||||
 | 
					const LANG = getUrlParam('lang');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 构建 Vue 应用
 | 
				
			||||||
 | 
					const App = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 设置
 | 
				
			||||||
 | 
					     * @param {*} props 
 | 
				
			||||||
 | 
					     * @param {*} context 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    setup(props, context) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 预设快捷键
 | 
				
			||||||
 | 
					        const presets = ref([
 | 
				
			||||||
 | 
					            { key: '', name: t('none') },
 | 
				
			||||||
 | 
					            { key: 'custom', name: t('custom-key') },
 | 
				
			||||||
 | 
					            { key: 'F1', name: 'F1' },
 | 
				
			||||||
 | 
					            { key: 'F3', name: 'F3' },
 | 
				
			||||||
 | 
					            { key: 'F4', name: 'F4' },
 | 
				
			||||||
 | 
					            { key: 'F5', name: 'F5' },
 | 
				
			||||||
 | 
					            { key: 'F6', name: 'F6' },
 | 
				
			||||||
 | 
					            { key: 'CmdOrCtrl+F', name: 'Cmd/Ctrl + F' },
 | 
				
			||||||
 | 
					            { key: 'CmdOrCtrl+B', name: 'Cmd/Ctrl + B' },
 | 
				
			||||||
 | 
					            { key: 'CmdOrCtrl+Shift+F', name: 'Cmd/Ctrl + Shift + F' },
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					        // 选择
 | 
				
			||||||
 | 
					        const selectKey = ref('');
 | 
				
			||||||
 | 
					        // 自定义
 | 
				
			||||||
 | 
					        const customKey = ref('');
 | 
				
			||||||
 | 
					        // 打印详情
 | 
				
			||||||
 | 
					        const printDetails = ref(true);
 | 
				
			||||||
 | 
					        // 单行打印
 | 
				
			||||||
 | 
					        const printFolding = ref(true);
 | 
				
			||||||
 | 
					        // 自动检查更新
 | 
				
			||||||
 | 
					        const autoCheckUpdate = ref(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 仓库地址
 | 
				
			||||||
 | 
					        const repositoryUrl = PackageUtil.repository;
 | 
				
			||||||
 | 
					        // 包名
 | 
				
			||||||
 | 
					        const packageName = PackageUtil.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 监听选择快捷键
 | 
				
			||||||
 | 
					        watch(selectKey, (value) => {
 | 
				
			||||||
 | 
					            if (value !== 'custom') {
 | 
				
			||||||
 | 
					                customKey.value = '';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 监听自定义
 | 
				
			||||||
 | 
					        watch(customKey, (value) => {
 | 
				
			||||||
 | 
					            if (value !== '' && selectKey.value !== 'custom') {
 | 
				
			||||||
 | 
					                selectKey.value = 'custom';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 获取配置
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        function getConfig() {
 | 
				
			||||||
 | 
					            const config = ConfigManager.get();
 | 
				
			||||||
 | 
					            if (!config) return;
 | 
				
			||||||
 | 
					            // 配置
 | 
				
			||||||
 | 
					            printDetails.value = config.printDetails;
 | 
				
			||||||
 | 
					            printFolding.value = config.printFolding;
 | 
				
			||||||
 | 
					            autoCheckUpdate.value = config.autoCheckUpdate;
 | 
				
			||||||
 | 
					            // 快捷键
 | 
				
			||||||
 | 
					            const hotkey = config.hotkey;
 | 
				
			||||||
 | 
					            if (!hotkey || hotkey === '') {
 | 
				
			||||||
 | 
					                selectKey.value = '';
 | 
				
			||||||
 | 
					                customKey.value = '';
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // 预设快捷键
 | 
				
			||||||
 | 
					            for (let i = 0, l = presets.value.length; i < l; i++) {
 | 
				
			||||||
 | 
					                if (presets.value[i].key === hotkey) {
 | 
				
			||||||
 | 
					                    selectKey.value = hotkey;
 | 
				
			||||||
 | 
					                    customKey.value = '';
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // 自定义快捷键
 | 
				
			||||||
 | 
					            selectKey.value = 'custom';
 | 
				
			||||||
 | 
					            customKey.value = hotkey;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 保存配置
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        function setConfig() {
 | 
				
			||||||
 | 
					            const config = {
 | 
				
			||||||
 | 
					                hotkey: null,
 | 
				
			||||||
 | 
					                printDetails: printDetails.value,
 | 
				
			||||||
 | 
					                printFolding: printFolding.value,
 | 
				
			||||||
 | 
					                autoCheckUpdate: autoCheckUpdate.value,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            if (selectKey.value === 'custom') {
 | 
				
			||||||
 | 
					                // 自定义输入是否有效
 | 
				
			||||||
 | 
					                if (customKey.value === '') {
 | 
				
			||||||
 | 
					                    EditorRendererKit.print('warn', t('custom-key-error'));
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // 不可以使用双引号(避免 json 值中出现双引号而解析错误,导致插件加载失败)
 | 
				
			||||||
 | 
					                if (customKey.value.includes('"')) {
 | 
				
			||||||
 | 
					                    customKey.value = customKey.value.replace(/\"/g, '');
 | 
				
			||||||
 | 
					                    EditorRendererKit.print('warn', t('quote-error'));
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                config.hotkey = customKey.value;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                config.hotkey = selectKey.value;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // 保存到本地
 | 
				
			||||||
 | 
					            ConfigManager.set(config);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 应用按钮点击回调
 | 
				
			||||||
 | 
					         * @param {*} event 
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        function onApplyBtnClick(event) {
 | 
				
			||||||
 | 
					            // 保存配置
 | 
				
			||||||
 | 
					            setConfig();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 翻译
 | 
				
			||||||
 | 
					         * @param {string} key 
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        function t(key) {
 | 
				
			||||||
 | 
					            return I18n.get(LANG, key);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 生命周期:挂载后
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        onMounted(() => {
 | 
				
			||||||
 | 
					            // 获取配置
 | 
				
			||||||
 | 
					            getConfig();
 | 
				
			||||||
 | 
					            // 覆盖 a 标签点击回调(使用默认浏览器打开网页)
 | 
				
			||||||
 | 
					            const links = document.querySelectorAll('a[href]');
 | 
				
			||||||
 | 
					            links.forEach((link) => {
 | 
				
			||||||
 | 
					                link.addEventListener('click', (event) => {
 | 
				
			||||||
 | 
					                    event.preventDefault();
 | 
				
			||||||
 | 
					                    const url = link.getAttribute('href');
 | 
				
			||||||
 | 
					                    shell.openExternal(url);
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            // (主进程)检查更新
 | 
				
			||||||
 | 
					            RendererEvent.send('check-update', false);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 生命周期:卸载前
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        onBeforeUnmount(() => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            presets,
 | 
				
			||||||
 | 
					            selectKey,
 | 
				
			||||||
 | 
					            customKey,
 | 
				
			||||||
 | 
					            printDetails,
 | 
				
			||||||
 | 
					            printFolding,
 | 
				
			||||||
 | 
					            autoCheckUpdate,
 | 
				
			||||||
 | 
					            repositoryUrl,
 | 
				
			||||||
 | 
					            packageName,
 | 
				
			||||||
 | 
					            onApplyBtnClick,
 | 
				
			||||||
 | 
					            t,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 创建实例
 | 
				
			||||||
 | 
					const app = createApp(App);
 | 
				
			||||||
 | 
					// 挂载
 | 
				
			||||||
 | 
					app.mount('#app');
 | 
				
			||||||
		Reference in New Issue
	
	Block a user