代码拉取完成,页面将自动刷新
同步操作将从 陈皮皮/Cocos 扩展 - Quick Finder 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
const { BrowserWindow, ipcMain } = require('electron');
const Path = require('path');
const ConfigManager = require('./config-manager');
const FileUtil = require('./utils/file-utils');
/** 包名 */
const PACKAGE_NAME = 'ccc-quick-finder';
/**
* i18n
* @param {string} key
* @returns {string}
*/
const translate = (key) => Editor.T(`${PACKAGE_NAME}.${key}`);
/** 扩展名 */
const EXTENSION_NAME = translate('name');
module.exports = {
/**
* 搜索栏实例
* @type {BrowserWindow}
*/
searchBar: null,
/**
* 缓存
* @type {{ name: string, path: string, extname: string }[]}
*/
cache: null,
/**
* 扩展消息
* @type {{ [key: string]: Function }}
*/
messages: {
/**
* 打开搜索面板
*/
'open-search-panel'() {
this.openSearchBar();
},
/**
* 打开设置面板
*/
'open-setting-panel'() {
Editor.Panel.open(`${PACKAGE_NAME}.setting`);
},
/**
* 读取配置
* @param {any} event
*/
'read-config'(event) {
const config = ConfigManager.read();
event.reply(null, config);
},
/**
* 保存配置
* @param {any} event
* @param {any} config
*/
'save-config'(event, config) {
ConfigManager.save(config);
event.reply(null, true);
},
},
/**
* 生命周期:加载
*/
load() {
// 监听事件
ipcMain.on(`${PACKAGE_NAME}:get-lang`, this.onGetLangEvent.bind(this));
ipcMain.on(`${PACKAGE_NAME}:match-keyword`, this.onMatchKeywordEvent.bind(this));
ipcMain.on(`${PACKAGE_NAME}:open`, this.onOpenEvent.bind(this));
ipcMain.on(`${PACKAGE_NAME}:focus`, this.onFocusEvent.bind(this));
},
/**
* 生命周期:卸载
*/
unload() {
// 取消事件监听
ipcMain.removeAllListeners(`${PACKAGE_NAME}:get-lang`);
ipcMain.removeAllListeners(`${PACKAGE_NAME}:match-keyword`);
ipcMain.removeAllListeners(`${PACKAGE_NAME}:open`);
ipcMain.removeAllListeners(`${PACKAGE_NAME}:focus`);
},
/**
* (渲染进程)获取语言事件回调
* @param {*} event
*/
onGetLangEvent(event) {
const lang = Editor.lang;
event.reply(`${PACKAGE_NAME}:get-lang-reply`, lang);
},
/**
* (渲染进程)关键词匹配事件回调
* @param {*} event
* @param {string} keyword
*/
onMatchKeywordEvent(event, keyword) {
// 匹配结果
const results = this.getMatchFiles(keyword);
// 返回结果给渲染进程
event.reply(`${PACKAGE_NAME}:match-keyword-reply`, results);
},
/**
* (渲染进程)打开文件事件回调
* @param {*} event
* @param {string} path 路径
*/
onOpenEvent(event, path) {
this.openFile(path);
},
/**
* (渲染进程)聚焦文件事件回调
* @param {*} event
* @param {string} path 路径
*/
onFocusEvent(event, path) {
// 在资源管理器中显示并选中文件
const uuid = Editor.assetdb.fspathToUuid(path);
this.showFileInAssets(uuid);
},
/**
* 打开搜索栏
*/
openSearchBar() {
// 已打开则关闭
if (this.searchBar) {
this.closeSearchBar();
return;
}
// 创建窗口
const winSize = [500, 600],
winPos = this.getPosition(winSize),
win = this.searchBar = new BrowserWindow({
width: winSize[0],
height: winSize[1],
x: winPos[0],
y: winPos[1],
frame: false,
resizable: false,
skipTaskbar: true,
alwaysOnTop: true,
transparent: true,
opacity: 0.95,
backgroundColor: '#00000000',
hasShadow: false,
show: false,
webPreferences: {
nodeIntegration: true
},
});
// 加载页面
win.loadURL(`file://${__dirname}/panels/search/index.html`);
// 调试用的 devtools(detach 模式需要取消失焦自动关闭)
// win.webContents.openDevTools({ mode: 'detach' });
// 监听按键(ESC 关闭)
win.webContents.on('before-input-event', (event, input) => {
if (input.key === 'Escape') {
this.closeSearchBar();
}
});
// 就绪后展示(避免闪烁)
win.on('ready-to-show', () => win.show());
// 展示后(缓存数据)
win.on('show', () => (this.cache = this.getAllFiles()));
// 失焦后(自动关闭)
win.on('blur', () => this.closeSearchBar());
// 关闭后(移除引用)
win.on('closed', () => (this.searchBar = null));
},
/**
* 关闭搜索栏
*/
closeSearchBar() {
if (!this.searchBar) {
return;
}
// 先隐藏
// 在 2.4.5 版本中,扩展如果安装在局部,关闭搜索栏会引发编辑器闪退
// 原因未知,修改为先隐藏再关闭就没问题了(离谱)
this.searchBar.hide();
// 关闭
this.searchBar.close();
// 移除缓存
this.cache = null;
},
/**
* 获取窗口位置
* @param {[number, number]} size 窗口尺寸
* @returns {[number, number]}
*/
getPosition(size) {
// 根据编辑器窗口的位置和尺寸来计算
const editorWin = BrowserWindow.getFocusedWindow(),
editorSize = editorWin.getSize(),
editorPos = editorWin.getPosition(),
// 需要注意一个问题:窗口的位置值必须是整数,否则修改不会生效
// 毕竟像素应该是显示器上的最低单位了,合理
x = Math.floor(editorPos[0] + (editorSize[0] / 2) - (size[0] / 2)),
y = Math.floor(editorPos[1] + 200);
return [x, y];
},
/**
* 获取项目中所有文件
* @returns {{ name: string, path: string, extname: string }[]}
*/
getAllFiles() {
const assetsPath = Editor.url('db://assets/'),
results = [];
const handler = (path, stat) => {
// 过滤
if (this.filter(path)) {
const name = Path.basename(path),
extname = Path.extname(path);
results.push({ name, path, extname });
}
}
// 遍历项目文件
FileUtil.map(assetsPath, handler);
// Done
return results;
},
/**
* 过滤文件
* @param {string} path 路径
* @returns {boolean}
*/
filter(path) {
// 扩展名
const extname = Path.extname(path);
// 排除 meta 文件和没有扩展名的文件
if (extname === '.meta' || extname === '') {
return false;
}
// 只要场景和预制体
// if (extname !== '.fire' && extname !== '.prefab') {
// return false;
// }
// 可用
return true;
},
/**
* 获取项目中匹配关键词的文件
* @param {string} keyword 关键词
* @returns {{ name: string, path: string, extname: string, similarity: number }[]}
*/
getMatchFiles(keyword) {
const results = [],
cache = this.cache;
// 正则(每个关键字之间可以有任意个字符(.*);不区分大小写(i);懒惰模式(?),匹配尽肯少的字符)
const pattern = keyword.split('').join('.*?'),
regExp = new RegExp(pattern, 'i');
// 下面这行正则插入很炫酷,但是性能不好,耗时接近 split + join 的 10 倍
// const pattern = keyword.replace(/(?<=.)(.)/g, '.*$1');
// 查找并匹配
if (cache && cache.length > 0) {
// 从缓存中查找
for (let i = 0, l = cache.length; i < l; i++) {
const { name, path, extname } = cache[i];
// 匹配
if (regExp.test(name)) {
const similarity = name.match(regExp)[0].length;
results.push({ name, path, extname, similarity });
}
}
// 排序(similarity 越小,匹配的长度越短,匹配度越高)
results.sort((a, b) => a.similarity - b.similarity);
} else {
Editor.warn(`[${EXTENSION_NAME}]`, translate('dataError'));
}
// Done
return results;
},
/**
* 打开文件
* @param {string} path 路径
*/
openFile(path) {
const extname = Path.extname(path),
uuid = Editor.assetdb.fspathToUuid(path);
// 文件格式
switch (extname) {
case '.fire':
// 打开场景
this.openScene(uuid);
break;
case '.prefab':
// 打开预制体
this.openPrefab(uuid);
break;
default:
// 在资源管理器中显示并选中文件
this.showFileInAssets(uuid);
break;
}
// 隐藏搜索栏
this.closeSearchBar();
},
/**
* 打开场景
* @param {string} uuid uuid
*/
openScene(uuid) {
Editor.Panel.open('scene', { uuid });
},
/**
* 打开预制体
* @param {string} uuid uuid
*/
openPrefab(uuid) {
Editor.Ipc.sendToAll('scene:enter-prefab-edit-mode', uuid);
},
/**
* 在资源管理器中显示并选中文件
* @param {string} uuid uuid
*/
showFileInAssets(uuid) {
Editor.Ipc.sendToAll('assets:hint', uuid);
Editor.Selection.select('asset', uuid);
},
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。