diff --git a/%APPDATA%/Adobe/CEP/extensions/AdminPanel/CSXS/manifest.xml b/%APPDATA%/Adobe/CEP/extensions/AdminPanel/CSXS/manifest.xml new file mode 100644 index 0000000..3554578 --- /dev/null +++ b/%APPDATA%/Adobe/CEP/extensions/AdminPanel/CSXS/manifest.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + ./index.html + + --enable-nodejs + --mixed-context + + + + + true + + + + Panel + Designer Admin Panel + + + 800 + 1200 + + + 400 + 600 + + + + + + + + diff --git a/%APPDATA%/Adobe/CEP/extensions/AdminPanel/index.html b/%APPDATA%/Adobe/CEP/extensions/AdminPanel/index.html new file mode 100644 index 0000000..aa65222 --- /dev/null +++ b/%APPDATA%/Adobe/CEP/extensions/AdminPanel/index.html @@ -0,0 +1,146 @@ + + + + + Designer Admin Panel + + + + +
+
+

加载中...

+
+ + + + + + + + diff --git a/%APPDATA%/Adobe/CEP/extensions/AdminPanel/检查并启用CEP.bat b/%APPDATA%/Adobe/CEP/extensions/AdminPanel/检查并启用CEP.bat new file mode 100644 index 0000000..75f09e0 --- /dev/null +++ b/%APPDATA%/Adobe/CEP/extensions/AdminPanel/检查并启用CEP.bat @@ -0,0 +1,41 @@ +@echo off +chcp 65001 >nul +echo ======================================== +echo CEP 扩展调试模式检查工具 +echo ======================================== +echo. + +echo [1] 检查当前 CEP 调试模式状态... +reg query "HKEY_CURRENT_USER\Software\Adobe\CSXS.8" /v PlayerDebugMode 2>nul +if %errorlevel% neq 0 ( + echo ❌ 未找到 CSXS.8 调试模式配置 +) else ( + echo ✅ CSXS.8 配置已存在 +) +echo. + +echo [2] 启用 CEP 调试模式... +reg add "HKEY_CURRENT_USER\Software\Adobe\CSXS.8" /v PlayerDebugMode /t REG_SZ /d 1 /f >nul +reg add "HKEY_CURRENT_USER\Software\Adobe\CSXS.9" /v PlayerDebugMode /t REG_SZ /d 1 /f >nul +reg add "HKEY_CURRENT_USER\Software\Adobe\CSXS.10" /v PlayerDebugMode /t REG_SZ /d 1 /f >nul +reg add "HKEY_CURRENT_USER\Software\Adobe\CSXS.11" /v PlayerDebugMode /t REG_SZ /d 1 /f >nul + +echo ✅ CEP 调试模式已启用(CSXS 8/9/10/11) +echo. + +echo [3] 检查插件安装位置... +set "EXT_DIR=%APPDATA%\Adobe\CEP\extensions\AdminPanel" +if exist "%EXT_DIR%\" ( + echo ✅ 插件已安装到: %EXT_DIR% + dir "%EXT_DIR%" /B +) else ( + echo ❌ 插件未安装,请运行安装命令 +) +echo. + +echo ======================================== +echo 操作完成! +echo 请 [完全关闭 Photoshop] 后重新打开 +echo ======================================== +pause + diff --git a/AdminPanel/cep.config.ts b/AdminPanel/cep.config.ts new file mode 100644 index 0000000..67eb0b9 --- /dev/null +++ b/AdminPanel/cep.config.ts @@ -0,0 +1,50 @@ +import { ICepConfig } from "./plugins"; + +const config: ICepConfig = { + "name": "AdminPanel", + "id": "com.designer.adminpanel", + "version": "1.0.0", + "extensionVersion": "6.1.0", + "requiredRuntimeVersion": "8.0", + "type": "Panel", + "parameters": [ + "--enable-nodejs" + ], + "panels": [ + { + "name": "AdminPanel", + "displayName": "ps套版", + "main": "./index.html", + "width": 280, + "height": 600, + "minWidth": 280, + "minHeight": 600, + "maxWidth": 600, + "maxHeight": 4080 + } + ], + "hosts": [ + { + "name": "PHSP", + "version": "[18.0,99.9]" + }, + { + "name": "PHXS", + "version": "[18.0,99.9]" + } + ], + "build": { + "jsxBin": false, + "country": "CN", + "province": "GD", + "org": "Designer", + "password": "", + "tsa": "" + }, + "zxp": { + "jsxBin": false + } +} + +export default config; + diff --git a/AdminPanel/dev.cep.config.ts b/AdminPanel/dev.cep.config.ts new file mode 100644 index 0000000..31f7831 --- /dev/null +++ b/AdminPanel/dev.cep.config.ts @@ -0,0 +1,49 @@ +import { ICepConfig } from "./plugins"; + +const config: ICepConfig = { + "name": "AdminPanel-dev", + "id": "com.designer.adminpanel.dev", + "version": "1.0.0", + "extensionVersion": "6.1.0", + "requiredRuntimeVersion": "8.0", + "type": "Panel", + "parameters": [ + "--enable-nodejs" + ], + "panels": [ + { + "name": "AdminPanel-dev", + "displayName": "管理面板", + "main": "./index.html", + "width": 280, + "height": 600, + "minWidth": 280, + "minHeight": 600, + "maxWidth": 600, + "maxHeight": 4080 + } + ], + "hosts": [ + { + "name": "PHSP", + "version": "[18.0,99.9]" + }, + { + "name": "PHXS", + "version": "[18.0,99.9]" + } + ], + "build": { + "jsxBin": false, + "country": "CN", + "province": "GD", + "org": "Designer", + "password": "", + "tsa": "" + }, + "zxp": { + "jsxBin": false + } +} + +export default config; diff --git a/AdminPanel/index.html b/AdminPanel/index.html new file mode 100644 index 0000000..512fe1a --- /dev/null +++ b/AdminPanel/index.html @@ -0,0 +1,13 @@ + + + + + + Designer Admin Panel + + +
+ + + + diff --git a/AdminPanel/package.json b/AdminPanel/package.json new file mode 100644 index 0000000..4387863 --- /dev/null +++ b/AdminPanel/package.json @@ -0,0 +1,34 @@ +{ + "name": "AdminPanel", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@vueuse/core": "^10.4.1", + "axios": "^1.6.8", + "types-for-adobe": "^7.0.12", + "vue": "^3.2.47", + "vue-router": "^4.2.4" + }, + "devDependencies": { + "@arco-design/web-vue": "^2.57.0", + "@types/node": "^20.3.2", + "@vitejs/plugin-legacy": "^4.0.5", + "@vitejs/plugin-vue": "^4.1.0", + "adm-zip": "^0.5.10", + "chokidar": "^3.5.3", + "less": "^4.1.3", + "open": "^11.0.0", + "sass": "^1.63.6", + "ts-node": "^10.9.2", + "typescript": "^5.1.5", + "vite": "^4.3.9", + "vite-tsconfig-paths": "^4.3.2", + "vue-tsc": "^1.4.2" + } +} diff --git a/AdminPanel/plugins/README.md b/AdminPanel/plugins/README.md new file mode 100644 index 0000000..e69de29 diff --git a/AdminPanel/plugins/global.d.ts b/AdminPanel/plugins/global.d.ts new file mode 100644 index 0000000..31d82e3 --- /dev/null +++ b/AdminPanel/plugins/global.d.ts @@ -0,0 +1,6 @@ + +declare global { + interface Window { + __adobe_cep__: any; + } +} \ No newline at end of file diff --git a/AdminPanel/plugins/index.ts b/AdminPanel/plugins/index.ts new file mode 100644 index 0000000..3f768d6 --- /dev/null +++ b/AdminPanel/plugins/index.ts @@ -0,0 +1,4 @@ +export type { ICepConfig } from './jsx/types'; +export { initJsx, evalJSX } from './utils/cep'; +export { CEPPath } from './utils/cep/cepPath' +export { CSInterface } from "./utils/cep" \ No newline at end of file diff --git a/AdminPanel/plugins/jsx/cepPlugin.ts b/AdminPanel/plugins/jsx/cepPlugin.ts new file mode 100644 index 0000000..b55f50d --- /dev/null +++ b/AdminPanel/plugins/jsx/cepPlugin.ts @@ -0,0 +1,98 @@ +import { copyCepToDev, copyCepToProd } from "./copyCepToDev" +import { createConfig } from "./createConfig" +// 注意:已移除 buildJsx 依赖,现在使用内联 JSX 方式 +//@ts-ignore +import packageConfig from "../../package.json" +import defaultConfig from '../../cep.config'; +import { ICepConfig } from "./types"; + +let g_config: any = '' +interface CepPluginOptions { + cepConfig?: ICepConfig; + jsxInput?: string; + jsxOutput?: string; + jsxIncludes?: string[]; +} + +export default function cepPlugin(options: CepPluginOptions = {}) { + const config = options.cepConfig || defaultConfig; + return { + name: 'transform-file', + async buildStart(viteConfig: any) { + // 已移除 JSX 构建逻辑,现在使用内联 JSX 方式 + if (process.env.NODE_ENV === 'production') { + console.log('正式环境 - 使用内联 JSX'); + } + }, + transform(src: any, id: any) { + + }, + configResolved(viteConfig: any) { + g_config = viteConfig + if (viteConfig.isProduction) + return console.log('[cepPlugin]打包不处理'); + // 已移除 JSX 监听构建,现在使用内联 JSX 方式 + console.log('[cepPlugin] 使用内联 JSX,无需构建外部文件'); + + const name = `${getProjectName(viteConfig.root)}-dev` + // 使用配置的端口(strictPort: true 确保端口不会变) + const port = viteConfig.server?.port || 5180 + const serverURL = `http://localhost:${port}/` + + try { + const cepConfig = createConfig(viteConfig.root, { + name: name, + id: `com.${name}`, + version: packageConfig.version, + }, "dev") + copyCepToDev({ + serverURL: serverURL, + name: name, + isBuild: false + }, cepConfig) + } catch (error) { + console.log('[CEP] 初始化失败'); + console.log(error); + } + }, + async closeBundle() { + if (!g_config.isProduction) + return console.log('[cepPlugin]开发环境不处理'); + + // await buildJsxByProd() + const name = `${getProjectName(g_config.root)}` + try { + // Use the provided config instead of recreating from package.json if possible, + // but createConfig merges simple props. + // Wait, createConfig uses hardcoded template logic. + // Let's passed detailed config if needed. + // For now, we trust config passed in options. + + // Note: createConfig logic might need review if we want full Custom Config control. + // But typically it uses the 'config' object we imported/selected at top. + + // Actually createConfig generates the manifest content string. + // We should pass our 'config' object to the copy/write logic. + + console.log('[id]:' + config.id); + + copyCepToProd({ + // 方案 B:CEP 插件打开后直接跳转到服务器 Shell 登录页 + serverURL: 'https://aidg168.uk/shell/#/login', + name: name, + isBuild: true, + distDir: g_config.build.outDir + }, config) + } catch (error) { + console.log('[CEP] 初始化失败'); + console.log(error); + } + console.log('[cepPlugins] 编译成功'); + } + } +} + +function getProjectName(root: string) { + if(root.endsWith("src/launcher")) return "Designer"; // Hack for launcher root? No, Vite root usually project root. + return root.split('/').pop() +} \ No newline at end of file diff --git a/AdminPanel/plugins/jsx/copyCepToDev.ts b/AdminPanel/plugins/jsx/copyCepToDev.ts new file mode 100644 index 0000000..a696376 --- /dev/null +++ b/AdminPanel/plugins/jsx/copyCepToDev.ts @@ -0,0 +1,181 @@ +import fs from 'fs' +import path from 'path' +import { ICepConfig, IPanel } from './types'; +import { joinDebug } from './template/debug'; +import { copyFolderSync } from './utils/fs'; +import { getAdobeCepDir } from './utils/cepDir'; +import { joinManifest } from './template/manifest'; +import { joinHtml } from './template/html'; +import open from 'open'; +/** + * 复制插件壳到ps插件目录 + */ +export function copyCepToDev(options: Omit, cepConfig: ICepConfig) { + cepConfig.panels[0].displayName = `[dev]${cepConfig.panels[0].displayName}` + const cep = new CEP(options, cepConfig) + cep.write() + console.log(`[CEP] 插件壳已就绪`); + console.log(`[CEP] PS调试地址: http://localhost:7090`); + open('http://localhost:7090') +} + +export function copyCepToProd(options: Omit, cepConfig: ICepConfig) { + cepConfig.panels[0].displayName = `${cepConfig.panels[0].displayName}` + const cep = new CEP(options, cepConfig) + cep.write() +} + +type IOptions = { + name: string + serverURL: string + outCepPath: string + inputCepTemp: string + isBuild: boolean + distDir?: string // Added dynamic dist path +} + +export class CEP { + constructor(private readonly options: Omit, private readonly cepConfig: ICepConfig) { + this.createDist() + } + + private get cepInput() { + return path.join(__dirname, "./template/cep") + } + + private get dist() { + if (this.options.distDir) { + if (path.isAbsolute(this.options.distDir)) return this.options.distDir; + return path.resolve(process.cwd(), this.options.distDir); + } + return path.join(__dirname, '../../dist') + } + + private get cepOutput() { + return path.join(this.dist, this.options.name) + } + + private get cepLink() { + return path.join(getAdobeCepDir(), this.options.name) + } + + private get debug() { + return path.join(this.cepOutput, '.debug') + } + + private createDist() { + if (!fs.existsSync(this.dist)) { + fs.mkdirSync(this.dist) + } + } + + public write() { + this.copyFolder() + if (!this.options.isBuild) + this.writeHtml() + this.writeCSXS() + if (!this.options.isBuild) + this.writeDebug() + this.copyJson2() + + // 创建符号链接或直接复制 + if (!fs.existsSync(this.cepLink)) { + try { + fs.symlinkSync(this.cepOutput, this.cepLink, 'dir') + console.log('[CEP] 符号链接已创建') + } catch (error: any) { + // 权限不足时,改用复制 + if (error.code === 'EPERM') { + console.warn('[CEP] 符号链接权限不足,改用复制方式') + this.copyToCepDir() + } else { + throw error + } + } + } else { + // 目录已存在,需要更新文件 + this.copyToCepDir() + } + + if (this.options.isBuild) { + this.copyBuildFiles() + } + + console.log('[cepPlugin] 安装目录:', getAdobeCepDir()); + + } + + private copyToCepDir() { + // 删除旧目录 + if (fs.existsSync(this.cepLink)) { + fs.rmSync(this.cepLink, { recursive: true, force: true }) + } + // 复制目录 + copyFolderSync(this.cepOutput, this.cepLink) + console.log('[CEP] 已复制到 CEP 目录') + } + + private copyFolder() { + copyFolderSync(this.cepInput, this.cepOutput) + } + + private writeHtml() { + const outhtml = path.join(this.cepOutput, 'index.html') + let content = joinHtml(this.cepConfig.name, this.options.serverURL || 'http://localhost:5173/') + fs.writeFileSync(outhtml, content) + } + + private writeCSXS() { + const info = joinManifest(this.cepConfig) + const output = path.join(this.cepOutput, 'CSXS/manifest.xml') + fs.writeFileSync(output, info) + } + + private writeDebug() { + const info = joinDebug(this.cepConfig.id, this.cepConfig.hosts) + fs.writeFileSync(this.debug, info) + } + + private copyJson2() { + const input = path.join(__dirname, '../utils/json') + const out = path.join(this.cepOutput, 'js') + copyFolderSync(input, out) + } + + private copyBuildFiles() { + // 1. 复制 assets 目录 + const assetsInput = path.join(this.dist, 'assets') + const assetsOut = path.join(this.cepOutput, 'assets') + if (fs.existsSync(assetsInput)) { + copyFolderSync(assetsInput, assetsOut) + console.log('[CEP] ✓ 已复制 assets 目录') + } + + // 2. 复制 CSInterface.js + const csInterfaceSrc = path.join(this.dist, 'CSInterface.js') + const csInterfaceDst = path.join(this.cepOutput, 'CSInterface.js') + if (fs.existsSync(csInterfaceSrc)) { + fs.copyFileSync(csInterfaceSrc, csInterfaceDst) + console.log('[CEP] ✓ 已复制 CSInterface.js') + } + + // 3. 复制并修正 HTML 路径 + const builtHtmlPath = path.join(this.dist, 'src/launcher/index.html') + const targetHtmlPath = path.join(this.cepOutput, 'index.html') + + if (fs.existsSync(builtHtmlPath)) { + // 读取 HTML 内容并修正路径 + let htmlContent = fs.readFileSync(builtHtmlPath, 'utf-8') + + // 修正路径:把 ../../ 替换成 ./ + htmlContent = htmlContent.replace(/\.\.\/\.\.\//g, './') + // 确保 CSInterface.js 路径正确 + htmlContent = htmlContent.replace(/src="\.\/CSInterface\.js"/g, 'src="CSInterface.js"') + + fs.writeFileSync(targetHtmlPath, htmlContent) + console.log('[CEP] ✓ 已复制并修正 HTML 路径') + } else { + console.warn('[CEP] ✗ 未找到构建的 HTML:', builtHtmlPath) + } + } +} diff --git a/AdminPanel/plugins/jsx/createConfig.ts b/AdminPanel/plugins/jsx/createConfig.ts new file mode 100644 index 0000000..e2e2264 --- /dev/null +++ b/AdminPanel/plugins/jsx/createConfig.ts @@ -0,0 +1,40 @@ + +import fs from 'fs'; +import path from 'path'; +import defConfig from './template/cep.config'; +import { ICepConfig } from './types'; +const fileName = 'cep.config.ts'; + +/** + * + * @param root 创建cep.config.ts + */ +export function createConfig(root: string, config: Partial, env: 'dev' | 'prod') { + // 指定要检查的文件路径 + const filePath = path.resolve(root, env + "." + fileName); + + const temp: ICepConfig = Object.assign({}, defConfig, { + name: config.name, + id: config.id, + version: config.version, + }); + + // 判断文件是否存在 + if (!fs.existsSync(filePath)) { + // 如果文件不存在,则创建文件 + fs.writeFileSync(filePath, `import { ICepConfig } from "@/plugins";\n\nconst config: ICepConfig = ${JSON.stringify(temp, null, 4)}\n\nexport default config; `); + console.log(`[CEP] 添加配置文件 ${fileName} 成功!`); + } else { + console.log(`[CEP] 已有配置`); + return getFileConfig(filePath); + } + return temp; +} + +function getFileConfig(configPath: string) { + let temp = fs.readFileSync(configPath, 'utf-8').split('ICepConfig = ')[1]; + const temp2 = temp.split('}') + temp2.pop() + const str = temp2.join('}') + '}'; + return JSON.parse(str); +} \ No newline at end of file diff --git a/AdminPanel/plugins/jsx/template/README.md b/AdminPanel/plugins/jsx/template/README.md new file mode 100644 index 0000000..eb367e9 --- /dev/null +++ b/AdminPanel/plugins/jsx/template/README.md @@ -0,0 +1,3 @@ +## 目录说明 +- cep 插件壳模板文件 +- cep.config.json 配置文件 \ No newline at end of file diff --git a/AdminPanel/plugins/jsx/template/cep.config.ts b/AdminPanel/plugins/jsx/template/cep.config.ts new file mode 100644 index 0000000..44f96bd --- /dev/null +++ b/AdminPanel/plugins/jsx/template/cep.config.ts @@ -0,0 +1,65 @@ +import { ICepConfig } from "@plugins"; + +const config: ICepConfig = { + name: "cepName", + id: "com.cepName", + version: "1.0.0", + extensionVersion: "6.1.0", + requiredRuntimeVersion: "9.0", + type: "Panel", + parameters: [ + "--enable-nodejs", + ], + panels: [ + { + name: "cepName", + displayName: "panelName", + main: "./index.html", + width: 400, + height: 300, + minWidth: 400, + minHeight: 300, + maxWidth: 4000, + maxHeight: 3000, + } + ], + hosts:[ + { + name: "AEFT", + version: "[0.0,99.9]", + }, + { + name: "PPRO", + version: "[0.0,99.9]", + }, + { + name: "ILST", + version: "[0.0,99.9]", + }, + { + name: "PHXS", + version: "[0.0,99.9]", + }, + { + name: "FLPR", + version: "[0.0,99.9]", + }, + ], + build: { + jsxBin: false, + /**国家 */ + country: "CN", + /**省份 */ + province: "GD", + /**公司名称 */ + org: "你的公司名称", + /**签名密码 */ + password: "", + tsa: "", + }, + zxp: { + jsxBin: false + } +} + +export default config; \ No newline at end of file diff --git a/AdminPanel/plugins/jsx/template/cep/CSXS/manifest.xml b/AdminPanel/plugins/jsx/template/cep/CSXS/manifest.xml new file mode 100644 index 0000000..82d81dd --- /dev/null +++ b/AdminPanel/plugins/jsx/template/cep/CSXS/manifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Server/Designer/img/dark.png b/AdminPanel/plugins/jsx/template/cep/img/dark.png similarity index 100% rename from Server/Designer/img/dark.png rename to AdminPanel/plugins/jsx/template/cep/img/dark.png diff --git a/Server/Designer/img/dark@2x.png b/AdminPanel/plugins/jsx/template/cep/img/dark@2x.png similarity index 100% rename from Server/Designer/img/dark@2x.png rename to AdminPanel/plugins/jsx/template/cep/img/dark@2x.png diff --git a/Server/Designer/img/dark@3x.png b/AdminPanel/plugins/jsx/template/cep/img/dark@3x.png similarity index 100% rename from Server/Designer/img/dark@3x.png rename to AdminPanel/plugins/jsx/template/cep/img/dark@3x.png diff --git a/Server/Designer/img/dark@4x.png b/AdminPanel/plugins/jsx/template/cep/img/dark@4x.png similarity index 100% rename from Server/Designer/img/dark@4x.png rename to AdminPanel/plugins/jsx/template/cep/img/dark@4x.png diff --git a/Server/Designer/img/highlight.png b/AdminPanel/plugins/jsx/template/cep/img/highlight.png similarity index 100% rename from Server/Designer/img/highlight.png rename to AdminPanel/plugins/jsx/template/cep/img/highlight.png diff --git a/Server/Designer/img/highlight@2x.png b/AdminPanel/plugins/jsx/template/cep/img/highlight@2x.png similarity index 100% rename from Server/Designer/img/highlight@2x.png rename to AdminPanel/plugins/jsx/template/cep/img/highlight@2x.png diff --git a/Server/Designer/img/highlight@3x.png b/AdminPanel/plugins/jsx/template/cep/img/highlight@3x.png similarity index 100% rename from Server/Designer/img/highlight@3x.png rename to AdminPanel/plugins/jsx/template/cep/img/highlight@3x.png diff --git a/Server/Designer/img/highlight@4x.png b/AdminPanel/plugins/jsx/template/cep/img/highlight@4x.png similarity index 100% rename from Server/Designer/img/highlight@4x.png rename to AdminPanel/plugins/jsx/template/cep/img/highlight@4x.png diff --git a/AdminPanel/plugins/jsx/template/cep/index.html b/AdminPanel/plugins/jsx/template/cep/index.html new file mode 100644 index 0000000..0d86587 --- /dev/null +++ b/AdminPanel/plugins/jsx/template/cep/index.html @@ -0,0 +1,16 @@ + + + + + + + + {{name}} + + + + + + \ No newline at end of file diff --git a/AdminPanel/plugins/jsx/template/debug.ts b/AdminPanel/plugins/jsx/template/debug.ts new file mode 100644 index 0000000..c4fa696 --- /dev/null +++ b/AdminPanel/plugins/jsx/template/debug.ts @@ -0,0 +1,15 @@ +export function joinDebug(id: string, hosts: { name: string }[]) { + let port = 7090 + return ` + + + + + ${hosts + .map((host) => ``) + .join("\n")} + + + + ` +} \ No newline at end of file diff --git a/AdminPanel/plugins/jsx/template/html.ts b/AdminPanel/plugins/jsx/template/html.ts new file mode 100644 index 0000000..4b89b4c --- /dev/null +++ b/AdminPanel/plugins/jsx/template/html.ts @@ -0,0 +1,15 @@ +export function joinHtml(name:string,server:string){ + return ` + + + + ${name} + + + + +` +} \ No newline at end of file diff --git a/Server/Designer/CSXS/manifest.xml b/AdminPanel/plugins/jsx/template/manifest.ts similarity index 53% rename from Server/Designer/CSXS/manifest.xml rename to AdminPanel/plugins/jsx/template/manifest.ts index dfa6ffb..5c53033 100644 --- a/Server/Designer/CSXS/manifest.xml +++ b/AdminPanel/plugins/jsx/template/manifest.ts @@ -1,31 +1,33 @@ - - +import { ICepConfig } from "../types"; + +export function joinManifest(config: ICepConfig) { + const { id, version, extensionVersion, requiredRuntimeVersion, hosts, parameters, panels } = config + const mainId=`${id}` + const panel = panels[0] + return ` + - + - - - - - + ${hosts.map(item => ``).join("\n")} - + - + ./index.html - --enable-nodejs + ${parameters.map(item => `${item}`).join("\n")} @@ -33,19 +35,19 @@ Panel - 超级套版 + ${panel.displayName} - 600 - 250 + ${panel.height} + ${panel.width} - 3000 - 4000 + ${panel.maxHeight||panel.height} + ${panel.maxWidth||panel.width} - 600 - 250 + ${panel.minHeight||panel.height} + ${panel.minWidth||panel.width} @@ -60,4 +62,5 @@ - \ No newline at end of file + ` +} \ No newline at end of file diff --git a/AdminPanel/plugins/jsx/types.ts b/AdminPanel/plugins/jsx/types.ts new file mode 100644 index 0000000..ac26755 --- /dev/null +++ b/AdminPanel/plugins/jsx/types.ts @@ -0,0 +1,42 @@ +export type ICepConfig = { + name: string + id: string + version: string + extensionVersion: string + requiredRuntimeVersion: string + type: "Panel" + parameters: IParameter[] + panels: IPanel[], + hosts?: {name:string,version:string}[] + build: { + jsxBin: boolean + /**国家 */ + country: string, + /**省份 */ + province: string, + /**公司名称 */ + org: string + /**签名密码 */ + password: string, + tsa: string, + }, + zxp: { + jsxBin: boolean + } +} + +type IParameter = "--enable-nodejs" | "--enable-media-stream" | "--enable-speech-input" + +export type IPanel = { + /**入口index.html */ + main:string + name: string + /**插件名称 */ + displayName:string + width: number + height: number + minWidth?: number + minHeight?: number + maxWidth?: number + maxHeight?: number +} \ No newline at end of file diff --git a/AdminPanel/plugins/jsx/utils/cepDir.ts b/AdminPanel/plugins/jsx/utils/cepDir.ts new file mode 100644 index 0000000..90f0eae --- /dev/null +++ b/AdminPanel/plugins/jsx/utils/cepDir.ts @@ -0,0 +1,18 @@ +import { isMac } from "./fs" +import os from 'os' +import path from 'path' + +function getUserDataPath() { + if (process.platform === 'darwin') { + return path.join(os.homedir(), 'Library', 'Application Support'); + } else if (process.platform === 'win32') { + return path.join(process.env.APPDATA); + } else { + return path.join(os.homedir()); + } +} +export function getAdobeCepDir() { + const mac = path.join(getUserDataPath(), 'Adobe/CEP/extensions') + const win = path.join(getUserDataPath(), 'Adobe/CEP/extensions') + return isMac() ? mac : win +} diff --git a/AdminPanel/plugins/jsx/utils/fs.ts b/AdminPanel/plugins/jsx/utils/fs.ts new file mode 100644 index 0000000..a602e9a --- /dev/null +++ b/AdminPanel/plugins/jsx/utils/fs.ts @@ -0,0 +1,25 @@ +import fs from 'fs' +import path from 'path' +import os from 'os' + +export const copyFolderSync = (from, to) => { + if (!fs.existsSync(to)) { + fs.mkdirSync(to); + } + + fs.readdirSync(from).forEach((element) => { + const srcPath = path.join(from, element); + const destPath = path.join(to, element); + + if (fs.lstatSync(srcPath).isFile()) { + fs.copyFileSync(srcPath, destPath); + } else { + copyFolderSync(srcPath, destPath); + } + }); +}; + + +export function isMac() { + return os.platform() === 'darwin' +} diff --git a/AdminPanel/plugins/utils/README.md b/AdminPanel/plugins/utils/README.md new file mode 100644 index 0000000..0558066 --- /dev/null +++ b/AdminPanel/plugins/utils/README.md @@ -0,0 +1 @@ +## 提供工具 \ No newline at end of file diff --git a/Server/Designer/js/.gitattributes b/AdminPanel/plugins/utils/cep/.gitattributes similarity index 100% rename from Server/Designer/js/.gitattributes rename to AdminPanel/plugins/utils/cep/.gitattributes diff --git a/AdminPanel/plugins/utils/cep/cep-types.d.ts b/AdminPanel/plugins/utils/cep/cep-types.d.ts new file mode 100644 index 0000000..a3d6c37 --- /dev/null +++ b/AdminPanel/plugins/utils/cep/cep-types.d.ts @@ -0,0 +1,99 @@ +export declare interface cep_node { + global: any; + process: any; + buffer: any; + require: any; +} +export declare interface cep { + encoding: { + Base64: "Base64" | string; + UTF8: "UTF-8" | string; + convertion: { + utf8_to_b64: (...params: any) => {}; + b64_to_utf8: (...params: any) => {}; + binary_to_b64: (...params: any) => {}; + b64_to_binary: (...params: any) => {}; + ascii_to_b64: (...params: any) => {}; + }; + }; + fs: { + ERR_CANT_READ: number; + ERR_CANT_WRITE: number; + ERR_FILE_EXISTS: number; + ERR_INVALID_PARAMS: number; + ERR_NOT_DIRECTORY: number; + ERR_NOT_FILE: number; + ERR_NOT_FOUND: number; + ERR_OUT_OF_SPACE: number; + ERR_UNKNOWN: number; + ERR_UNSUPPORTED_ENCODING: number; + NO_ERROR: number; + chmod: (...params: any) => {}; + deleteFile: (...params: any) => {}; + makedir: (...params: any) => {}; + readFile: (...params: any) => {}; + readdir: (...params: any) => {}; + rename: (...params: any) => {}; + showOpenDialog: (...params: any) => {}; + showOpenDialogEx: (...params: any) => {}; + showSaveDialogEx: (...params: any) => {}; + stat: (...params: any) => {}; + writeFile: (...params: any) => {}; + }; + process: { + ERR_EXCEED_MAX_NUM_PROCESS: number; + createProcess: (...params: any) => {}; + getWorkingDirectory: (...params: any) => {}; + isRunning: (...params: any) => {}; + onquit: (...params: any) => {}; + stderr: (...params: any) => {}; + stdin: (...params: any) => {}; + stdout: (...params: any) => {}; + terminate: (...params: any) => {}; + waitfor: (...params: any) => {}; + }; + util: { + DEPRECATED_API: number; + ERR_INVALID_URL: number; + openURLInDefaultBrowser: (...params: any) => {}; + registerExtensionUnloadCallback: (...params: any) => {}; + storeProxyCredentials: (...params: any) => {}; + }; +} + +export interface __adobe_cep__ { + addEventListener: (...params: any) => {}; + analyticsLogging: (...params: any) => {}; + autoThemeColorChange: (...params: any) => {}; + closeExtension: (...params: any) => {}; + dispatchEvent: (...params: any) => {}; + dumpInstallationInfo: (...params: any) => {}; + evalScript: (...params: any) => {}; + getCurrentApiVersion: (...params: any) => {}; + getCurrentImsUserId: (...params: any) => {}; + getExtensionId: (...params: any) => {}; + getExtensions: (...params: any) => {}; + getHostCapabilities: (...params: any) => {}; + getHostEnvironment: (...params: any) => {}; + getMonitorScaleFactor: (...params: any) => {}; + getNetworkPreferences: (...params: any) => {}; + getScaleFactor: (...params: any) => {}; + getSystemPath: (...params: any) => {}; + imsConnect: (...params: any) => {}; + imsDisconnect: (...params: any) => {}; + imsFetchAccessToken: (...params: any) => {}; + imsFetchAccounts: (...params: any) => {}; + imsSetProxyCredentials: (...params: any) => {}; + initResourceBundle: (...params: any) => {}; + invokeAsync: (...params: any) => {}; + invokeSync: (...params: any) => {}; + nglImsFetchAccessToken: (...params: any) => {}; + nglImsFetchProfile: (...params: any) => {}; + registerInvalidCertificateCallback: (...params: any) => {}; + registerKeyEventsInterest: (...params: any) => {}; + removeEventListener: (...params: any) => {}; + requestOpenExtension: (...params: any) => {}; + resizeContent: (...params: any) => {}; + setScaleFactorChangedHandler: (...params: any) => {}; + showAAM: (...params: any) => {}; +} diff --git a/AdminPanel/plugins/utils/cep/cepPath.ts b/AdminPanel/plugins/utils/cep/cepPath.ts new file mode 100644 index 0000000..2e986e5 --- /dev/null +++ b/AdminPanel/plugins/utils/cep/cepPath.ts @@ -0,0 +1,36 @@ +import CSInterface, { SystemPath } from "./csinterface" + +export class CEPPath { + constructor() { + + } + + static getUserData(): string { + const cs = new CSInterface() + return cs.getSystemPath(SystemPath.USER_DATA) + } + static getCommonFiles() { + const cs = new CSInterface() + return cs.getSystemPath(SystemPath.COMMON_FILES) + } + + static getMyDocuments(): string { + const cs = new CSInterface() + return cs.getSystemPath(SystemPath.MY_DOCUMENTS) + } + + static getApplication(): string { + const cs = new CSInterface() + return cs.getSystemPath(SystemPath.APPLICATION) + } + + static getExtension(): string { + const cs = new CSInterface() + return cs.getSystemPath(SystemPath.EXTENSION) + } + + static getHostApplication(): string { + const cs = new CSInterface() + return cs.getSystemPath(SystemPath.HOST_APPLICATION) + } +} \ No newline at end of file diff --git a/AdminPanel/plugins/utils/cep/cep_engine_extensions.js b/AdminPanel/plugins/utils/cep/cep_engine_extensions.js new file mode 100644 index 0000000..e82020e --- /dev/null +++ b/AdminPanel/plugins/utils/cep/cep_engine_extensions.js @@ -0,0 +1,701 @@ +// FOR REFERENCE ONLY -- THIS FILE IS NOT BUNDLED + +/************************************************************************************************** +* +* ADOBE SYSTEMS INCORPORATED +* Copyright 2020 Adobe Systems Incorporated +* All Rights Reserved. +* +* NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the +* terms of the Adobe license agreement accompanying it. If you have received this file from a +* source other than Adobe, then your use, modification, or distribution of it requires the prior +* written permission of Adobe. +* +**************************************************************************************************/ + +// This is the JavaScript code for bridging to native functionality +// See CEPEngine_extensions.cpp for implementation of native methods. +// +// Note: So far all native file i/o functions are synchronous, and aynchronous file i/o is TBD. + +/** Version v11.0.0 */ + +/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, forin: true, maxerr: 50, regexp: true */ +/*global define, native */ + +var cep; +if (!cep) { + cep = {}; +} +if (!cep.fs) { + cep.fs = {}; +} +if (!cep.process) { + cep.process = {}; +} +if (!cep.encoding) { + cep.encoding = {}; +} +if (!cep.util) { + cep.util = {}; +} +(function () { + // Internal function to get the last error code. + native function GetLastError(); + function getLastError() { + return GetLastError(); + } + + function getErrorResult(){ + var result = {err: getLastError()}; + return result; + } + + // Error values. These MUST be in sync with the error values + // at the top of CEPEngine_extensions.cpp + + /** + * @constant No error. + */ + cep.fs.NO_ERROR = 0; + + /** + * @constant Unknown error occurred. + */ + cep.fs.ERR_UNKNOWN = 1; + + /** + * @constant Invalid parameters passed to function. + */ + cep.fs.ERR_INVALID_PARAMS = 2; + + /** + * @constant File or directory was not found. + */ + cep.fs.ERR_NOT_FOUND = 3; + + /** + * @constant File or directory could not be read. + */ + cep.fs.ERR_CANT_READ = 4; + + /** + * @constant An unsupported encoding value was specified. + */ + cep.fs.ERR_UNSUPPORTED_ENCODING = 5; + + /** + * @constant File could not be written. + */ + cep.fs.ERR_CANT_WRITE = 6; + + /** + * @constant Target directory is out of space. File could not be written. + */ + cep.fs.ERR_OUT_OF_SPACE = 7; + + /** + * @constant Specified path does not point to a file. + */ + cep.fs.ERR_NOT_FILE = 8; + + /** + * @constant Specified path does not point to a directory. + */ + cep.fs.ERR_NOT_DIRECTORY = 9; + + /** + * @constant Specified file already exists. + */ + cep.fs.ERR_FILE_EXISTS = 10; + + /** + * @constant The maximum number of processes has been exceeded. + */ + cep.process.ERR_EXCEED_MAX_NUM_PROCESS = 101; + + /** + * @constant Invalid URL. + */ + cep.util.ERR_INVALID_URL = 201; + + /** + * @constant deprecated API. + */ + cep.util.DEPRECATED_API = 202; + + /** + * @constant UTF8 encoding type. + */ + cep.encoding.UTF8 = "UTF-8"; + + /** + * @constant Base64 encoding type. + */ + cep.encoding.Base64 = "Base64"; + + /** + * Displays the OS File Open dialog, allowing the user to select files or directories. + * + * @param allowMultipleSelection {boolean} When true, multiple files/folders can be selected. + * @param chooseDirectory {boolean} When true, only folders can be selected. When false, only + * files can be selected. + * @param title {string} Title of the open dialog. + * @param initialPath {string} Initial path to display in the dialog. Pass NULL or "" to + * display the last path chosen. + * @param fileTypes {Array.} The file extensions (without the dot) for the types + * of files that can be selected. Ignored when chooseDirectory=true. + * + * @return An object with these properties: + *
  • "data": An array of the full names of the selected files.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_INVALID_PARAMS
  • + *
+ **/ + native function ShowOpenDialog(); + cep.fs.showOpenDialog = function (allowMultipleSelection, chooseDirectory, title, initialPath, fileTypes) { + var resultString = ShowOpenDialog(allowMultipleSelection, chooseDirectory, + title || 'Open', initialPath || '', + fileTypes ? fileTypes.join(' ') : ''); + + var result = {data: JSON.parse(resultString || '[]'), err: getLastError() }; + return result; + }; + + /** + * Displays the OS File Open dialog, allowing the user to select files or directories. + * + * @param allowMultipleSelection {boolean} When true, multiple files/folders can be selected. + * @param chooseDirectory {boolean} When true, only folders can be selected. When false, only + * files can be selected. + * @param title {string} Title of the open dialog. + * @param initialPath {string} Initial path to display in the dialog. Pass NULL or "" to + * display the last path chosen. + * @param fileTypes {Array.} The file extensions (without the dot) for the types + * of files that can be selected. Ignored when chooseDirectory=true. + * @param friendlyFilePrefix {string} String to put in front of the extensions + * of files that can be selected. Ignored when chooseDirectory=true. (win only) + * For example: + * fileTypes = ["gif", "jpg", "jpeg", "png", "bmp", "webp", "svg"]; + * friendlyFilePrefix = "Images (*.gif;*.jpg;*.jpeg;*.png;*.bmp;*.webp;*.svg)"; + * @param prompt {string} String for OK button (mac only, default is "Open" on mac, "Open" or "Select Folder" on win). + * + * @return An object with these properties: + *
  • "data": An array of the full names of the selected files.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_INVALID_PARAMS
  • + *
+ **/ + native function ShowOpenDialogEx(); + cep.fs.showOpenDialogEx = function (allowMultipleSelection, chooseDirectory, title, initialPath, fileTypes, + friendlyFilePrefix, prompt) { + var resultString = ShowOpenDialogEx(allowMultipleSelection, chooseDirectory, + title || 'Open', initialPath || '', + fileTypes ? fileTypes.join(' ') : '', friendlyFilePrefix || '', + prompt || ''); + + var result = {data: JSON.parse(resultString || '[]'), err: getLastError() }; + return result; + }; + + /** + * Displays the OS File Save dialog, allowing the user to type in a file name. + * + * @param title {string} Title of the save dialog. + * @param initialPath {string} Initial path to display in the dialog. Pass NULL or "" to + * display the last path chosen. + * @param fileTypes {Array.} The file extensions (without the dot) for the types + * of files that can be selected. + * @param defaultName {string} String to start with for the file name. + * @param friendlyFilePrefix {string} String to put in front of the extensions of files that can be selected. (win only) + * For example: + * fileTypes = ["gif", "jpg", "jpeg", "png", "bmp", "webp", "svg"]; + * friendlyFilePrefix = "Images (*.gif;*.jpg;*.jpeg;*.png;*.bmp;*.webp;*.svg)"; + * @param prompt {string} String for Save button (mac only, default is "Save" on mac and win). + * @param nameFieldLabel {string} String displayed in front of the file name text field (mac only, "File name:" on win). + * + * @return An object with these properties: + *
  • "data": The file path selected to save at or "" if canceled
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_INVALID_PARAMS
  • + *
+ **/ + native function ShowSaveDialogEx(); + cep.fs.showSaveDialogEx = function (title, initialPath, fileTypes, defaultName, friendlyFilePrefix, prompt, nameFieldLabel) { + var resultString = ShowSaveDialogEx(title || '', initialPath || '', + fileTypes ? fileTypes.join(' ') : '', defaultName || '', + friendlyFilePrefix || '', prompt || '', nameFieldLabel || ''); + + var result = {data: resultString || '', err: getLastError() }; + return result; + }; + + /** + * Reads the contents of a folder. + * + * @param path {string} The path of the folder to read. + * + * @return An object with these properties: + *
  • "data": An array of the names of the contained files (excluding '.' and '..'.
  • + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_NOT_FOUND + *
    ERR_CANT_READ
+ **/ + native function ReadDir(); + cep.fs.readdir = function (path) { + var resultString = ReadDir(path); + var result = {data: JSON.parse(resultString || '[]'), err: getLastError() }; + return result; + }; + + /** + * Creates a new folder. + * + * @param path {string} The path of the folder to create. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS
+ **/ + native function MakeDir(); + cep.fs.makedir = function (path) { + MakeDir(path); + return getErrorResult(); + }; + + /** + * Renames a file or folder. + * + * @param oldPath {string} The old name of the file or folder. + * @param newPath {string} The new name of the file or folder. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_NOT_FOUND + *
    ERR_FILE_EXISTS
+ **/ + native function Rename(); + cep.fs.rename = function(oldPath, newPath) { + Rename(oldPath, newPath); + return getErrorResult(); + }; + + /** + * Reports whether an item is a file or folder. + * + * @param path {string} The path of the file or folder. + * + * @return An object with these properties: + *
  • "data": An object with properties + *
    isFile (boolean) + *
    isDirectory (boolean) + *
    mtime (modification DateTime)
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_NOT_FOUND
  • + *
+ **/ + native function IsDirectory(); + native function GetFileModificationTime(); + cep.fs.stat = function (path) { + var isDir = IsDirectory(path); + var modtime = GetFileModificationTime(path); + var result = { + data: { + isFile: function () { + return !isDir; + }, + isDirectory: function () { + return isDir; + }, + mtime: modtime + }, + err: getLastError() + }; + + return result; + }; + + /** + * Reads the entire contents of a file. + * + * @param path {string} The path of the file to read. + * @param encoding {string} The encoding of the contents of file, one of + * UTF8 (the default) or Base64. + * + * @return An object with these properties: + *
  • "data": The file contents.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_NOT_FOUND + *
    ERR_CANT_READ + *
    ERR_UNSUPPORTED_ENCODING
  • + *
+ **/ + native function ReadFile(); + cep.fs.readFile = function (path, encoding) { + encoding = encoding ? encoding : cep.encoding.UTF8; + var contents = ReadFile(path, encoding); + var result = {data: contents, err: getLastError() }; + return result; + }; + + /** + * Writes data to a file, replacing the file if it already exists. + * + * @param path {string} The path of the file to write. + * @param data {string} The data to write to the file. + * @param encoding {string} The encoding of the contents of file, one of + * UTF8 (the default) or Base64. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_UNSUPPORTED_ENCODING + *
    ERR_CANT_WRITE + *
    ERR_OUT_OF_SPACE
+ **/ + native function WriteFile(); + cep.fs.writeFile = function (path, data, encoding) { + encoding = encoding ? encoding : cep.encoding.UTF8; + WriteFile(path, data, encoding); + return getErrorResult(); + }; + + /** + * Sets permissions for a file or folder. + * + * @param path {string} The path of the file or folder. + * @param mode {number} The permissions in numeric format (for example, 0777). + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_CANT_WRITE
+ **/ + native function SetPosixPermissions(); + cep.fs.chmod = function (path, mode) { + SetPosixPermissions(path, mode); + return getErrorResult(); + }; + + /** + * Deletes a file. + * + * @param path {string} The path of the file to delete. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_NOT_FOUND + *
    ERR_NOT_FILE
+ **/ + native function DeleteFileOrDirectory(); + native function IsDirectory(); + cep.fs.deleteFile = function (path) { + if (IsDirectory(path)) { + var result = {err: cep.fs.ERR_NOT_FILE}; + return result; + } + DeleteFileOrDirectory(path); + return getErrorResult(); + }; + + /** + * Creates a process. + * + * @param arguments {list} The arguments to create process. The first one is the full path of the executable, + * followed by the arguments of the executable. + * + * @return An object with these properties: + *
  • "data": The pid of the process, or -1 on error.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_EXCEED_MAX_NUM_PROCESS + *
    ERR_NOT_FOUND + *
    ERR_NOT_FILE
  • + *
+ **/ + native function CreateProcess(); + cep.process.createProcess = function () { + var args = Array.prototype.slice.call(arguments); + var pid = CreateProcess(args); + var result = {data: pid, err: getLastError()}; + return result; + }; + + /** + * Registers a standard-output handler for a process. + * + * @param pid {int} The pid of the process. + * @param callback {function} The handler function for the standard output callback. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function SetupStdOutHandler(); + cep.process.stdout = function (pid, callback) { + SetupStdOutHandler(pid, callback); + return getErrorResult(); + }; + + /** + * Registers up a standard-error handler for a process. + * + * @param pid {int} The pid of the process. + * @param callback {function} The handler function for the standard error callback. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function SetupStdErrHandler(); + cep.process.stderr = function (pid, callback) { + SetupStdErrHandler(pid, callback); + return getErrorResult(); + }; + + /** + * Writes data to the standard input of a process. + * + * @param pid {int} The pid of the process + * @param data {string} The data to write. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function WriteStdIn(); + cep.process.stdin = function (pid, data) { + WriteStdIn(pid, data); + return getErrorResult(); + }; + + /** + * Retrieves the working directory of a process. + * + * @param pid {int} The pid of the process. + * + * @return An object with these properties: + *
  • "data": The path of the working directory.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function GetWorkingDirectory(); + cep.process.getWorkingDirectory = function (pid) { + var wd = GetWorkingDirectory(pid); + var result = {data: wd, err: getLastError()}; + return result; + }; + + /** + * Waits for a process to quit. + * + * @param pid {int} The pid of the process. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function WaitFor(); + cep.process.waitfor = function (pid) { + WaitFor(pid); + return getErrorResult(); + }; + + /** + * Registers a handler for the onquit callback of a process. + * + * @param pid {int} The pid of the process. + * @param callback {function} The handler function. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function OnQuit(); + cep.process.onquit = function (pid, callback) { + OnQuit(pid, callback); + return getErrorResult(); + }; + + /** + * Reports whether a process is currently running. + * + * @param pid {int} The pid of the process. + * + * @return An object with these properties: + *
  • "data": True if the process is running, false otherwise.
  • + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function IsRunning(); + cep.process.isRunning = function (pid) { + var isRunning = IsRunning(pid); + var result = {data: isRunning, err: getLastError()}; + return result; + }; + + /** + * Terminates a process. + * + * @param pid {int} The pid of the process + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS + *
    ERR_INVALID_PROCESS_ID
+ **/ + native function Terminate(); + cep.process.terminate = function (pid) { + Terminate(pid); + return getErrorResult(); + }; + + /** + * Encoding conversions. + * + */ + cep.encoding.convertion = + { + utf8_to_b64: function(str) { + return window.btoa(unescape(encodeURIComponent(str))); + }, + + b64_to_utf8: function(base64str) { + // If a base64 string contains any whitespace character, DOM Exception 5 occurs during window.atob, please see + // http://stackoverflow.com/questions/14695988/dom-exception-5-invalid-character-error-on-valid-base64-image-string-in-javascri + base64str = base64str.replace(/\s/g, ''); + return decodeURIComponent(escape(window.atob(base64str))); + }, + + binary_to_b64: function(binary) { + return window.btoa(binary); + }, + + b64_to_binary: function(base64str) { + return window.atob(base64str); + }, + + ascii_to_b64: function(ascii) { + return window.btoa(binary); + }, + + b64_to_ascii: function(base64str) { + return window.atob(base64str); + } + }; + + /** + * Opens a page in the default system browser. + * + * @param url {string} The URL of the page/file to open, or the email address. + * Must use HTTP/HTTPS/file/mailto. For example: + * "http://www.adobe.com" + * "https://github.com" + * "file:///C:/log.txt" + * "mailto:test@adobe.com" + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_UNKNOWN + *
    ERR_INVALID_PARAMS
+ **/ + native function OpenURLInDefaultBrowser(); + cep.util.openURLInDefaultBrowser = function (url) { + if (url && (url.indexOf("http://") === 0 || + url.indexOf("https://") === 0 || + url.indexOf("file://") === 0 || + url.indexOf("mailto:") === 0)) { + OpenURLInDefaultBrowser(url); + return getErrorResult(); + } else { + return { err : cep.util.ERR_INVALID_URL }; + } + }; + + /** + * Registers a callback function for extension unload. If called more than once, + * the last callback that is successfully registered is used. + * + * @deprecated since version 6.0.0 + * + * @param callback {function} The handler function. + * + * @return An object with this property: + *
  • "err": The status of the operation, one of: + *
    NO_ERROR + *
    ERR_INVALID_PARAMS
+ **/ + native function RegisterExtensionUnloadCallback(); + cep.util.registerExtensionUnloadCallback = function (callback) { + return { err : cep.util.DEPRECATED_API }; + }; + + /** + * Stores the user's proxy credentials + * + * @param username {string} proxy username + * @param password {string} proxy password + * + * @return An object with this property: + *
  • "err": The status of the operation, one of + *
    NO_ERROR + *
    ERR_INVALID_PARAMS
  • + *
+ **/ + native function StoreProxyCredentials(); + cep.util.storeProxyCredentials = function (username, password) { + StoreProxyCredentials(username, password); + return getErrorResult(); + }; + +})(); \ No newline at end of file diff --git a/AdminPanel/plugins/utils/cep/csinterface.d.ts b/AdminPanel/plugins/utils/cep/csinterface.d.ts new file mode 100644 index 0000000..70de514 --- /dev/null +++ b/AdminPanel/plugins/utils/cep/csinterface.d.ts @@ -0,0 +1,788 @@ +/** + * Stores constants for the window types supported by the CSXS infrastructure. + */ +declare function CSXSWindowType(): void; + +/** + * EvalScript error message + */ +declare var EvalScript_ErrMessage: any; + +/** + * Version +Defines a version number with major, minor, micro, and special +components. The major, minor and micro values are numeric; the special +value can be any string. + * @param major - The major version component, a positive integer up to nine digits long. + * @param minor - The minor version component, a positive integer up to nine digits long. + * @param micro - The micro version component, a positive integer up to nine digits long. + * @param special - The special version component, an arbitrary string. + */ +declare class Version { + constructor(major: any, minor: any, micro: any, special: any); + /** + * The maximum value allowed for a numeric version component. + This reflects the maximum value allowed in PlugPlug and the manifest schema. + */ + static MAX_NUM: any; +} + +/** + * VersionBound +Defines a boundary for a version range, which associates a \c Version object +with a flag for whether it is an inclusive or exclusive boundary. + * @param version - The \c #Version object. + * @param inclusive - True if this boundary is inclusive, false if it is exclusive. + */ +declare class VersionBound { + constructor(version: any, inclusive: any); +} + +/** + * VersionRange +Defines a range of versions using a lower boundary and optional upper boundary. + * @param lowerBound - The \c #VersionBound object. + * @param upperBound - The \c #VersionBound object, or null for a range with no upper boundary. + */ +declare class VersionRange { + constructor(lowerBound: any, upperBound: any); +} + +/** + * Runtime +Represents a runtime related to the CEP infrastructure. +Extensions can declare dependencies on particular +CEP runtime versions in the extension manifest. + * @param name - The runtime name. + * @param version - A \c #VersionRange object that defines a range of valid versions. + */ +declare class Runtime { + constructor(name: any, version: any); +} + +/** + * Extension +Encapsulates a CEP-based extension to an Adobe application. + * @param id - The unique identifier of this extension. + * @param name - The localizable display name of this extension. + * @param mainPath - The path of the "index.html" file. + * @param basePath - The base path of this extension. + * @param windowType - The window type of the main window of this extension. + * Valid values are defined by \c #CSXSWindowType. + * @param width - The default width in pixels of the main window of this extension. + * @param height - The default height in pixels of the main window of this extension. + * @param minWidth - The minimum width in pixels of the main window of this extension. + * @param minHeight - The minimum height in pixels of the main window of this extension. + * @param maxWidth - The maximum width in pixels of the main window of this extension. + * @param maxHeight - The maximum height in pixels of the main window of this extension. + * @param defaultExtensionDataXml - The extension data contained in the default \c ExtensionDispatchInfo section of the extension manifest. + * @param specialExtensionDataXml - The extension data contained in the application-specific \c ExtensionDispatchInfo section of the extension manifest. + * @param requiredRuntimeList - An array of \c Runtime objects for runtimes required by this extension. + * @param isAutoVisible - True if this extension is visible on loading. + * @param isPluginExtension - True if this extension has been deployed in the Plugins folder of the host application. + */ +declare class Extension { + constructor( + id: any, + name: any, + mainPath: any, + basePath: any, + windowType: any, + width: any, + height: any, + minWidth: any, + minHeight: any, + maxWidth: any, + maxHeight: any, + defaultExtensionDataXml: any, + specialExtensionDataXml: any, + requiredRuntimeList: any, + isAutoVisible: any, + isPluginExtension: any + ); +} + +/** + * CSEvent +A standard JavaScript event, the base class for CEP events. + * @param type - The name of the event type. + * @param scope - The scope of event, can be "GLOBAL" or "APPLICATION". + * @param appId - The unique identifier of the application that generated the event. + * @param extensionId - The unique identifier of the extension that generated the event. + */ +declare class CSEvent { + public type: any + public scope: any + public appId: any + public extensionId: any + constructor(type?: any, scope?: any, appId?: any, extensionId?: any); + /** + * Event-specific data. + */ + data: any; +} + +/** + * SystemPath +Stores operating-system-specific location constants for use in the +\c #CSInterface.getSystemPath() method. + */ +declare class SystemPath { + constructor(); + /** + * The path to user data. + */ + static USER_DATA: any; + /** + * The path to common files for Adobe applications. + */ + static COMMON_FILES: any; + /** + * The path to the user's default document folder. + */ + static MY_DOCUMENTS: any; + static APPLICATION: any; + /** + * The path to current extension. + */ + static EXTENSION: any; + /** + * The path to hosting application's executable. + */ + static HOST_APPLICATION: any; +} + +/** + * ColorType +Stores color-type constants. + */ +declare class ColorType { + constructor(); + /** + * RGB color type. + */ + static RGB: any; + /** + * Gradient color type. + */ + static GRADIENT: any; + /** + * Null color type. + */ + static NONE: any; +} + +/** + * RGBColor +Stores an RGB color with red, green, blue, and alpha values. +All values are in the range [0.0 to 255.0]. Invalid numeric values are +converted to numbers within this range. + * @param red - The red value, in the range [0.0 to 255.0]. + * @param green - The green value, in the range [0.0 to 255.0]. + * @param blue - The blue value, in the range [0.0 to 255.0]. + * @param alpha - The alpha (transparency) value, in the range [0.0 to 255.0]. + The default, 255.0, means that the color is fully opaque. + */ +declare class RGBColor { + constructor(red: any, green: any, blue: any, alpha: any); +} + +/** + * Direction +A point value in which the y component is 0 and the x component +is positive or negative for a right or left direction, +or the x component is 0 and the y component is positive or negative for +an up or down direction. + * @param x - The horizontal component of the point. + * @param y - The vertical component of the point. + */ +declare class Direction { + constructor(x: any, y: any); +} + +/** + * GradientStop +Stores gradient stop information. + * @param offset - The offset of the gradient stop, in the range [0.0 to 1.0]. + * @param rgbColor - The color of the gradient at this point, an \c #RGBColor object. + */ +declare class GradientStop { + constructor(offset: any, rgbColor: any); +} + +/** + * GradientColor +Stores gradient color information. + * @param type - The gradient type, must be "linear". + * @param direction - A \c #Direction object for the direction of the gradient + * (up, down, right, or left). + * @param numStops - The number of stops in the gradient. + * @param gradientStopList - An array of \c #GradientStop objects. + */ +declare class GradientColor { + constructor(type: any, direction: any, numStops: any, gradientStopList: any); +} + +/** + * UIColor +Stores color information, including the type, anti-alias level, and specific color +values in a color object of an appropriate type. + * @param type - The color type, 1 for "rgb" and 2 for "gradient". + * The supplied color object must correspond to this type. + * @param antialiasLevel - The anti-alias level constant. + * @param color - A \c #RGBColor or \c #GradientColor object containing specific color information. + */ +declare class UIColor { + constructor(type: any, antialiasLevel: any, color: any); +} + +/** + * AppSkinInfo +Stores window-skin properties, such as color and font. All color parameter values are \c #UIColor objects except that systemHighlightColor is \c #RGBColor object. + * @param baseFontFamily - The base font family of the application. + * @param baseFontSize - The base font size of the application. + * @param appBarBackgroundColor - The application bar background color. + * @param panelBackgroundColor - The background color of the extension panel. + * @param appBarBackgroundColorSRGB - The application bar background color, as sRGB. + * @param panelBackgroundColorSRGB - The background color of the extension panel, as sRGB. + * @param systemHighlightColor - The highlight color of the extension panel, if provided by the host application. Otherwise, the operating-system highlight color. + */ +declare class AppSkinInfo { + constructor( + baseFontFamily: any, + baseFontSize: any, + appBarBackgroundColor: any, + panelBackgroundColor: any, + appBarBackgroundColorSRGB: any, + panelBackgroundColorSRGB: any, + systemHighlightColor: any + ); +} + +/** + * HostEnvironment +Stores information about the environment in which the extension is loaded. + * @param appName - The application's name. + * @param appVersion - The application's version. + * @param appLocale - The application's current license locale. + * @param appUILocale - The application's current UI locale. + * @param appId - The application's unique identifier. + * @param isAppOnline - True if the application is currently online. + * @param appSkinInfo - An \c #AppSkinInfo object containing the application's default color and font styles. + */ +declare class HostEnvironment { + constructor( + appName: any, + appVersion: any, + appLocale: any, + appUILocale: any, + appId: any, + isAppOnline: any, + appSkinInfo: any + ); +} + +/** + * HostCapabilities +Stores information about the host capabilities. + * @param EXTENDED_PANEL_MENU - True if the application supports panel menu. + * @param EXTENDED_PANEL_ICONS - True if the application supports panel icon. + * @param DELEGATE_APE_ENGINE - True if the application supports delegated APE engine. + * @param SUPPORT_HTML_EXTENSIONS - True if the application supports HTML extensions. + * @param DISABLE_FLASH_EXTENSIONS - True if the application disables FLASH extensions. + */ +declare class HostCapabilities { + constructor( + EXTENDED_PANEL_MENU: any, + EXTENDED_PANEL_ICONS: any, + DELEGATE_APE_ENGINE: any, + SUPPORT_HTML_EXTENSIONS: any, + DISABLE_FLASH_EXTENSIONS: any + ); +} + +/** + * ApiVersion +Stores current api version. + +Since 4.2.0 + * @param major - The major version + * @param minor - The minor version. + * @param micro - The micro version. + */ +declare class ApiVersion { + constructor(major: any, minor: any, micro: any); +} + +/** + * MenuItemStatus +Stores flyout menu item status + +Since 5.2.0 + * @param menuItemLabel - The menu item label. + * @param enabled - True if user wants to enable the menu item. + * @param checked - True if user wants to check the menu item. + */ +declare class MenuItemStatus { + constructor(menuItemLabel: any, enabled: any, checked: any); +} + +/** + * ContextMenuItemStatus +Stores the status of the context menu item. + +Since 5.2.0 + * @param menuItemID - The menu item id. + * @param enabled - True if user wants to enable the menu item. + * @param checked - True if user wants to check the menu item. + */ +declare class ContextMenuItemStatus { + constructor(menuItemID: any, enabled: any, checked: any); +} + +/** + * CSInterface +This is the entry point to the CEP extensibility infrastructure. +Instantiate this object and use it to: +
    +
  • Access information about the host application in which an extension is running
  • +
  • Launch an extension
  • +
  • Register interest in event notifications, and dispatch events
  • +
+ */ + +type RBGAColor = { + alpha: number; + green: number; + blue: number; + red: number; +}; + +export default class CSInterface { + constructor(); + /** + * User can add this event listener to handle native application theme color changes. + Callback function gives extensions ability to fine-tune their theme color after the + global theme color has been changed. + The callback function should be like below: + * @example + * // event is a CSEvent object, but user can ignore it. + function OnAppThemeColorChanged(event) + { + // Should get a latest HostEnvironment object from application. + var skinInfo = JSON.parse(window.__adobe_cep__.getHostEnvironment()).appSkinInfo; + // Gets the style information such as color info from the skinInfo, + // and redraw all UI controls of your extension according to the style info. + } + */ + static THEME_COLOR_CHANGED_EVENT: any; + /** + * The host environment data object. + */ + hostEnvironment: { + appName: string; + appVersion: string; + appLocale: string; + appUILocale: string; + appId: string; + isAppOnline: boolean; + appSkinInfo: { + baseFontFamily: string; + baseFontSize: number; + appBarBackgroundColor: { + antialiasLevel: number; + type: number; + color: RBGAColor; + }; + panelBackgroundColor: { + antialiasLevel: number; + type: number; + color: RBGAColor; + }; + appBarBackgroundColorSRGB: { + antialiasLevel: number; + type: number; + color: RBGAColor; + }; + panelBackgroundColorSRGB: { + antialiasLevel: number; + type: number; + color: RBGAColor; + }; + systemHighlightColor: RBGAColor; + }; + }; + /** + * Retrieves information about the host environment in which the + extension is currently running. + * @returns A \c #HostEnvironment object. + */ + getHostEnvironment(): any; + /** + * Loads binary file created which is located at url asynchronously + * @example + * To create JS binary use command ./cep_compiler test.js test.bin + To load JS binary asyncronously + var CSLib = new CSInterface(); + CSLib.loadBinAsync(url, function () { }); + * @param urlName - url at which binary file is located. Local files should start with 'file://' + * @param callback - Optional. A callback function that returns after binary is loaded + */ + loadBinAsync(urlName: any, callback: any): void; + /** + * Loads binary file created synchronously + * @example + * To create JS binary use command ./cep_compiler test.js test.bin + To load JS binary syncronously + var CSLib = new CSInterface(); + CSLib.loadBinSync(path); + * @param pathName - the local path at which binary file is located + */ + loadBinSync(pathName: any): void; + /** + * Closes this extension. + */ + closeExtension(): void; + /** + * Retrieves a path for which a constant is defined in the system. + * @param pathType - The path-type constant defined in \c #SystemPath , + * @returns The platform-specific system path string. + */ + getSystemPath(pathType: any): any; + /** + * Evaluates a JavaScript script, which can use the JavaScript DOM + of the host application. + * @param script - The JavaScript script. + * @param callback - Optional. A callback function that receives the result of execution. + If execution fails, the callback function receives the error message \c EvalScript_ErrMessage. + */ + evalScript(script: any, callback: any): void; + /** + * Retrieves the unique identifier of the application. + in which the extension is currently running. + * @returns The unique ID string. + */ + getApplicationID(): any; + /** + * Retrieves host capability information for the application + in which the extension is currently running. + * @returns A \c #HostCapabilities object. + */ + getHostCapabilities(): any; + /** + * Triggers a CEP event programmatically. Yoy can use it to dispatch + an event of a predefined type, or of a type you have defined. + * @param event - A \c CSEvent object. + */ + dispatchEvent(event: any): void; + /** + * Registers an interest in a CEP event of a particular type, and + assigns an event handler. + The event infrastructure notifies your extension when events of this type occur, + passing the event object to the registered handler function. + * @param type - The name of the event type of interest. + * @param listener - The JavaScript handler function or method. + * @param obj - Optional, the object containing the handler method, if any. + Default is null. + */ + addEventListener(type: any, listener: Function, obj?: any): void; + /** + * Removes a registered event listener. + * @param type - The name of the event type of interest. + * @param listener - The JavaScript handler function or method that was registered. + * @param obj - Optional, the object containing the handler method, if any. + Default is null. + */ + removeEventListener(type: any, listener: any, obj: any): void; + /** + * Loads and launches another extension, or activates the extension if it is already loaded. + * @example + * To launch the extension "help" with ID "HLP" from this extension, call: + requestOpenExtension("HLP", ""); + * @param extensionId - The extension's unique identifier. + * @param startupParams - Not currently used, pass "". + */ + requestOpenExtension(extensionId: any, startupParams: any): void; + /** + * Retrieves the list of extensions currently loaded in the current host application. + The extension list is initialized once, and remains the same during the lifetime + of the CEP session. + * @param extensionIds - Optional, an array of unique identifiers for extensions of interest. + If omitted, retrieves data for all extensions. + * @returns Zero or more \c #Extension objects. + */ + getExtensions(extensionIds: any): any; + /** + * Retrieves network-related preferences. + * @returns A JavaScript object containing network preferences. + */ + getNetworkPreferences(): any; + /** + * Initializes the resource bundle for this extension with property values + for the current application and locale. + To support multiple locales, you must define a property file for each locale, + containing keyed display-string values for that locale. + See localization documentation for Extension Builder and related products. + + Keys can be in the + form key.value="localized string", for use in HTML text elements. + For example, in this input element, the localized \c key.value string is displayed + instead of the empty \c value string: + + + * @returns An object containing the resource bundle information. + */ + initResourceBundle(): any; + /** + * Writes installation information to a file. + * @returns The file path. + */ + dumpInstallationInfo(): any; + /** + * Retrieves version information for the current Operating System, + See http://www.useragentstring.com/pages/Chrome/ for Chrome \c navigator.userAgent values. + * @returns A string containing the OS version, or "unknown Operation System". + If user customizes the User Agent by setting CEF command parameter "--user-agent", only + "Mac OS X" or "Windows" will be returned. + */ + getOSInformation(): any; + /** + * Opens a page in the default system browser. + + Since 4.2.0 + * @param url - The URL of the page/file to open, or the email address. + Must use HTTP/HTTPS/file/mailto protocol. For example: + "http://www.adobe.com" + "https://github.com" + "file:///C:/log.txt" + "mailto:test@adobe.com" + * @returns One of these error codes:\n +
    \n +
  • NO_ERROR - 0
  • \n +
  • ERR_UNKNOWN - 1
  • \n +
  • ERR_INVALID_PARAMS - 2
  • \n +
  • ERR_INVALID_URL - 201
  • \n +
\n + */ + openURLInDefaultBrowser(url: any): any; + /** + * Retrieves extension ID. + + Since 4.2.0 + * @returns extension ID. + */ + getExtensionID(): any; + /** + * Retrieves the scale factor of screen. + On Windows platform, the value of scale factor might be different from operating system's scale factor, + since host application may use its self-defined scale factor. + + Since 4.2.0 + * @returns One of the following float number. +
    \n +
  • -1.0 when error occurs
  • \n +
  • 1.0 means normal screen
  • \n +
  • >1.0 means HiDPI screen
  • \n +
\n + */ + getScaleFactor(): any; + /** + * Set a handler to detect any changes of scale factor. This only works on Mac. + + Since 4.2.0 + * @param handler - The function to be called when scale factor is changed. + */ + setScaleFactorChangedHandler(handler: any): void; + /** + * Retrieves current API version. + + Since 4.2.0 + * @returns ApiVersion object. + */ + getCurrentApiVersion(): { + minor: string; + micro: string; + major: string; + }; + /** + * Set panel flyout menu by an XML. + + Since 5.2.0 + + Register a callback function for "com.adobe.csxs.events.flyoutMenuClicked" to get notified when a + menu item is clicked. + The "data" attribute of event is an object which contains "menuId" and "menuName" attributes. + + Register callback functions for "com.adobe.csxs.events.flyoutMenuOpened" and "com.adobe.csxs.events.flyoutMenuClosed" + respectively to get notified when flyout menu is opened or closed. + * @param menu - A XML string which describes menu structure. + An example menu XML: + + + + + + + + + + + + */ + setPanelFlyoutMenu(menu: any): void; + /** + * Updates a menu item in the extension window's flyout menu, by setting the enabled + and selection status. + + Since 5.2.0 + * @param menuItemLabel - The menu item label. + * @param enabled - True to enable the item, false to disable it (gray it out). + * @param checked - True to select the item, false to deselect it. + * @returns false when the host application does not support this functionality (HostCapabilities.EXTENDED_PANEL_MENU is false). + Fails silently if menu label is invalid. + */ + updatePanelMenuItem(menuItemLabel: any, enabled: any, checked: any): any; + /** + * An example menu XML: + + + + + + + + + + + + * @param menu - A XML string which describes menu structure. + * @param callback - The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. + */ + setContextMenu(menu: any, callback: any): void; + /** + * An example menu JSON: + + { + "menu": [ + { + "id": "menuItemId1", + "label": "testExample1", + "enabled": true, + "checkable": true, + "checked": false, + "icon": "./image/small_16X16.png" + }, + { + "id": "menuItemId2", + "label": "testExample2", + "menu": [ + { + "id": "menuItemId2-1", + "label": "testExample2-1", + "menu": [ + { + "id": "menuItemId2-1-1", + "label": "testExample2-1-1", + "enabled": false, + "checkable": true, + "checked": true + } + ] + }, + { + "id": "menuItemId2-2", + "label": "testExample2-2", + "enabled": true, + "checkable": true, + "checked": true + } + ] + }, + { + "label": "---" + }, + { + "id": "menuItemId3", + "label": "testExample3", + "enabled": false, + "checkable": true, + "checked": false + } + ] + } + * @param menu - A JSON string which describes menu structure. + * @param callback - The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. + */ + setContextMenuByJSON(menu: any, callback: any): void; + /** + * Updates a context menu item by setting the enabled and selection status. + + Since 5.2.0 + * @param menuItemID - The menu item ID. + * @param enabled - True to enable the item, false to disable it (gray it out). + * @param checked - True to select the item, false to deselect it. + */ + updateContextMenuItem(menuItemID: any, enabled: any, checked: any): void; + /** + * Get the visibility status of an extension window. + + Since 6.0.0 + * @returns true if the extension window is visible; false if the extension window is hidden. + */ + isWindowVisible(): any; + /** + * Resize extension's content to the specified dimensions. + 1. Works with modal and modeless extensions in all Adobe products. + 2. Extension's manifest min/max size constraints apply and take precedence. + 3. For panel extensions + 3.1 This works in all Adobe products except: + * Premiere Pro + * Prelude + * After Effects + 3.2 When the panel is in certain states (especially when being docked), + it will not change to the desired dimensions even when the + specified size satisfies min/max constraints. + + Since 6.0.0 + * @param width - The new width + * @param height - The new height + */ + resizeContent(width: any, height: any): void; + /** + * Register the invalid certificate callback for an extension. + This callback will be triggered when the extension tries to access the web site that contains the invalid certificate on the main frame. + But if the extension does not call this function and tries to access the web site containing the invalid certificate, a default error page will be shown. + + Since 6.1.0 + * @param callback - the callback function + */ + registerInvalidCertificateCallback(callback: any): void; + /** + * Register an interest in some key events to prevent them from being sent to the host application. + + This function works with modeless extensions and panel extensions. + Generally all the key events will be sent to the host application for these two extensions if the current focused element + is not text input or dropdown, + If you want to intercept some key events and want them to be handled in the extension, please call this function + in advance to prevent them being sent to the host application. + + Since 6.1.0 + */ + registerKeyEventsInterest(keyEventsInterest: any): void; + /** + * Set the title of the extension window. + This function works with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Flash Pro and Dreamweaver. + + Since 6.1.0 + * @param title - The window title. + */ + setWindowTitle(title: any): void; + /** + * Get the title of the extension window. + This function works with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Flash Pro and Dreamweaver. + + Since 6.1.0 + * @returns The window title. + */ + getWindowTitle(): any; +} diff --git a/AdminPanel/plugins/utils/cep/csinterface.js b/AdminPanel/plugins/utils/cep/csinterface.js new file mode 100644 index 0000000..56f7840 --- /dev/null +++ b/AdminPanel/plugins/utils/cep/csinterface.js @@ -0,0 +1,1263 @@ +/************************************************************************************************** + * + * ADOBE SYSTEMS INCORPORATED + * Copyright 2020 Adobe Systems Incorporated + * All Rights Reserved. + * + * NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the + * terms of the Adobe license agreement accompanying it. If you have received this file from a + * source other than Adobe, then your use, modification, or distribution of it requires the prior + * written permission of Adobe. + * + **************************************************************************************************/ + +/** CSInterface - v11.0.0 */ + +/** + * Stores constants for the window types supported by the CSXS infrastructure. + */ +function CSXSWindowType() {} + +/** Constant for the CSXS window type Panel. */ +CSXSWindowType._PANEL = "Panel"; + +/** Constant for the CSXS window type Modeless. */ +CSXSWindowType._MODELESS = "Modeless"; + +/** Constant for the CSXS window type ModalDialog. */ +CSXSWindowType._MODAL_DIALOG = "ModalDialog"; + +/** EvalScript error message */ +let EvalScript_ErrMessage = "EvalScript error."; + +/** + * @class Version + * Defines a version number with major, minor, micro, and special + * components. The major, minor and micro values are numeric; the special + * value can be any string. + * + * @param major The major version component, a positive integer up to nine digits long. + * @param minor The minor version component, a positive integer up to nine digits long. + * @param micro The micro version component, a positive integer up to nine digits long. + * @param special The special version component, an arbitrary string. + * + * @return A new \c Version object. + */ +function Version(major, minor, micro, special) { + this.major = major; + this.minor = minor; + this.micro = micro; + this.special = special; +} + +/** + * The maximum value allowed for a numeric version component. + * This reflects the maximum value allowed in PlugPlug and the manifest schema. + */ +Version.MAX_NUM = 999999999; + +/** + * @class VersionBound + * Defines a boundary for a version range, which associates a \c Version object + * with a flag for whether it is an inclusive or exclusive boundary. + * + * @param version The \c #Version object. + * @param inclusive True if this boundary is inclusive, false if it is exclusive. + * + * @return A new \c VersionBound object. + */ +function VersionBound(version, inclusive) { + this.version = version; + this.inclusive = inclusive; +} + +/** + * @class VersionRange + * Defines a range of versions using a lower boundary and optional upper boundary. + * + * @param lowerBound The \c #VersionBound object. + * @param upperBound The \c #VersionBound object, or null for a range with no upper boundary. + * + * @return A new \c VersionRange object. + */ +function VersionRange(lowerBound, upperBound) { + this.lowerBound = lowerBound; + this.upperBound = upperBound; +} + +/** + * @class Runtime + * Represents a runtime related to the CEP infrastructure. + * Extensions can declare dependencies on particular + * CEP runtime versions in the extension manifest. + * + * @param name The runtime name. + * @param version A \c #VersionRange object that defines a range of valid versions. + * + * @return A new \c Runtime object. + */ +function Runtime(name, versionRange) { + this.name = name; + this.versionRange = versionRange; +} + +/** + * @class Extension + * Encapsulates a CEP-based extension to an Adobe application. + * + * @param id The unique identifier of this extension. + * @param name The localizable display name of this extension. + * @param mainPath The path of the "index.html" file. + * @param basePath The base path of this extension. + * @param windowType The window type of the main window of this extension. + Valid values are defined by \c #CSXSWindowType. + * @param width The default width in pixels of the main window of this extension. + * @param height The default height in pixels of the main window of this extension. + * @param minWidth The minimum width in pixels of the main window of this extension. + * @param minHeight The minimum height in pixels of the main window of this extension. + * @param maxWidth The maximum width in pixels of the main window of this extension. + * @param maxHeight The maximum height in pixels of the main window of this extension. + * @param defaultExtensionDataXml The extension data contained in the default \c ExtensionDispatchInfo section of the extension manifest. + * @param specialExtensionDataXml The extension data contained in the application-specific \c ExtensionDispatchInfo section of the extension manifest. + * @param requiredRuntimeList An array of \c Runtime objects for runtimes required by this extension. + * @param isAutoVisible True if this extension is visible on loading. + * @param isPluginExtension True if this extension has been deployed in the Plugins folder of the host application. + * + * @return A new \c Extension object. + */ +function Extension( + id, + name, + mainPath, + basePath, + windowType, + width, + height, + minWidth, + minHeight, + maxWidth, + maxHeight, + defaultExtensionDataXml, + specialExtensionDataXml, + requiredRuntimeList, + isAutoVisible, + isPluginExtension +) { + this.id = id; + this.name = name; + this.mainPath = mainPath; + this.basePath = basePath; + this.windowType = windowType; + this.width = width; + this.height = height; + this.minWidth = minWidth; + this.minHeight = minHeight; + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this.defaultExtensionDataXml = defaultExtensionDataXml; + this.specialExtensionDataXml = specialExtensionDataXml; + this.requiredRuntimeList = requiredRuntimeList; + this.isAutoVisible = isAutoVisible; + this.isPluginExtension = isPluginExtension; +} + +/** + * @class CSEvent + * A standard JavaScript event, the base class for CEP events. + * + * @param type The name of the event type. + * @param scope The scope of event, can be "GLOBAL" or "APPLICATION". + * @param appId The unique identifier of the application that generated the event. + * @param extensionId The unique identifier of the extension that generated the event. + * + * @return A new \c CSEvent object + */ +function CSEvent(type, scope, appId, extensionId) { + this.type = type; + this.scope = scope; + this.appId = appId; + this.extensionId = extensionId; +} + +/** Event-specific data. */ +CSEvent.prototype.data = ""; + +/** + * @class SystemPath + * Stores operating-system-specific location constants for use in the + * \c #CSInterface.getSystemPath() method. + * @return A new \c SystemPath object. + */ +function SystemPath() {} + +/** The path to user data. */ +SystemPath.USER_DATA = "userData"; + +/** The path to common files for Adobe applications. */ +SystemPath.COMMON_FILES = "commonFiles"; + +/** The path to the user's default document folder. */ +SystemPath.MY_DOCUMENTS = "myDocuments"; + +/** @deprecated. Use \c #SystemPath.Extension. */ +SystemPath.APPLICATION = "application"; + +/** The path to current extension. */ +SystemPath.EXTENSION = "extension"; + +/** The path to hosting application's executable. */ +SystemPath.HOST_APPLICATION = "hostApplication"; + +/** + * @class ColorType + * Stores color-type constants. + */ +function ColorType() {} + +/** RGB color type. */ +ColorType.RGB = "rgb"; + +/** Gradient color type. */ +ColorType.GRADIENT = "gradient"; + +/** Null color type. */ +ColorType.NONE = "none"; + +/** + * @class RGBColor + * Stores an RGB color with red, green, blue, and alpha values. + * All values are in the range [0.0 to 255.0]. Invalid numeric values are + * converted to numbers within this range. + * + * @param red The red value, in the range [0.0 to 255.0]. + * @param green The green value, in the range [0.0 to 255.0]. + * @param blue The blue value, in the range [0.0 to 255.0]. + * @param alpha The alpha (transparency) value, in the range [0.0 to 255.0]. + * The default, 255.0, means that the color is fully opaque. + * + * @return A new RGBColor object. + */ +function RGBColor(red, green, blue, alpha) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; +} + +/** + * @class Direction + * A point value in which the y component is 0 and the x component + * is positive or negative for a right or left direction, + * or the x component is 0 and the y component is positive or negative for + * an up or down direction. + * + * @param x The horizontal component of the point. + * @param y The vertical component of the point. + * + * @return A new \c Direction object. + */ +function Direction(x, y) { + this.x = x; + this.y = y; +} + +/** + * @class GradientStop + * Stores gradient stop information. + * + * @param offset The offset of the gradient stop, in the range [0.0 to 1.0]. + * @param rgbColor The color of the gradient at this point, an \c #RGBColor object. + * + * @return GradientStop object. + */ +function GradientStop(offset, rgbColor) { + this.offset = offset; + this.rgbColor = rgbColor; +} + +/** + * @class GradientColor + * Stores gradient color information. + * + * @param type The gradient type, must be "linear". + * @param direction A \c #Direction object for the direction of the gradient + (up, down, right, or left). + * @param numStops The number of stops in the gradient. + * @param gradientStopList An array of \c #GradientStop objects. + * + * @return A new \c GradientColor object. + */ +function GradientColor(type, direction, numStops, arrGradientStop) { + this.type = type; + this.direction = direction; + this.numStops = numStops; + this.arrGradientStop = arrGradientStop; +} + +/** + * @class UIColor + * Stores color information, including the type, anti-alias level, and specific color + * values in a color object of an appropriate type. + * + * @param type The color type, 1 for "rgb" and 2 for "gradient". + The supplied color object must correspond to this type. + * @param antialiasLevel The anti-alias level constant. + * @param color A \c #RGBColor or \c #GradientColor object containing specific color information. + * + * @return A new \c UIColor object. + */ +function UIColor(type, antialiasLevel, color) { + this.type = type; + this.antialiasLevel = antialiasLevel; + this.color = color; +} + +/** + * @class AppSkinInfo + * Stores window-skin properties, such as color and font. All color parameter values are \c #UIColor objects except that systemHighlightColor is \c #RGBColor object. + * + * @param baseFontFamily The base font family of the application. + * @param baseFontSize The base font size of the application. + * @param appBarBackgroundColor The application bar background color. + * @param panelBackgroundColor The background color of the extension panel. + * @param appBarBackgroundColorSRGB The application bar background color, as sRGB. + * @param panelBackgroundColorSRGB The background color of the extension panel, as sRGB. + * @param systemHighlightColor The highlight color of the extension panel, if provided by the host application. Otherwise, the operating-system highlight color. + * + * @return AppSkinInfo object. + */ +function AppSkinInfo( + baseFontFamily, + baseFontSize, + appBarBackgroundColor, + panelBackgroundColor, + appBarBackgroundColorSRGB, + panelBackgroundColorSRGB, + systemHighlightColor +) { + this.baseFontFamily = baseFontFamily; + this.baseFontSize = baseFontSize; + this.appBarBackgroundColor = appBarBackgroundColor; + this.panelBackgroundColor = panelBackgroundColor; + this.appBarBackgroundColorSRGB = appBarBackgroundColorSRGB; + this.panelBackgroundColorSRGB = panelBackgroundColorSRGB; + this.systemHighlightColor = systemHighlightColor; +} + +/** + * @class HostEnvironment + * Stores information about the environment in which the extension is loaded. + * + * @param appName The application's name. + * @param appVersion The application's version. + * @param appLocale The application's current license locale. + * @param appUILocale The application's current UI locale. + * @param appId The application's unique identifier. + * @param isAppOnline True if the application is currently online. + * @param appSkinInfo An \c #AppSkinInfo object containing the application's default color and font styles. + * + * @return A new \c HostEnvironment object. + */ +function HostEnvironment( + appName, + appVersion, + appLocale, + appUILocale, + appId, + isAppOnline, + appSkinInfo +) { + this.appName = appName; + this.appVersion = appVersion; + this.appLocale = appLocale; + this.appUILocale = appUILocale; + this.appId = appId; + this.isAppOnline = isAppOnline; + this.appSkinInfo = appSkinInfo; +} + +/** + * @class HostCapabilities + * Stores information about the host capabilities. + * + * @param EXTENDED_PANEL_MENU True if the application supports panel menu. + * @param EXTENDED_PANEL_ICONS True if the application supports panel icon. + * @param DELEGATE_APE_ENGINE True if the application supports delegated APE engine. + * @param SUPPORT_HTML_EXTENSIONS True if the application supports HTML extensions. + * @param DISABLE_FLASH_EXTENSIONS True if the application disables FLASH extensions. + * + * @return A new \c HostCapabilities object. + */ +function HostCapabilities( + EXTENDED_PANEL_MENU, + EXTENDED_PANEL_ICONS, + DELEGATE_APE_ENGINE, + SUPPORT_HTML_EXTENSIONS, + DISABLE_FLASH_EXTENSIONS +) { + this.EXTENDED_PANEL_MENU = EXTENDED_PANEL_MENU; + this.EXTENDED_PANEL_ICONS = EXTENDED_PANEL_ICONS; + this.DELEGATE_APE_ENGINE = DELEGATE_APE_ENGINE; + this.SUPPORT_HTML_EXTENSIONS = SUPPORT_HTML_EXTENSIONS; + this.DISABLE_FLASH_EXTENSIONS = DISABLE_FLASH_EXTENSIONS; // Since 5.0.0 +} + +/** + * @class ApiVersion + * Stores current api version. + * + * Since 4.2.0 + * + * @param major The major version + * @param minor The minor version. + * @param micro The micro version. + * + * @return ApiVersion object. + */ +function ApiVersion(major, minor, micro) { + this.major = major; + this.minor = minor; + this.micro = micro; +} + +/** + * @class MenuItemStatus + * Stores flyout menu item status + * + * Since 5.2.0 + * + * @param menuItemLabel The menu item label. + * @param enabled True if user wants to enable the menu item. + * @param checked True if user wants to check the menu item. + * + * @return MenuItemStatus object. + */ +function MenuItemStatus(menuItemLabel, enabled, checked) { + this.menuItemLabel = menuItemLabel; + this.enabled = enabled; + this.checked = checked; +} + +/** + * @class ContextMenuItemStatus + * Stores the status of the context menu item. + * + * Since 5.2.0 + * + * @param menuItemID The menu item id. + * @param enabled True if user wants to enable the menu item. + * @param checked True if user wants to check the menu item. + * + * @return MenuItemStatus object. + */ +function ContextMenuItemStatus(menuItemID, enabled, checked) { + this.menuItemID = menuItemID; + this.enabled = enabled; + this.checked = checked; +} +//------------------------------ CSInterface ---------------------------------- + +/** + * @class CSInterface + * This is the entry point to the CEP extensibility infrastructure. + * Instantiate this object and use it to: + *
    + *
  • Access information about the host application in which an extension is running
  • + *
  • Launch an extension
  • + *
  • Register interest in event notifications, and dispatch events
  • + *
+ * + * @return A new \c CSInterface object + */ +function CSInterface() {} + +/** + * User can add this event listener to handle native application theme color changes. + * Callback function gives extensions ability to fine-tune their theme color after the + * global theme color has been changed. + * The callback function should be like below: + * + * @example + * // event is a CSEvent object, but user can ignore it. + * function OnAppThemeColorChanged(event) + * { + * // Should get a latest HostEnvironment object from application. + * var skinInfo = JSON.parse(window.__adobe_cep__.getHostEnvironment()).appSkinInfo; + * // Gets the style information such as color info from the skinInfo, + * // and redraw all UI controls of your extension according to the style info. + * } + */ +CSInterface.THEME_COLOR_CHANGED_EVENT = + "com.adobe.csxs.events.ThemeColorChanged"; + +/** The host environment data object. */ +CSInterface.prototype.hostEnvironment = window.__adobe_cep__ + ? JSON.parse(window.__adobe_cep__.getHostEnvironment()) + : null; + +/** Retrieves information about the host environment in which the + * extension is currently running. + * + * @return A \c #HostEnvironment object. + */ +CSInterface.prototype.getHostEnvironment = function () { + this.hostEnvironment = JSON.parse(window.__adobe_cep__.getHostEnvironment()); + return this.hostEnvironment; +}; + +/** Loads binary file created which is located at url asynchronously + * + *@param urlName url at which binary file is located. Local files should start with 'file://' + *@param callback Optional. A callback function that returns after binary is loaded + *@example + * To create JS binary use command ./cep_compiler test.js test.bin + * To load JS binary asyncronously + * var CSLib = new CSInterface(); + * CSLib.loadBinAsync(url, function () { }); + */ +CSInterface.prototype.loadBinAsync = function (urlName, callback) { + try { + var xhr = new XMLHttpRequest(); + xhr.responseType = "arraybuffer"; // make response as ArrayBuffer + xhr.open("GET", urlName, true); + xhr.onerror = function () { + console.log("Unable to load snapshot from given URL"); + return false; + }; + xhr.send(); + xhr.onload = () => { + window.__adobe_cep__.loadSnapshot(xhr.response); + if (typeof callback === "function") { + callback(); + } else if (typeof callback !== "undefined") { + console.log("Provided callback is not a function"); + } + }; + } catch (err) { + console.log(err); + return false; + } + + return true; +}; + +/** Loads binary file created synchronously + * + *@param pathName the local path at which binary file is located + *@example + * To create JS binary use command ./cep_compiler test.js test.bin + * To load JS binary syncronously + * var CSLib = new CSInterface(); + * CSLib.loadBinSync(path); + */ +CSInterface.prototype.loadBinSync = function (pathName) { + try { + var OSVersion = this.getOSInformation(); + if (pathName.startsWith("file://")) { + if (OSVersion.indexOf("Windows") >= 0) { + pathName = pathName.replace("file:///", ""); + } else if (OSVersion.indexOf("Mac") >= 0) { + pathName = pathName.replace("file://", ""); + } + window.__adobe_cep__.loadSnapshot(pathName); + return true; + } + } catch (err) { + console.log(err); + return false; + } + //control should not come here + return false; +}; + +/** Closes this extension. */ +CSInterface.prototype.closeExtension = function () { + window.__adobe_cep__.closeExtension(); +}; + +/** + * Retrieves a path for which a constant is defined in the system. + * + * @param pathType The path-type constant defined in \c #SystemPath , + * + * @return The platform-specific system path string. + */ +CSInterface.prototype.getSystemPath = function (pathType) { + var path = decodeURI(window.__adobe_cep__.getSystemPath(pathType)); + var OSVersion = this.getOSInformation(); + if (OSVersion.indexOf("Windows") >= 0) { + path = path.replace("file:///", ""); + } else if (OSVersion.indexOf("Mac") >= 0) { + path = path.replace("file://", ""); + } + return path; +}; + +/** + * Evaluates a JavaScript script, which can use the JavaScript DOM + * of the host application. + * + * @param script The JavaScript script. + * @param callback Optional. A callback function that receives the result of execution. + * If execution fails, the callback function receives the error message \c EvalScript_ErrMessage. + */ +CSInterface.prototype.evalScript = function (script, callback) { + if (callback === null || callback === undefined) { + callback = function (result) {}; + } + window.__adobe_cep__.evalScript(script, callback); +}; + +/** + * Retrieves the unique identifier of the application. + * in which the extension is currently running. + * + * @return The unique ID string. + */ +CSInterface.prototype.getApplicationID = function () { + var appId = this.hostEnvironment.appId; + return appId; +}; + +/** + * Retrieves host capability information for the application + * in which the extension is currently running. + * + * @return A \c #HostCapabilities object. + */ +CSInterface.prototype.getHostCapabilities = function () { + var hostCapabilities = JSON.parse(window.__adobe_cep__.getHostCapabilities()); + return hostCapabilities; +}; + +/** + * Triggers a CEP event programmatically. Yoy can use it to dispatch + * an event of a predefined type, or of a type you have defined. + * + * @param event A \c CSEvent object. + */ +CSInterface.prototype.dispatchEvent = function (event) { + if (typeof event.data == "object") { + event.data = JSON.stringify(event.data); + } + + window.__adobe_cep__.dispatchEvent(event); +}; + +/** + * Registers an interest in a CEP event of a particular type, and + * assigns an event handler. + * The event infrastructure notifies your extension when events of this type occur, + * passing the event object to the registered handler function. + * + * @param type The name of the event type of interest. + * @param listener The JavaScript handler function or method. + * @param obj Optional, the object containing the handler method, if any. + * Default is null. + */ +CSInterface.prototype.addEventListener = function (type, listener, obj) { + window.__adobe_cep__.addEventListener(type, listener, obj); +}; + +/** + * Removes a registered event listener. + * + * @param type The name of the event type of interest. + * @param listener The JavaScript handler function or method that was registered. + * @param obj Optional, the object containing the handler method, if any. + * Default is null. + */ +CSInterface.prototype.removeEventListener = function (type, listener, obj) { + window.__adobe_cep__.removeEventListener(type, listener, obj); +}; + +/** + * Loads and launches another extension, or activates the extension if it is already loaded. + * + * @param extensionId The extension's unique identifier. + * @param startupParams Not currently used, pass "". + * + * @example + * To launch the extension "help" with ID "HLP" from this extension, call: + * requestOpenExtension("HLP", ""); + * + */ +CSInterface.prototype.requestOpenExtension = function (extensionId, params) { + window.__adobe_cep__.requestOpenExtension(extensionId, params); +}; + +/** + * Retrieves the list of extensions currently loaded in the current host application. + * The extension list is initialized once, and remains the same during the lifetime + * of the CEP session. + * + * @param extensionIds Optional, an array of unique identifiers for extensions of interest. + * If omitted, retrieves data for all extensions. + * + * @return Zero or more \c #Extension objects. + */ +CSInterface.prototype.getExtensions = function (extensionIds) { + var extensionIdsStr = JSON.stringify(extensionIds); + var extensionsStr = window.__adobe_cep__.getExtensions(extensionIdsStr); + + var extensions = JSON.parse(extensionsStr); + return extensions; +}; + +/** + * Retrieves network-related preferences. + * + * @return A JavaScript object containing network preferences. + */ +CSInterface.prototype.getNetworkPreferences = function () { + var result = window.__adobe_cep__.getNetworkPreferences(); + var networkPre = JSON.parse(result); + + return networkPre; +}; + +/** + * Initializes the resource bundle for this extension with property values + * for the current application and locale. + * To support multiple locales, you must define a property file for each locale, + * containing keyed display-string values for that locale. + * See localization documentation for Extension Builder and related products. + * + * Keys can be in the + * form key.value="localized string", for use in HTML text elements. + * For example, in this input element, the localized \c key.value string is displayed + * instead of the empty \c value string: + * + * + * + * @return An object containing the resource bundle information. + */ +CSInterface.prototype.initResourceBundle = function () { + var resourceBundle = JSON.parse(window.__adobe_cep__.initResourceBundle()); + var resElms = document.querySelectorAll("[data-locale]"); + for (var n = 0; n < resElms.length; n++) { + var resEl = resElms[n]; + // Get the resource key from the element. + var resKey = resEl.getAttribute("data-locale"); + if (resKey) { + // Get all the resources that start with the key. + for (var key in resourceBundle) { + if (key.indexOf(resKey) === 0) { + var resValue = resourceBundle[key]; + if (key.length == resKey.length) { + resEl.innerHTML = resValue; + } else if ("." == key.charAt(resKey.length)) { + var attrKey = key.substring(resKey.length + 1); + resEl[attrKey] = resValue; + } + } + } + } + } + return resourceBundle; +}; + +/** + * Writes installation information to a file. + * + * @return The file path. + */ +CSInterface.prototype.dumpInstallationInfo = function () { + return window.__adobe_cep__.dumpInstallationInfo(); +}; + +/** + * Retrieves version information for the current Operating System, + * See http://www.useragentstring.com/pages/Chrome/ for Chrome \c navigator.userAgent values. + * + * @return A string containing the OS version, or "unknown Operation System". + * If user customizes the User Agent by setting CEF command parameter "--user-agent", only + * "Mac OS X" or "Windows" will be returned. + */ +CSInterface.prototype.getOSInformation = function () { + var userAgent = navigator.userAgent; + + if (navigator.platform == "Win32" || navigator.platform == "Windows") { + var winVersion = "Windows"; + var winBit = ""; + if (userAgent.indexOf("Windows") > -1) { + if (userAgent.indexOf("Windows NT 5.0") > -1) { + winVersion = "Windows 2000"; + } else if (userAgent.indexOf("Windows NT 5.1") > -1) { + winVersion = "Windows XP"; + } else if (userAgent.indexOf("Windows NT 5.2") > -1) { + winVersion = "Windows Server 2003"; + } else if (userAgent.indexOf("Windows NT 6.0") > -1) { + winVersion = "Windows Vista"; + } else if (userAgent.indexOf("Windows NT 6.1") > -1) { + winVersion = "Windows 7"; + } else if (userAgent.indexOf("Windows NT 6.2") > -1) { + winVersion = "Windows 8"; + } else if (userAgent.indexOf("Windows NT 6.3") > -1) { + winVersion = "Windows 8.1"; + } else if (userAgent.indexOf("Windows NT 10") > -1) { + winVersion = "Windows 10"; + } + + if (userAgent.indexOf("WOW64") > -1 || userAgent.indexOf("Win64") > -1) { + winBit = " 64-bit"; + } else { + winBit = " 32-bit"; + } + } + + return winVersion + winBit; + } else if ( + navigator.platform == "MacIntel" || + navigator.platform == "Macintosh" + ) { + var result = "Mac OS X"; + + if (userAgent.indexOf("Mac OS X") > -1) { + result = userAgent.substring( + userAgent.indexOf("Mac OS X"), + userAgent.indexOf(")") + ); + result = result.replace(/_/g, "."); + } + + return result; + } + + return "Unknown Operation System"; +}; + +/** + * Opens a page in the default system browser. + * + * Since 4.2.0 + * + * @param url The URL of the page/file to open, or the email address. + * Must use HTTP/HTTPS/file/mailto protocol. For example: + * "http://www.adobe.com" + * "https://github.com" + * "file:///C:/log.txt" + * "mailto:test@adobe.com" + * + * @return One of these error codes:\n + *
    \n + *
  • NO_ERROR - 0
  • \n + *
  • ERR_UNKNOWN - 1
  • \n + *
  • ERR_INVALID_PARAMS - 2
  • \n + *
  • ERR_INVALID_URL - 201
  • \n + *
\n + */ +CSInterface.prototype.openURLInDefaultBrowser = function (url) { + return cep.util.openURLInDefaultBrowser(url); +}; + +/** + * Retrieves extension ID. + * + * Since 4.2.0 + * + * @return extension ID. + */ +CSInterface.prototype.getExtensionID = function () { + return window.__adobe_cep__.getExtensionId(); +}; + +/** + * Retrieves the scale factor of screen. + * On Windows platform, the value of scale factor might be different from operating system's scale factor, + * since host application may use its self-defined scale factor. + * + * Since 4.2.0 + * + * @return One of the following float number. + *
    \n + *
  • -1.0 when error occurs
  • \n + *
  • 1.0 means normal screen
  • \n + *
  • >1.0 means HiDPI screen
  • \n + *
\n + */ +CSInterface.prototype.getScaleFactor = function () { + return window.__adobe_cep__.getScaleFactor(); +}; + +/** + * Retrieves the scale factor of Monitor. + * + * Since 8.5.0 + * + * @return value >= 1.0f + * only available for windows machine + */ +if (navigator.appVersion.toLowerCase().indexOf("windows") >= 0) { + CSInterface.prototype.getMonitorScaleFactor = function () { + return window.__adobe_cep__.getMonitorScaleFactor(); + }; +} + +/** + * Set a handler to detect any changes of scale factor. This only works on Mac. + * + * Since 4.2.0 + * + * @param handler The function to be called when scale factor is changed. + * + */ +CSInterface.prototype.setScaleFactorChangedHandler = function (handler) { + window.__adobe_cep__.setScaleFactorChangedHandler(handler); +}; + +/** + * Retrieves current API version. + * + * Since 4.2.0 + * + * @return ApiVersion object. + * + */ +CSInterface.prototype.getCurrentApiVersion = function () { + var apiVersion = JSON.parse(window.__adobe_cep__.getCurrentApiVersion()); + return apiVersion; +}; + +/** + * Set panel flyout menu by an XML. + * + * Since 5.2.0 + * + * Register a callback function for "com.adobe.csxs.events.flyoutMenuClicked" to get notified when a + * menu item is clicked. + * The "data" attribute of event is an object which contains "menuId" and "menuName" attributes. + * + * Register callback functions for "com.adobe.csxs.events.flyoutMenuOpened" and "com.adobe.csxs.events.flyoutMenuClosed" + * respectively to get notified when flyout menu is opened or closed. + * + * @param menu A XML string which describes menu structure. + * An example menu XML: + * + * + * + * + * + * + * + * + * + * + * + * + */ +CSInterface.prototype.setPanelFlyoutMenu = function (menu) { + if ("string" != typeof menu) { + return; + } + + window.__adobe_cep__.invokeSync("setPanelFlyoutMenu", menu); +}; + +/** + * Updates a menu item in the extension window's flyout menu, by setting the enabled + * and selection status. + * + * Since 5.2.0 + * + * @param menuItemLabel The menu item label. + * @param enabled True to enable the item, false to disable it (gray it out). + * @param checked True to select the item, false to deselect it. + * + * @return false when the host application does not support this functionality (HostCapabilities.EXTENDED_PANEL_MENU is false). + * Fails silently if menu label is invalid. + * + * @see HostCapabilities.EXTENDED_PANEL_MENU + */ +CSInterface.prototype.updatePanelMenuItem = function ( + menuItemLabel, + enabled, + checked +) { + var ret = false; + if (this.getHostCapabilities().EXTENDED_PANEL_MENU) { + var itemStatus = new MenuItemStatus(menuItemLabel, enabled, checked); + ret = window.__adobe_cep__.invokeSync( + "updatePanelMenuItem", + JSON.stringify(itemStatus) + ); + } + return ret; +}; + +/** + * Set context menu by XML string. + * + * Since 5.2.0 + * + * There are a number of conventions used to communicate what type of menu item to create and how it should be handled. + * - an item without menu ID or menu name is disabled and is not shown. + * - if the item name is "---" (three hyphens) then it is treated as a separator. The menu ID in this case will always be NULL. + * - Checkable attribute takes precedence over Checked attribute. + * - a PNG icon. For optimal display results please supply a 16 x 16px icon as larger dimensions will increase the size of the menu item. + The Chrome extension contextMenus API was taken as a reference. + https://developer.chrome.com/extensions/contextMenus + * - the items with icons and checkable items cannot coexist on the same menu level. The former take precedences over the latter. + * + * @param menu A XML string which describes menu structure. + * @param callback The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. + * + * @description An example menu XML: + * + * + * + * + * + * + * + * + * + * + * + */ +CSInterface.prototype.setContextMenu = function (menu, callback) { + if ("string" != typeof menu) { + return; + } + + window.__adobe_cep__.invokeAsync("setContextMenu", menu, callback); +}; + +/** + * Set context menu by JSON string. + * + * Since 6.0.0 + * + * There are a number of conventions used to communicate what type of menu item to create and how it should be handled. + * - an item without menu ID or menu name is disabled and is not shown. + * - if the item label is "---" (three hyphens) then it is treated as a separator. The menu ID in this case will always be NULL. + * - Checkable attribute takes precedence over Checked attribute. + * - a PNG icon. For optimal display results please supply a 16 x 16px icon as larger dimensions will increase the size of the menu item. + The Chrome extension contextMenus API was taken as a reference. + * - the items with icons and checkable items cannot coexist on the same menu level. The former take precedences over the latter. + https://developer.chrome.com/extensions/contextMenus + * + * @param menu A JSON string which describes menu structure. + * @param callback The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. + * + * @description An example menu JSON: + * + * { + * "menu": [ + * { + * "id": "menuItemId1", + * "label": "testExample1", + * "enabled": true, + * "checkable": true, + * "checked": false, + * "icon": "./image/small_16X16.png" + * }, + * { + * "id": "menuItemId2", + * "label": "testExample2", + * "menu": [ + * { + * "id": "menuItemId2-1", + * "label": "testExample2-1", + * "menu": [ + * { + * "id": "menuItemId2-1-1", + * "label": "testExample2-1-1", + * "enabled": false, + * "checkable": true, + * "checked": true + * } + * ] + * }, + * { + * "id": "menuItemId2-2", + * "label": "testExample2-2", + * "enabled": true, + * "checkable": true, + * "checked": true + * } + * ] + * }, + * { + * "label": "---" + * }, + * { + * "id": "menuItemId3", + * "label": "testExample3", + * "enabled": false, + * "checkable": true, + * "checked": false + * } + * ] + * } + * + */ +CSInterface.prototype.setContextMenuByJSON = function (menu, callback) { + if ("string" != typeof menu) { + return; + } + + window.__adobe_cep__.invokeAsync("setContextMenuByJSON", menu, callback); +}; + +/** + * Updates a context menu item by setting the enabled and selection status. + * + * Since 5.2.0 + * + * @param menuItemID The menu item ID. + * @param enabled True to enable the item, false to disable it (gray it out). + * @param checked True to select the item, false to deselect it. + */ +CSInterface.prototype.updateContextMenuItem = function ( + menuItemID, + enabled, + checked +) { + var itemStatus = new ContextMenuItemStatus(menuItemID, enabled, checked); + ret = window.__adobe_cep__.invokeSync( + "updateContextMenuItem", + JSON.stringify(itemStatus) + ); +}; + +/** + * Get the visibility status of an extension window. + * + * Since 6.0.0 + * + * @return true if the extension window is visible; false if the extension window is hidden. + */ +CSInterface.prototype.isWindowVisible = function () { + return window.__adobe_cep__.invokeSync("isWindowVisible", ""); +}; + +/** + * Resize extension's content to the specified dimensions. + * 1. Works with modal and modeless extensions in all Adobe products. + * 2. Extension's manifest min/max size constraints apply and take precedence. + * 3. For panel extensions + * 3.1 This works in all Adobe products except: + * * Premiere Pro + * * Prelude + * * After Effects + * 3.2 When the panel is in certain states (especially when being docked), + * it will not change to the desired dimensions even when the + * specified size satisfies min/max constraints. + * + * Since 6.0.0 + * + * @param width The new width + * @param height The new height + */ +CSInterface.prototype.resizeContent = function (width, height) { + window.__adobe_cep__.resizeContent(width, height); +}; + +/** + * Register the invalid certificate callback for an extension. + * This callback will be triggered when the extension tries to access the web site that contains the invalid certificate on the main frame. + * But if the extension does not call this function and tries to access the web site containing the invalid certificate, a default error page will be shown. + * + * Since 6.1.0 + * + * @param callback the callback function + */ +CSInterface.prototype.registerInvalidCertificateCallback = function (callback) { + return window.__adobe_cep__.registerInvalidCertificateCallback(callback); +}; + +/** + * Register an interest in some key events to prevent them from being sent to the host application. + * + * This function works with modeless extensions and panel extensions. + * Generally all the key events will be sent to the host application for these two extensions if the current focused element + * is not text input or dropdown, + * If you want to intercept some key events and want them to be handled in the extension, please call this function + * in advance to prevent them being sent to the host application. + * + * Since 6.1.0 + * + * @param keyEventsInterest A JSON string describing those key events you are interested in. A null object or + an empty string will lead to removing the interest + * + * This JSON string should be an array, each object has following keys: + * + * keyCode: [Required] represents an OS system dependent virtual key code identifying + * the unmodified value of the pressed key. + * ctrlKey: [optional] a Boolean that indicates if the control key was pressed (true) or not (false) when the event occurred. + * altKey: [optional] a Boolean that indicates if the alt key was pressed (true) or not (false) when the event occurred. + * shiftKey: [optional] a Boolean that indicates if the shift key was pressed (true) or not (false) when the event occurred. + * metaKey: [optional] (Mac Only) a Boolean that indicates if the Meta key was pressed (true) or not (false) when the event occurred. + * On Macintosh keyboards, this is the command key. To detect Windows key on Windows, please use keyCode instead. + * An example JSON string: + * + * [ + * { + * "keyCode": 48 + * }, + * { + * "keyCode": 123, + * "ctrlKey": true + * }, + * { + * "keyCode": 123, + * "ctrlKey": true, + * "metaKey": true + * } + * ] + * + */ +CSInterface.prototype.registerKeyEventsInterest = function (keyEventsInterest) { + return window.__adobe_cep__.registerKeyEventsInterest(keyEventsInterest); +}; + +/** + * Set the title of the extension window. + * This function works with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Flash Pro and Dreamweaver. + * + * Since 6.1.0 + * + * @param title The window title. + */ +CSInterface.prototype.setWindowTitle = function (title) { + window.__adobe_cep__.invokeSync("setWindowTitle", title); +}; + +/** + * Get the title of the extension window. + * This function works with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Flash Pro and Dreamweaver. + * + * Since 6.1.0 + * + * @return The window title. + */ +CSInterface.prototype.getWindowTitle = function () { + return window.__adobe_cep__.invokeSync("getWindowTitle", ""); +}; + +// Boilerplate Added Export +export default CSInterface; +export { + CSXSWindowType, + Version, + VersionBound, + VersionRange, + Runtime, + Extension, + CSEvent, + SystemPath, + ColorType, + RGBColor, + Direction, + GradientStop, + GradientColor, + UIColor, + AppSkinInfo, + HostEnvironment, + HostCapabilities, + ApiVersion, + MenuItemStatus, + ContextMenuItemStatus, + CSInterface, +}; diff --git a/AdminPanel/plugins/utils/cep/csinterfaceEx.ts b/AdminPanel/plugins/utils/cep/csinterfaceEx.ts new file mode 100644 index 0000000..346fa36 --- /dev/null +++ b/AdminPanel/plugins/utils/cep/csinterfaceEx.ts @@ -0,0 +1,30 @@ +import CSInterface, { CSEvent } from "./csinterface"; +/** + * 扩展PS的CSInterface类 + */ +export class CSInterfaceEx { + constructor() { + + } + + /**持久化运行 */ + public persistent() { + var cs = new CSInterface(); + var event1 = new CSEvent(); + event1.type = "com.adobe.PhotoshopPersistent"; + event1.scope = "APPLICATION"; + event1.extensionId = cs.getExtensionID(); + cs.dispatchEvent(event1); + } + + /**取消持久化运行 */ + public unPersisten() { + var cs = new CSInterface(); + var event1 = new CSEvent(); + event1.type = "com.adobe.PhotoshopUnPersistent"; + event1.scope = "APPLICATION"; + event1.extensionId = cs.getExtensionID(); + cs.dispatchEvent(event1); + } +} + diff --git a/AdminPanel/plugins/utils/cep/es-types/index.ts b/AdminPanel/plugins/utils/cep/es-types/index.ts new file mode 100644 index 0000000..11be5af --- /dev/null +++ b/AdminPanel/plugins/utils/cep/es-types/index.ts @@ -0,0 +1,3 @@ +export type Scripts = { + [key: string]: (a: any, ...ags: any) => any; +}; diff --git a/AdminPanel/plugins/utils/cep/index.ts b/AdminPanel/plugins/utils/cep/index.ts new file mode 100644 index 0000000..db504fd --- /dev/null +++ b/AdminPanel/plugins/utils/cep/index.ts @@ -0,0 +1,64 @@ +import CSInterface from "./csinterface" + +export function initJsx(path: string) { + console.log('[cep] init jsx', path); + const cs = new CSInterface() + + cs.evalScript(`$.evalFile("${path}")`, (e) => { + if (e === 'undefined') return console.log('init json success'); + console.warn('load jsx', e); + }) +} + +type JsxTypeof = typeof import('../../../src/jsx/index') +type MethodName = keyof JsxTypeof +export function evalJSX(functionName: T, ...args: Parameters) { + return new Promise>((resolve, reject) => { + const formattedArgs = args + .map((arg) => { + console.log(JSON.stringify(arg)); + return `${JSON.stringify(arg)}`; + }) + .join(","); + + const cs = new CSInterface() + cs.evalScript( + `try{ + var res = ${functionName}(${formattedArgs}); + JSON.stringify(res) + }catch(e){ + alert(e); + e.fileName =new File(e.fileName).fsName; + JSON.stringify(e) + }`, (e) => { + console.log('evalJSX', e); + if (e === 'undefined') return resolve(null) + try { + let parsed = JSON.parse(e); + if (parsed.name === "ReferenceError") { + console.error("REFERENCE ERROR"); + reject(parsed); + } else { + resolve(parsed); + } + } catch (error) { + reject(error) + } + }) + }) +} + +export function evalFile(path: string) { + return new Promise((resolve, reject) => { + const cs = new CSInterface() + cs.evalScript(`$.evalFile("${path}")`, (e) => { + if (e === 'undefined') return resolve(null) + // alert(e) + console.warn('evalFileError: ' + path, e); + reject(e) + }) + }) +} + +export { CSInterface } +export { CSInterfaceEx } from "./csinterfaceEx" \ No newline at end of file diff --git a/AdminPanel/plugins/utils/cep/node.ts b/AdminPanel/plugins/utils/cep/node.ts new file mode 100644 index 0000000..98a21fe --- /dev/null +++ b/AdminPanel/plugins/utils/cep/node.ts @@ -0,0 +1,87 @@ +// Abstracted built-in Node.js Modules + +//@ts-ignore +export const crypto = ( + typeof window.cep !== "undefined" ? require("crypto") : {} +) as typeof import("crypto"); +export const assert = ( + typeof window.cep !== "undefined" ? require("assert") : {} +) as typeof import("assert"); +export const buffer = ( + typeof window.cep !== "undefined" ? require("buffer") : {} +) as typeof import("buffer"); +export const child_process = ( + typeof window.cep !== "undefined" ? require("child_process") : {} +) as typeof import("child_process"); +export const cluster = ( + typeof window.cep !== "undefined" ? require("cluster") : {} +) as typeof import("cluster"); +export const dgram = ( + typeof window.cep !== "undefined" ? require("dgram") : {} +) as typeof import("dgram"); +export const dns = ( + typeof window.cep !== "undefined" ? require("dns") : {} +) as typeof import("dns"); +export const domain = ( + typeof window.cep !== "undefined" ? require("domain") : {} +) as typeof import("domain"); +export const events = ( + typeof window.cep !== "undefined" ? require("events") : {} +) as typeof import("events"); +export const fs = ( + typeof window.cep !== "undefined" ? require("fs") : {} +) as typeof import("fs"); +export const http = ( + typeof window.cep !== "undefined" ? require("http") : {} +) as typeof import("http"); +export const https = ( + typeof window.cep !== "undefined" ? require("https") : {} +) as typeof import("https"); +export const net = ( + typeof window.cep !== "undefined" ? require("net") : {} +) as typeof import("net"); +export const os = ( + typeof window.cep !== "undefined" ? require("os") : {} +) as typeof import("os"); +export const path = ( + typeof window.cep !== "undefined" ? require("path") : {} +) as typeof import("path"); +export const punycode = ( + typeof window.cep !== "undefined" ? require("punycode") : {} +) as typeof import("punycode"); +export const querystring = ( + typeof window.cep !== "undefined" ? require("querystring") : {} +) as typeof import("querystring"); +export const readline = ( + typeof window.cep !== "undefined" ? require("readline") : {} +) as typeof import("readline"); +export const stream = ( + typeof window.cep !== "undefined" ? require("stream") : {} +) as typeof import("stream"); +export const string_decoder = ( + typeof window.cep !== "undefined" ? require("string_decoder") : {} +) as typeof import("string_decoder"); +export const timers = ( + typeof window.cep !== "undefined" ? require("timers") : {} +) as typeof import("timers"); +export const tls = ( + typeof window.cep !== "undefined" ? require("tls") : {} +) as typeof import("tls"); +export const tty = ( + typeof window.cep !== "undefined" ? require("tty") : {} +) as typeof import("tty"); +export const url = ( + typeof window.cep !== "undefined" ? require("url") : {} +) as typeof import("url"); +export const util = ( + typeof window.cep !== "undefined" ? require("util") : {} +) as typeof import("util"); +export const v8 = ( + typeof window.cep !== "undefined" ? require("v8") : {} +) as typeof import("v8"); +export const vm = ( + typeof window.cep !== "undefined" ? require("vm") : {} +) as typeof import("vm"); +export const zlib = ( + typeof window.cep !== "undefined" ? require("zlib") : {} +) as typeof import("zlib"); diff --git a/AdminPanel/plugins/utils/cep/vulcan.d.ts b/AdminPanel/plugins/utils/cep/vulcan.d.ts new file mode 100644 index 0000000..fa2195f --- /dev/null +++ b/AdminPanel/plugins/utils/cep/vulcan.d.ts @@ -0,0 +1,265 @@ +/** + * Vulcan + +The singleton instance, VulcanInterface, provides an interface +to the Vulcan. Allows you to launch CC applications +and discover information about them. + */ +export default class Vulcan { + constructor(); + + /** + * Gets all available application SAPCode-Specifiers on the local machine. + * + * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. + * Changes : New getTargetSpecifiersEx returns productSAPCodeSpecifiers + * + * @return The array of all available application SAPCode-Specifiers. + */ + getTargetSpecifiersEx(): any; + + /** + * Launches a CC application on the local machine, if it is not already running. + * + * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. + * Changes : New launchAppEx uses productSAPCodeSpecifiers + * + * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. + * @param focus True to launch in foreground, or false to launch in the background. + * @param cmdLine Optional, command-line parameters to supply to the launch command. + * @return True if the app can be launched, false otherwise. + */ + launchAppEx( + productSAPCodeSpecifier: string, + focus: boolean, + cmdLine?: string, + ): boolean; + + /** + * Checks whether a CC application is running on the local machine. + * + * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. + * Changes : New isAppRunningEx uses productSAPCodeSpecifiers + * + * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. + * @return True if the app is running, false otherwise. + */ + isAppRunningEx(productSAPCodeSpecifier: string): boolean; + + /** + * Checks whether a CC application is installed on the local machine. + * + * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. + * Changes : New isAppInstalledEx uses productSAPCodeSpecifiers + * + * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. + * @return True if the app is installed, false otherwise. + */ + isAppInstalledEx(productSAPCodeSpecifier: string): any; + + /**s + * Retrieves the local install path of a CC application. + * + * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. + * Changes : New getAppPathEx uses productSAPCodeSpecifiers + * + * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. + * @return The path string if the application is found, "" otherwise. + */ + getAppPathEx(): any; + + // OLD FUNCTIONS + // OLD FUNCTIONS + // OLD FUNCTIONS + // OLD FUNCTIONS + + /** + * Gets all available application specifiers on the local machine. + * @returns The array of all available application specifiers. + */ + getTargetSpecifiers(): any; + /** + * Launches a CC application on the local machine, if it is not already running. + * @param targetSpecifier - The application specifier; for example "indesign". + + Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + receive wrong result. + The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + + In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @param focus - True to launch in foreground, or false to launch in the background. + * @param cmdLine - Optional, command-line parameters to supply to the launch command. + * @returns True if the app can be launched, false otherwise. + */ + launchApp(targetSpecifier: any, focus: any, cmdLine: any): any; + /** + * Checks whether a CC application is running on the local machine. + * @param targetSpecifier - The application specifier; for example "indesign". + + Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + receive wrong result. + The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + + In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @returns True if the app is running, false otherwise. + */ + isAppRunning(targetSpecifier: any): any; + /** + * Checks whether a CC application is installed on the local machine. + * @param targetSpecifier - The application specifier; for example "indesign". + + Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + receive wrong result. + The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + + In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @returns True if the app is installed, false otherwise. + */ + isAppInstalled(targetSpecifier: any): any; + /** + * Retrieves the local install path of a CC application. + * @param targetSpecifier - The application specifier; for example "indesign". + + Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + receive wrong result. + The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + + In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @returns The path string if the application is found, "" otherwise. + */ + getAppPath(targetSpecifier: any): any; + /** + * Registers a message listener callback function for a Vulcan message. + * @param type - The message type. + * @param callback - The callback function that handles the message. + Takes one argument, the message object. + * @param obj - Optional, the object containing the callback method, if any. + Default is null. + */ + addMessageListener(type: any, callback: any, obj: any): void; + /** + * Removes a registered message listener callback function for a Vulcan message. + * @param type - The message type. + * @param callback - The callback function that was registered. + Takes one argument, the message object. + * @param obj - Optional, the object containing the callback method, if any. + Default is null. + */ + removeMessageListener(type: any, callback: any, obj: any): void; + /** + * Dispatches a Vulcan message. + * @param vulcanMessage - The message object. + */ + dispatchMessage(vulcanMessage: any): void; + /** + * Retrieves the message payload of a Vulcan message for the registered message listener callback function. + * @param vulcanMessage - The message object. + * @returns A string containing the message payload. + */ + getPayload(vulcanMessage: any): any; + /** + * Gets all available endpoints of the running Vulcan-enabled applications. + + Since 7.0.0 + * @returns The array of all available endpoints. + An example endpoint string: + + PHXS + 16.1.0 + + */ + getEndPoints(): any; + /** + * Gets the endpoint for itself. + + Since 7.0.0 + * @returns The endpoint string for itself. + */ + getSelfEndPoint(): any; +} + +/** + * Singleton instance of Vulcan + */ +declare var VulcanInterface: any; + +/** + * VulcanMessage +Message type for sending messages between host applications. +A message of this type can be sent to the designated destination +when appId and appVersion are provided and valid. Otherwise, +the message is broadcast to all running Vulcan-enabled applications. + +To send a message between extensions running within one +application, use the CSEvent type in CSInterface.js. + * @param type - The message type. + * @param appId - The peer appId. + * @param appVersion - The peer appVersion. + */ +export declare class VulcanMessage { + static TYPE_PREFIX: string; + static SCOPE_SUITE: string; + static DEFAULT_APP_ID: string; + static DEFAULT_APP_VERSION: string; + static DEFAULT_DATA: string; + static dataTemplate: string; + static payloadTemplate: string; + constructor(type: any, appId: any, appVersion: any); + /** + * Initializes this message instance. + * @param message - A \c message instance to use for initialization. + */ + initialize(message: any): void; + /** + * Retrieves the message data. + * @returns A data string in XML format. + */ + xmlData(): any; + /** + * Sets the message payload of this message. + * @param payload - A string containing the message payload. + */ + setPayload(payload: any): void; + /** + * Retrieves the message payload of this message. + * @returns A string containing the message payload. + */ + getPayload(): any; + /** + * Converts the properties of this instance to a string. + * @returns The string version of this instance. + */ + toString(): any; +} + +/** + * Retrieves the content of an XML element. + * @param xmlStr - The XML string. + * @param key - The name of the tag. + * @returns The content of the tag, or the empty string + if such tag is not found or the tag has no content. + */ +declare function GetValueByKey(xmlStr: any, key: any): any; + +/** + * Reports whether required parameters are valid. + * @returns True if all required parameters are valid, + false if any of the required parameters are invalid. + */ +declare function requiredParamsValid(): any; + +/** + * Reports whether a string has a given prefix. + * @param str - The target string. + * @param prefix - The specific prefix string. + * @returns True if the string has the prefix, false if not. + */ +declare function strStartsWith(str: any, prefix: any): any; diff --git a/AdminPanel/plugins/utils/cep/vulcan.js b/AdminPanel/plugins/utils/cep/vulcan.js new file mode 100644 index 0000000..d1bb4c9 --- /dev/null +++ b/AdminPanel/plugins/utils/cep/vulcan.js @@ -0,0 +1,620 @@ +/************************************************************************************************** + * + * ADOBE SYSTEMS INCORPORATED + * Copyright 2020 Adobe Systems Incorporated + * All Rights Reserved. + * + * NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the + * terms of the Adobe license agreement accompanying it. If you have received this file from a + * source other than Adobe, then your use, modification, or distribution of it requires the prior + * written permission of Adobe. + * + **************************************************************************************************/ + +/** Vulcan - v11.2.0 */ + +/** + * @class Vulcan + * + * The singleton instance, VulcanInterface, provides an interface + * to the Vulcan. Allows you to launch CC applications + * and discover information about them. + */ +function Vulcan() {} + +/** + * Gets all available application SAPCode-Specifiers on the local machine. + * + * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. + * Changes : New getTargetSpecifiersEx returns productSAPCodeSpecifiers + * + * @return The array of all available application SAPCode-Specifiers. + */ +Vulcan.prototype.getTargetSpecifiersEx = function () { + var params = {}; + return JSON.parse( + window.__adobe_cep__.invokeSync( + "vulcanGetTargetSpecifiersEx", + JSON.stringify(params) + ) + ); +}; + +/** + * Launches a CC application on the local machine, if it is not already running. + * + * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. + * Changes : New launchAppEx uses productSAPCodeSpecifiers + * + * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. + * @param focus True to launch in foreground, or false to launch in the background. + * @param cmdLine Optional, command-line parameters to supply to the launch command. + * @return True if the app can be launched, false otherwise. + */ +Vulcan.prototype.launchAppEx = function ( + productSAPCodeSpecifier, + focus, + cmdLine +) { + if (!requiredParamsValid(productSAPCodeSpecifier)) { + return false; + } + + var params = {}; + params.productSAPCodeSpecifier = productSAPCodeSpecifier; + params.focus = focus ? "true" : "false"; + params.cmdLine = requiredParamsValid(cmdLine) ? cmdLine : ""; + + return JSON.parse( + window.__adobe_cep__.invokeSync("vulcanLaunchAppEx", JSON.stringify(params)) + ).result; +}; + +/** + * Checks whether a CC application is running on the local machine. + * + * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. + * Changes : New isAppRunningEx uses productSAPCodeSpecifiers + * + * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. + * @return True if the app is running, false otherwise. + */ +Vulcan.prototype.isAppRunningEx = function (productSAPCodeSpecifier) { + if (!requiredParamsValid(productSAPCodeSpecifier)) { + return false; + } + + var params = {}; + params.productSAPCodeSpecifier = productSAPCodeSpecifier; + + return JSON.parse( + window.__adobe_cep__.invokeSync( + "vulcanIsAppRunningEx", + JSON.stringify(params) + ) + ).result; +}; + +/** + * Checks whether a CC application is installed on the local machine. + * + * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. + * Changes : New isAppInstalledEx uses productSAPCodeSpecifiers + * + * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. + * @return True if the app is installed, false otherwise. + */ +Vulcan.prototype.isAppInstalledEx = function (productSAPCodeSpecifier) { + if (!requiredParamsValid(productSAPCodeSpecifier)) { + return false; + } + + var params = {}; + params.productSAPCodeSpecifier = productSAPCodeSpecifier; + + return JSON.parse( + window.__adobe_cep__.invokeSync( + "vulcanIsAppInstalledEx", + JSON.stringify(params) + ) + ).result; +}; + +/**s + * Retrieves the local install path of a CC application. + * + * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. + * Changes : New getAppPathEx uses productSAPCodeSpecifiers + * + * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. + * @return The path string if the application is found, "" otherwise. + */ +Vulcan.prototype.getAppPathEx = function (productSAPCodeSpecifier) { + if (!requiredParamsValid(productSAPCodeSpecifier)) { + return ""; + } + + var params = {}; + params.productSAPCodeSpecifier = productSAPCodeSpecifier; + + return JSON.parse( + window.__adobe_cep__.invokeSync( + "vulcanGetAppPathEx", + JSON.stringify(params) + ) + ).result; +}; + +/** + * DEPRECATED API:: use getTargetSpecifiersEx + * Gets all available application specifiers on the local machine. + * + * @return The array of all available application specifiers. + */ +Vulcan.prototype.getTargetSpecifiers = function () { + console.warn( + "WARNING! Function 'getTargetSpecifiers' has been deprecated, please use the new 'getTargetSpecifiersEx' function instead!" + ); + var params = {}; + return JSON.parse( + window.__adobe_cep__.invokeSync( + "vulcanGetTargetSpecifiers", + JSON.stringify(params) + ) + ); +}; + +/** + * DEPRECATED API:: use launchAppEx + * Launches a CC application on the local machine, if it is not already running. + * + * @param targetSpecifier The application specifier; for example "indesign". + * + * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + * receive wrong result. + * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + * + * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @param focus True to launch in foreground, or false to launch in the background. + * @param cmdLine Optional, command-line parameters to supply to the launch command. + * @return True if the app can be launched, false otherwise. + */ +Vulcan.prototype.launchApp = function (targetSpecifier, focus, cmdLine) { + console.warn( + "WARNING! Function 'launchApp' has been deprecated, please use the new 'launchAppEx' function instead!" + ); + if (!requiredParamsValid(targetSpecifier)) { + return false; + } + + var params = {}; + params.targetSpecifier = targetSpecifier; + params.focus = focus ? "true" : "false"; + params.cmdLine = requiredParamsValid(cmdLine) ? cmdLine : ""; + + return JSON.parse( + window.__adobe_cep__.invokeSync("vulcanLaunchApp", JSON.stringify(params)) + ).result; +}; + +/** + * DEPRECATED API:: use isAppRunningEx + * Checks whether a CC application is running on the local machine. + * + * @param targetSpecifier The application specifier; for example "indesign". + * + * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + * receive wrong result. + * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + * + * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @return True if the app is running, false otherwise. + */ +Vulcan.prototype.isAppRunning = function (targetSpecifier) { + console.warn( + "WARNING! Function 'isAppRunning' has been deprecated, please use the new 'isAppRunningEx' function instead!" + ); + if (!requiredParamsValid(targetSpecifier)) { + return false; + } + + var params = {}; + params.targetSpecifier = targetSpecifier; + + return JSON.parse( + window.__adobe_cep__.invokeSync( + "vulcanIsAppRunning", + JSON.stringify(params) + ) + ).result; +}; + +/** + * DEPRECATED API:: use isAppInstalledEx + * Checks whether a CC application is installed on the local machine. + * + * @param targetSpecifier The application specifier; for example "indesign". + * + * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + * receive wrong result. + * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + * + * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @return True if the app is installed, false otherwise. + */ +Vulcan.prototype.isAppInstalled = function (targetSpecifier) { + console.warn( + "WARNING! Function 'isAppInstalled' has been deprecated, please use the new 'isAppInstalledEx' function instead!" + ); + if (!requiredParamsValid(targetSpecifier)) { + return false; + } + + var params = {}; + params.targetSpecifier = targetSpecifier; + + return JSON.parse( + window.__adobe_cep__.invokeSync( + "vulcanIsAppInstalled", + JSON.stringify(params) + ) + ).result; +}; + +/** + * DEPRECATED API:: use getAppPathEx + * Retrieves the local install path of a CC application. + * + * @param targetSpecifier The application specifier; for example "indesign". + * + * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version + * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you + * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may + * receive wrong result. + * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". + * + * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. + * @return The path string if the application is found, "" otherwise. + */ +Vulcan.prototype.getAppPath = function (targetSpecifier) { + console.warn( + "WARNING! Function 'getAppPath' has been deprecated, please use the new 'getAppPathEx' function instead!" + ); + if (!requiredParamsValid(targetSpecifier)) { + return ""; + } + + var params = {}; + params.targetSpecifier = targetSpecifier; + + return JSON.parse( + window.__adobe_cep__.invokeSync("vulcanGetAppPath", JSON.stringify(params)) + ).result; +}; + +/** + * Registers a message listener callback function for a Vulcan message. + * + * @param type The message type. + * @param callback The callback function that handles the message. + * Takes one argument, the message object. + * @param obj Optional, the object containing the callback method, if any. + * Default is null. + */ +Vulcan.prototype.addMessageListener = function (type, callback, obj) { + if ( + !requiredParamsValid(type, callback) || + !strStartsWith(type, VulcanMessage.TYPE_PREFIX) + ) { + return; + } + + var params = {}; + params.type = type; + + window.__adobe_cep__.invokeAsync( + "vulcanAddMessageListener", + JSON.stringify(params), + callback, + obj + ); +}; + +/** + * Removes a registered message listener callback function for a Vulcan message. + * + * @param type The message type. + * @param callback The callback function that was registered. + * Takes one argument, the message object. + * @param obj Optional, the object containing the callback method, if any. + * Default is null. + */ +Vulcan.prototype.removeMessageListener = function (type, callback, obj) { + if ( + !requiredParamsValid(type, callback) || + !strStartsWith(type, VulcanMessage.TYPE_PREFIX) + ) { + return; + } + + var params = {}; + params.type = type; + + window.__adobe_cep__.invokeAsync( + "vulcanRemoveMessageListener", + JSON.stringify(params), + callback, + obj + ); +}; + +/** + * Dispatches a Vulcan message. + * + * @param vulcanMessage The message object. + */ +Vulcan.prototype.dispatchMessage = function (vulcanMessage) { + if ( + !requiredParamsValid(vulcanMessage) || + !strStartsWith(vulcanMessage.type, VulcanMessage.TYPE_PREFIX) + ) { + return; + } + + var params = {}; + var message = new VulcanMessage(vulcanMessage.type); + message.initialize(vulcanMessage); + params.vulcanMessage = message; + + window.__adobe_cep__.invokeSync( + "vulcanDispatchMessage", + JSON.stringify(params) + ); +}; + +/** + * Retrieves the message payload of a Vulcan message for the registered message listener callback function. + * + * @param vulcanMessage The message object. + * @return A string containing the message payload. + */ +Vulcan.prototype.getPayload = function (vulcanMessage) { + if ( + !requiredParamsValid(vulcanMessage) || + !strStartsWith(vulcanMessage.type, VulcanMessage.TYPE_PREFIX) + ) { + return null; + } + + var message = new VulcanMessage(vulcanMessage.type); + message.initialize(vulcanMessage); + return message.getPayload(); +}; + +/** + * Gets all available endpoints of the running Vulcan-enabled applications. + * + * Since 7.0.0 + * + * @return The array of all available endpoints. + * An example endpoint string: + * + * PHXS + * 16.1.0 + * + */ +Vulcan.prototype.getEndPoints = function () { + var params = {}; + return JSON.parse( + window.__adobe_cep__.invokeSync( + "vulcanGetEndPoints", + JSON.stringify(params) + ) + ); +}; + +/** + * Gets the endpoint for itself. + * + * Since 7.0.0 + * + * @return The endpoint string for itself. + */ +Vulcan.prototype.getSelfEndPoint = function () { + var params = {}; + return window.__adobe_cep__.invokeSync( + "vulcanGetSelfEndPoint", + JSON.stringify(params) + ); +}; + +/** Singleton instance of Vulcan **/ +var VulcanInterface = new Vulcan(); + +//--------------------------------- Vulcan Message ------------------------------ + +/** + * @class VulcanMessage + * Message type for sending messages between host applications. + * A message of this type can be sent to the designated destination + * when appId and appVersion are provided and valid. Otherwise, + * the message is broadcast to all running Vulcan-enabled applications. + * + * To send a message between extensions running within one + * application, use the CSEvent type in CSInterface.js. + * + * @param type The message type. + * @param appId The peer appId. + * @param appVersion The peer appVersion. + * + */ +function VulcanMessage(type, appId, appVersion) { + this.type = type; + this.scope = VulcanMessage.SCOPE_SUITE; + this.appId = requiredParamsValid(appId) + ? appId + : VulcanMessage.DEFAULT_APP_ID; + this.appVersion = requiredParamsValid(appVersion) + ? appVersion + : VulcanMessage.DEFAULT_APP_VERSION; + this.data = VulcanMessage.DEFAULT_DATA; +} + +VulcanMessage.TYPE_PREFIX = "vulcan.SuiteMessage."; +VulcanMessage.SCOPE_SUITE = "GLOBAL"; +VulcanMessage.DEFAULT_APP_ID = "UNKNOWN"; +VulcanMessage.DEFAULT_APP_VERSION = "UNKNOWN"; +VulcanMessage.DEFAULT_DATA = ""; +VulcanMessage.dataTemplate = "{0}"; +VulcanMessage.payloadTemplate = "{0}"; + +/** + * Initializes this message instance. + * + * @param message A \c message instance to use for initialization. + */ +VulcanMessage.prototype.initialize = function (message) { + this.type = message.type; + this.scope = message.scope; + this.appId = message.appId; + this.appVersion = message.appVersion; + this.data = message.data; +}; + +/** + * Retrieves the message data. + * + * @return A data string in XML format. + */ +VulcanMessage.prototype.xmlData = function () { + if (this.data === undefined) { + var str = ""; + str = String.format(VulcanMessage.payloadTemplate, str); + this.data = String.format(VulcanMessage.dataTemplate, str); + } + return this.data; +}; + +/** + * Sets the message payload of this message. + * + * @param payload A string containing the message payload. + */ +VulcanMessage.prototype.setPayload = function (payload) { + var str = cep.encoding.convertion.utf8_to_b64(payload); + str = String.format(VulcanMessage.payloadTemplate, str); + this.data = String.format(VulcanMessage.dataTemplate, str); +}; + +/** + * Retrieves the message payload of this message. + * + * @return A string containing the message payload. + */ +VulcanMessage.prototype.getPayload = function () { + var str = GetValueByKey(this.data, "payload"); + if (str !== null) { + return cep.encoding.convertion.b64_to_utf8(str); + } + return null; +}; + +/** + * Converts the properties of this instance to a string. + * + * @return The string version of this instance. + */ +VulcanMessage.prototype.toString = function () { + var str = "type=" + this.type; + str += ", scope=" + this.scope; + str += ", appId=" + this.appId; + str += ", appVersion=" + this.appVersion; + str += ", data=" + this.xmlData(); + return str; +}; + +//--------------------------------------- Util -------------------------------- + +/** + * Formats a string based on a template. + * + * @param src The format template. + * + * @return The formatted string + */ +String.format = function (src) { + if (arguments.length === 0) { + return null; + } + + var args = Array.prototype.slice.call(arguments, 1); + return src.replace(/\{(\d+)\}/g, function (m, i) { + return args[i]; + }); +}; + +/** + * Retrieves the content of an XML element. + * + * @param xmlStr The XML string. + * @param key The name of the tag. + * + * @return The content of the tag, or the empty string + * if such tag is not found or the tag has no content. + */ +function GetValueByKey(xmlStr, key) { + if (window.DOMParser) { + var parser = new window.DOMParser(); + try { + var xmlDoc = parser.parseFromString(xmlStr, "text/xml"); + var node = xmlDoc.getElementsByTagName(key)[0]; + if (node && node.childNodes[0]) { + return node.childNodes[0].nodeValue; + } + } catch (e) { + //log the error + } + } + return ""; +} + +/** + * Reports whether required parameters are valid. + * + * @return True if all required parameters are valid, + * false if any of the required parameters are invalid. + */ +function requiredParamsValid() { + for (var i = 0; i < arguments.length; i++) { + var argument = arguments[i]; + if (argument === undefined || argument === null) { + return false; + } + } + return true; +} + +/** + * Reports whether a string has a given prefix. + * + * @param str The target string. + * @param prefix The specific prefix string. + * + * @return True if the string has the prefix, false if not. + */ +function strStartsWith(str, prefix) { + if (typeof str != "string") { + return false; + } + return str.indexOf(prefix) === 0; +} + +// Boilerplate Added Export +export { VulcanMessage }; +export default Vulcan; diff --git a/AdminPanel/plugins/utils/dom/cursor.js b/AdminPanel/plugins/utils/dom/cursor.js new file mode 100644 index 0000000..54bda01 --- /dev/null +++ b/AdminPanel/plugins/utils/dom/cursor.js @@ -0,0 +1,65 @@ +/** + + * 获取当前光标位置 返回表示位置的索引(number)以0开头 + + * @param ctrl + + * @returns {number} + + */ + +export function getCursorPosition(element) { + + var CaretPos = 0; + + if (document.selection) {//支持IE + + element.focus(); + + var Sel = document.selection.createRange(); + + Sel.moveStart('character', -element.value.length); + + CaretPos = Sel.text.length; + + } + + else if (element.selectionStart || element.selectionStart == '0')//支持firefox + + CaretPos = element.selectionStart; + + return (CaretPos); + +} + +export function insertAtCursor(myField, myValue) { + + //IE 浏览器 + if (document.selection) { + myField.focus(); + sel = document.selection.createRange(); + sel.text = myValue; + sel.select(); + } + + //FireFox、Chrome等 + else if (myField.selectionStart || myField.selectionStart == '0') { + var startPos = myField.selectionStart; + var endPos = myField.selectionEnd; + + // 保存滚动条 + var restoreTop = myField.scrollTop; + myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length); + + if (restoreTop > 0) { + myField.scrollTop = restoreTop; + } + + myField.focus(); + myField.selectionStart = startPos + myValue.length; + myField.selectionEnd = startPos + myValue.length; + } else { + myField.value += myValue; + myField.focus(); + } +} \ No newline at end of file diff --git a/AdminPanel/plugins/utils/dom/dom.js b/AdminPanel/plugins/utils/dom/dom.js new file mode 100644 index 0000000..4010802 --- /dev/null +++ b/AdminPanel/plugins/utils/dom/dom.js @@ -0,0 +1,313 @@ +/** + * 简单版对dom的封装 + * 初始化一个myDom对象 + * 通过类、id、以及dom元素创建 + * 可以获取所有子节点、父节点、第一个子节点、最后一个子节点、上一个兄弟节点、下一个兄弟节点 + * 判断元素类型 + * 获取文本 + * 获取元素的坐标、宽高 + * 设置元素的坐标、宽高 + * 设置样式 + * 复制元素 + * 返回真正的dom元素 + * 获取所有父亲节点 + * 获取指定类型的父节点 + * 获取所有子节点 + * 获取自定类型的子节点 + */ + +/** + * 获取dom元素 + * @param {*} 参数 ,可以接受dom元素或者id(id必须带#号) + */ +export function $(el) { + //id选择器 + if (typeof el == 'object') { + return new Dom(el); + } else if (typeof el == 'string') { + let dom = document.getElementById(el); + return dom ? new Dom(dom) : null; + } else { + console.warn(`Dom:传入的字符串不符合要求${el}`); + } + + return null; +} + +export class Dom { + constructor(el) { + this._el = el; + } + /** + * 获取元素内的所有文本内容 + */ + getTexts() { + let result = []; + const callback = (el) => { + let arr = [...el.childNodes]; + arr.filter(item => item.nodeType == 3).forEach(item => result.push(item.nodeValue)) + arr.filter(item => item.nodeType == 1).forEach(item => callback(item));//遍历所有元素的子节点 + } + callback(this._el); + return result; + } + + /** + * 获取标签内第一个文本,没有返回空 + * @returns + */ + getText() { + let texts = this.getTexts(); + return texts.length > 0 ? texts[0] : '' + } + + /** + * 获取元素的高 + */ + getHeight() { + return this._el.offsetHeight; + } + + /** + * 获取元素的宽 + */ + getWidth() { + return this._el.offsetWidth; + } + + get left() { + return this.getLeft(); + } + + get top() { + return this.getTop(); + } + + get width() { + return this._el.offsetWidth; + } + + get height() { + return this._el.offsetHeight; + } + + get bottom() { + return this.top + this.height; + } + + get right() { + return this.left + this.width; + } + + /** + * 获取元素的left坐标 + */ + getLeft() { + const callback = (e) => { + return e.offsetParent != null ? e.offsetLeft + callback(e.offsetParent) : e.offsetLeft + } + return callback(this._el) + } + + /** + * 获取元素的顶点坐标 + */ + getTop() { + const callback = (e) => { + return e.offsetParent != null ? e.offsetTop + callback(e.offsetParent) : e.offsetTop + } + return callback(this._el) + } + + /** + * 获取坐标,包含4个点以及宽高 + * @returns + */ + getPosition() { + return { + left: this.getLeft(), + top: this.getTop(), + } + } + + /** + * 设置样式,直接合并css的样式对象 + * @param {*} option + */ + setStyle(option) { + Object.assign(this._el.style, option); + } + + addUnit(val, unit = 'px') { + // return unit ? val + unit : val; + return val + unit; + } + + /** + * 设置坐标 + * @param {*} val 左坐标位置 + * @param {*} unit 默认单位为px,如果不用则,需要传递null + */ + setLeft(val, unit = 'px') { + this.setStyle({ left: this.addUnit(val, unit) }) + } + + /** + * 设置顶坐标 + * @param {*} val + * @param {*} unit + */ + setTop(val, unit = 'px') { + this.setStyle({ top: this.addUnit(val, unit) }) + } + + /** + * 设置宽度 + * @param {*} val + * @param {*} unit + */ + setWidth(val, unit = 'px') { + this.setStyle({ width: this.addUnit(val, unit) }) + } + + setHeight(val, unit = 'px') { + this.setStyle({ height: this.addUnit(val, unit) }) + } + + setSize(width, height, unit = 'px') { + this.setStyle({ + width: this.addUnit(width, unit), + height: this.addUnit(height, unit), + }) + } + + /** + * 设置元素位置 + * @param {*} left + * @param {*} top + * @param {*} unit 单位,默认为px + */ + setPosition(left, top, unit = 'px') { + this.setStyle({ + left: this.addUnit(left, unit), + top: this.addUnit(top, unit) + }) + } + + /** + * 克隆元素 + * @param {*} deep + * @returns + */ + clone(deep = true) { + let el = this._el.cloneNode(deep);//克隆元素 + return new Dom(el); + } + + /** + * 移除元素 + */ + remove() { + this._el.remove(); + } + + /** + * 返回原本的dom元素 + * @returns + */ + getElement() { + return this._el; + } + + /** + * 获取封装一层的子元素 + */ + childNodes() { + return [...this._el.childNodes].map(item => new Dom(item)) + } + + parentNode() { + return new Dom(this._el.parentNode) + } + + firstChild() { + return new Dom(this._el.firstChild); + } + + lastChild() { + return new Dom(this._el.lastChild) + } + + nextSibling() { + return new Dom(this._el.nextSibling) + } + + previousSibling() { + return new Dom(this._el.previousSibling) + } + + /** + * 是否是标签元素 + * @returns + */ + isElement() { + return this._el.nodeType == 1; + } + + /** + * 获取第一个指定标签的元素 + * @param {*} name 标签名字 + */ + firstParentByName(name) { + name = name.toUpperCase();//转大写 + const callback = (el) => { + let parent = el.parentNode; + if (parent.nodeName == 'BODY') + return null; + + if (parent.nodeName == name) + return new Dom(parent) + return callback(parent); + } + + return callback(this._el); + } + + firstChildByName(name) { + name = name.toUpperCase();//转大写 + const callback = (el) => { + let childs = el.childNodes; + if (childs.length == 0) + return null; + + for (let i = 0; i < childs.length; i++) { + const item = childs[i]; + if (item.nodeName == name) + return new Dom(item) + } + + for (let i = 0; i < childs.length; i++) { + const item = childs[i]; + if (item.childNodes.length > 0) + return callback(item) + } + return null; + } + + return callback(this._el); + } + + getNodeName() { + return this._el.nodeName; + } + + /** + * 全选 + */ + select() { + + // console.log(this._el); + this._el.focus(); + this._el.select(); + } +} \ No newline at end of file diff --git a/AdminPanel/plugins/utils/dom/index.js b/AdminPanel/plugins/utils/dom/index.js new file mode 100644 index 0000000..3931243 --- /dev/null +++ b/AdminPanel/plugins/utils/dom/index.js @@ -0,0 +1,113 @@ +/** + * 获取元素坐标 + * @param {*} params + */ +export function getRefPosition(e) { + return { left: getLeft(e), top: getTop(e) }; +} + +export function getTop(e) { + var offset = e.offsetTop; + if (e.offsetParent != null) offset += getTop(e.offsetParent); + return offset; +} + +export function getLeft(e) { + var offset = e.offsetLeft; + if (e.offsetParent != null) offset += getLeft(e.offsetParent); + return offset; +} + +export function getHeight(id) { + let dom = document.getElementById(id); + return dom.offsetHeight; +} + +export function getWidth(id) { + let dom = document.getElementById(id); + return dom.offsetWidth; +} +export function getClientHeight(id) { + let dom = document.getElementById(id); + return dom.clientHeight; +} + +export function getClientWidth(id) { + let dom = document.getElementById(id); + return dom.clientWidth; +} + +export function getWindowsHeight(param) { + return document.body.clientHeight +} + +export function getWindowsWidth(param) { + return document.body.clientWidth +} + +/** + * 教程菜单位置,保证菜单出现的位置不超出不可见区域 + * @param {*} e + * @param {*} menuId + * @returns + */ +export function correctMenuPosition(e, menuId) { + let winHeight = getWindowsHeight(); + let height = getHeight(menuId); + + let winWidth = getWindowsWidth(); + let windth = getWidth(menuId); + + let top = (height + e.clientY) > winHeight ? winHeight - height : e.clientY; + + let left = (windth + e.clientX) > winWidth ? winWidth - windth : e.clientX; + return { top, left: left + 5 } +} + +/** + * 设置id的元素选择 + * @param {*} id + */ +export function setInputSelect(id, time = 0) { + let count = 0; + const callbcak = () => { + let dom = document.getElementById(id); + if (!dom) { + count += 1; + if (count > 50) return + return setTimeout(callbcak, 50); + } + dom.select(); + dom.focus() + } + time == 0 ? callbcak() : setTimeout(callbcak, 50); +} + +export function setFoucs(id, time = 0) { + setTimeout(() => { + let dom = document.getElementById(id); + dom.focus() + }, time); +} + + + +/** + * 获取dom元素位置 + * @param {*} e + * @returns + */ +export function getPosition(e) { + var evt = e || event; + return { x: evt.clientX, y: evt.clientY } +} + +/** + * 根据id获取元素的位置 + * @param {*} elementId + * @returns + */ +export function getPostionById(elementId) { + var el = document.getElementById(elementId); + return getRefPosition(el); +} \ No newline at end of file diff --git a/AdminPanel/plugins/utils/drag/dom.js b/AdminPanel/plugins/utils/drag/dom.js new file mode 100644 index 0000000..1a34859 --- /dev/null +++ b/AdminPanel/plugins/utils/drag/dom.js @@ -0,0 +1,64 @@ +/** + * 在指定节点前插入节点 + * @param {*} newElement + * @param {*} targentElement + */ +export function insertBefore(newElement, targentElement) { + targentElement.parentNode.insertBefore(newElement, targentElement) +} + +/** + * 在指定节点后插入节点 + * @param {*} newNode + * @param {*} referenceNode + */ +export function insertAfter(newNode, referenceNode) { + referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); +} + + +/** + * 获取元素上坐标 + * @param {*} e + * @returns + */ +export function getTop(e) { + var result = e.offsetTop; + if (e.offsetParent != null) + result += getTop(e.offsetParent); + return result; +} + +/** + * 获取元素左坐标 + * @param {*} e + * @returns + */ +export function getLeft(e) { + var result = e.offsetLeft; + if (e.offsetParent != null) + result += getLeft(e.offsetParent); + return result; +} + +/** + * 获取dom元素位置 + * @param {*} e + * @returns + */ +export function getPosition(e) { + var evt = e || event; + return { x: evt.clientX, y: evt.clientY } +} + +/** + * 设置dom元素的位置 left top + * @param {*} dom + * @param {*} x + * @param {*} y + * @param {*} unit 后缀单位,默认px + */ +export function setPosition(dom, left, top, unit = 'px') { + dom.style.left = left + unit; + dom.style.top = top + unit; +} \ No newline at end of file diff --git a/AdminPanel/plugins/utils/drag/drag.js b/AdminPanel/plugins/utils/drag/drag.js new file mode 100644 index 0000000..9352f4c --- /dev/null +++ b/AdminPanel/plugins/utils/drag/drag.js @@ -0,0 +1,174 @@ +//引入操作dom元素的 +import { insertBefore, insertAfter, getTop, getLeft, getPosition, setPosition } from './dom.js' + +class Drap { + static status = { + downIndex: null, + upIndex: null, + node: null, + transparentNode: null, + time: null, + callback: null, + styleWidth: null, + styleHeight: null, + } + + /** + * 鼠标松开 + * @returns + */ + static onMouseUp() { + Drap.status.time && clearTimeout(Drap.status.time); + + let obj = Object.assign({}, Drap.status); //浅复制一份 + Drap.resetStatus(); //重置 + + if (obj.downIndex != null && obj.upIndex != null && obj.downIndex != obj.upIndex) { + Drap.status.callback && Drap.status.callback(obj); + Drap.status.callback = null; + } + + document.removeEventListener('mouseup', DragFolder.onMouseUp); + document.removeEventListener('mousemove', DragFolder.onMouseMove); + return false; + } + + /** + * 鼠标移动 + * @param {*} e + */ + static onMouseMove(e) { + let res = getPosition(e); + setPosition(Drap.status.node, res.x, res.y); + } + + /** + * 重置状态 + * @returns + */ + static resetStatus() { + if (Drap.status.downIndex == null) + return; + Drap.status.downIndex = null; + Drap.status.upIndex = null; + Drap.status.upIndex = null; + Drap.status.time = null; + + if (Drap.status.node != null) { + Drap.status.node.style.width = Drap.status.styleWidth; + Drap.status.node.style.height = Drap.status.styleHeight; + Drap.status.node.style.position = "static"; + } + + + Drap.status.transparentNode && Drap.status.transparentNode.remove(); + Drap.status.transparentNode = null; + } + + constructor(el, option = {}) { + let config = { + direction: 'x', //默认配置 左右方向 + callback: null, + } + Object.assign(config, option); + this.option = config; + + this.el = el; + this.downTime = 300; + this.init(); + } + + /** + * 初始化 + */ + init() { + // console.log(this.option); + this.el.onmousedown = (e) => { + this.onMouseDown(e) + return false + } + + this.el.onmousemove = (e) => { + this.onMouseMove(e); + } + } + + /** + * 鼠标按下事件 + * @param {*} e + */ + onMouseDown(e) { + document.addEventListener('mouseup', Drap.onMouseUp); + + Drap.status.time = setTimeout(() => { + Drap.status.downIndex = this.option.index; + Drap.status.node = this.el; + Drap.status.transparentNode = this.el.cloneNode(true); //克隆节点 + Drap.status.callback = this.option.callback; + + console.log(this.el.offsetWidth); + + Drap.status.styleWidth = Drap.status.node.style.width; + Drap.status.styleHeight = Drap.status.node.style.height; + Drap.status.node.style.width = this.el.offsetWidth + "px"; + Drap.status.node.style.height = this.el.offsetHeight + "px" + //处理节点显示 + Drap.status.node.style.position = "fixed"; + + + + Drap.status.transparentNode.style.cssText += ";opacity: 0;" + insertBefore(Drap.status.transparentNode, this.el); + + document.addEventListener('mousemove', Drap.onMouseMove); + }, this.downTime); + } + + + /** + * 鼠标移动事件 + * @param {*} e + * @returns + */ + onMouseMove(e) { + if (Drap.status.downIndex == null) + return false; + + let left = getLeft(this.el) + this.el.offsetWidth / 2; + let top = getTop(this.el) + this.el.offsetHeight / 2; + + let obj = getPosition(e); + let min = Drap.status.downIndex < this.option.index; + + //左右方向进行拖拽 + Drap.status.upIndex = this.option.index; + if (this.option.direction == 'x') { + if (obj.x < left) { + // console.log('左边'); + insertBefore(Drap.status.transparentNode, this.el) + } else { + // console.log('右边'); + insertAfter(Drap.status.transparentNode, this.el) + Drap.status.upIndex += min ? 0 : 1; //按下大于松开的下标+1 + } + return; + } + + //上下方向拖拽 + if (obj.y < top) { + // console.log('上边'); + insertBefore(Drap.status.transparentNode, this.el); + } else { + // console.log('下边'); + insertAfter(Drap.status.transparentNode, this.el); + Drap.status.upIndex += min ? 0 : 1; //按下大于松开的下标+1 + } + } +} + +//导出vue指令用到的对象 +export const drag = { + mounted(el, binding) { + new Drap(el, binding.value || {}) + } +} \ No newline at end of file diff --git a/AdminPanel/plugins/utils/drag/dragFileToFolder.js b/AdminPanel/plugins/utils/drag/dragFileToFolder.js new file mode 100644 index 0000000..e8637e8 --- /dev/null +++ b/AdminPanel/plugins/utils/drag/dragFileToFolder.js @@ -0,0 +1,203 @@ +/** + * 实现拖拽文件到文件夹 + */ +import { getPosition, setPosition } from './dom.js' +import { ipcSend } from "@/api/electronApi/ipc.js" + +let g_time = null; +let g_div = null; +let g_foldersElement = [];//所有文件夹的dom元素 +let g_selectId = 'g_selectId'; +let g_moveCssTest = '';//css样式 +let g_callback = null; +/** + * 开启拖拽 + * @param {Array} folderIds 所有文件夹的id数组,需要通过获取文件夹单个的id开启拖移入移出事件 + * @param {String} imgPath 预览图片的路径地址 + * @param {Int} number 拖动的数量 + * @param {Function} endCallback 回调函数,返回null || id + */ +export function startDragFileToFolder(e, folderIds, imgPath, number, endCallback, readyCallback) { + + const downTime = 200; + // document.addEventListener('mouseup', mouseUp, true);//绑定鼠标松开事件 + + g_time = setTimeout(() => { + // console.log('dragFileToFolder=>绑定事件'); + // readyCallback && readyCallback();//准备 + // createPreviewElement(imgPath, number); + + // mouseMove(e) + ipcSend('ondragstart', imgPath) + + // addFolderEvent(folderIds); + // g_callback = endCallback; + // document.addEventListener('mousemove', mouseMove, true);//绑定鼠标松开事件 + }, downTime); +} +// export function startDragFileToFolder(e, folderIds, imgPath, number, endCallback, readyCallback) { + +// const downTime = 200; +// document.addEventListener('mouseup', mouseUp, true);//绑定鼠标松开事件 + +// g_time = setTimeout(() => { +// console.log('dragFileToFolder=>绑定事件'); +// readyCallback && readyCallback();//准备 +// createPreviewElement(imgPath, number); + +// // mouseMove(e) +// ipcSend('ondragstart',imgPath) + +// addFolderEvent(folderIds); +// g_callback = endCallback; +// document.addEventListener('mousemove', mouseMove, true);//绑定鼠标松开事件 +// }, downTime); +// } + +/** + * 鼠标拖动的处理事件 + * @param {*} params + */ +function mouseMove(e) { + console.log('dragFileToFolder=>拖动'); + let res = getPosition(e); + setPosition(g_div, res.x + 4, res.y + 4); +} + +/** + * 松开鼠标的处理事件 + */ +function mouseUp() { + if (g_time) + clearTimeout(g_time); + + clearPreviewElement();//清除节点 + removeFolderEvent();//清除所有文件夹元素的事件 + document.removeEventListener('mouseup', mouseUp, true); + document.removeEventListener('mousemove', mouseMove, true); + console.log('dragFileToFolder=>取消绑定'); + + if (g_selectId) { + console.log('最终id:', g_selectId); + if (g_selectId.style) + g_selectId.style.cssText = g_moveCssTest; + + const idText = '#leftFolderItem'; + if (g_selectId.id) + g_callback && g_callback(g_selectId.id.replace(idText, '')) + g_selectId = null; + } + g_callback = null; +} + + +/** + * 创建预览元素 + */ +function createPreviewElement(imgPath, number) { + if (g_div != null) + return; + g_div = document.createElement('div'); + let img = document.createElement('img'); + img.src = imgPath; + + g_div.appendChild(img); + Object.assign(img.style, { + maxWidth: '100px', + maxHeight: '100px', + border: '2px solid #2a98ff', + borderRadius: '4px' + }) + + Object.assign(g_div.style, { + position: 'fixed', + zIndex: 10011, + left: '-1000px', + }) + + g_div.appendChild(createTextElement(number)); + document.body.appendChild(g_div); +} + +/** + * 创建文件数量的样式 + * @param {*} number + * @returns + */ +function createTextElement(number) { + let dom = document.createElement('div'); + dom.innerHTML = number; + let style = { + width: '24px', + height: '24px', + lineHeight: '24px', + borderRadius: '100%', + background: "#D84A4A", + color: '#fff', + fontSize: '12px', + position: "absolute", + top: '-12px', + right: '-12px', + boxShadow: '0px 0px 10px rgba(0, 0, 0, 0.3)', + textAlign: 'center' + } + Object.assign(dom.style, style); + return dom; +} + +/** + * 清除创建的元素 + */ +function clearPreviewElement() { + if (g_div) { + g_div.remove(); + g_div = null; + } +} + + +function mouseover(e) { + console.log('移入', e); + let el = e.target; + if (el.id == '') + el = el.parentNode; + g_selectId = el; + g_moveCssTest = el.style.cssText + el.style.border = '1px solid #2a98ff'; + el.style.background = 'rgba(42,152,255,0.2)'; +} + +function mouseout(e) { + let el = e.target; + if (el.id == '') { + el = el.parentNode; + } + console.log('移出', el); + g_selectId = null; + // let el = e.target; + el.style.cssText = g_moveCssTest; +} + +/** + * 给文件夹id添加关联事件 + * @param {Array} ids 所有文件夹id + */ +function addFolderEvent(ids) { + const idText = '#leftFolderItem'; + + g_foldersElement = ids.map(id => document.getElementById(idText + id)).filter(el => el) + g_foldersElement.forEach(el => { + el.addEventListener('mouseover', mouseover);//鼠标移入 + el.addEventListener('mouseout', mouseout);//鼠标移出事件 + }) +} + +function removeFolderEvent(params) { + if (g_foldersElement.length > 0) { + g_foldersElement.forEach(el => { + el.removeEventListener('mouseover', mouseover);//鼠标移入 + el.removeEventListener('mouseout', mouseout);//鼠标移出事件 + }) + g_foldersElement.splice(0, g_foldersElement.length); + } +} \ No newline at end of file diff --git a/AdminPanel/plugins/utils/drag/dragFileToImage.js b/AdminPanel/plugins/utils/drag/dragFileToImage.js new file mode 100644 index 0000000..47ab884 --- /dev/null +++ b/AdminPanel/plugins/utils/drag/dragFileToImage.js @@ -0,0 +1,68 @@ +/** + * 拖拽文件时,创建一个临时的预览图 + */ +import { nodeFs, getOsPrefix } from "@/utils/nodeFs" +import g_config from "@/api/config/index"; +/** + * 通过canvas将svg转成png + * @param {*} path 路径 + * @returns 返回base64字符串 + */ +export function dragFile2png(path, number) { + // debugger + let outPath = g_config.path.dragPreview; + console.log(path, outPath); + + return new Promise((resolve, reject) => { + var img = new Image(); + img.src = getOsPrefix() + path; + img.onload = () => { + var canvas = document.createElement('canvas'); + var c = canvas.getContext('2d'); + + let width, height; + let scale = img.width / 100; + if (img.width > img.height) { + width = 100; + height = img.height / scale; + } else { + scale = img.height / 100; + height = 100; + width = img.width / scale; + } + + + canvas.width = width + 20; + canvas.height = height + 10; + //canvas画图片 + c.drawImage(img, 10, 10, width, height); + c.strokeStyle = "#2961d9"; + c.lineWidth = 2; + c.strokeRect(10, 10, width, height); + + if (number > 1) { + c.beginPath(); + c.arc(width + 10, 10, 10, 0, Math.PI * 2, true); + c.closePath(); + c.fillStyle = "rgba(255,0,0,1)"; + c.fill(); + + c.fillStyle = "#fff";//文字的颜色 + c.textAlign = 'center';//对齐方式 + // c.font = '13px "微软雅黑"'; + c.fillText(number, width + 10, 13); + } + + + //将图片添加到body中 + // console.log('转png', canvas.toDataURL('image/png')); + let base64 = canvas.toDataURL('image/png') + let temp = nodeFs.sync.writeBase64(outPath, base64.split('base64,')[1]); + temp.err == 1 ? reject(temp.msg) : resolve({ outPath }); + } + + img.onerror = (err) => { + reject(err);//转换失败 + } + }) +} \ No newline at end of file diff --git a/AdminPanel/plugins/utils/drag/dragFolder.js b/AdminPanel/plugins/utils/drag/dragFolder.js new file mode 100644 index 0000000..3e8e747 --- /dev/null +++ b/AdminPanel/plugins/utils/drag/dragFolder.js @@ -0,0 +1,230 @@ +//引入操作dom元素的 +import { insertBefore, getTop, getPosition, setPosition } from './dom.js' + +export class DragFolder { + static status = { + downIndex: null, + upIndex: null, + node: null, + transparentNode: null, + moveNode: null, + moveCssTest: null, + time: null, + callback: null, + cssText: null, + position: null, + multipleChoice: null,//多选样式节点 + } + + /** + * 鼠标松开 + * @returns + */ + static onMouseUp() { + DragFolder.status.time && clearTimeout(DragFolder.status.time); + + if (DragFolder.status.moveNode != null) { + DragFolder.status.moveNode.style.cssText = DragFolder.status.moveCssTest; + DragFolder.status.moveNode = null; + } + + // let obj = Object.assign({}, DragFolder.status); //浅复制一份 + let downIndex = DragFolder.status.downIndex; + let upIndex = DragFolder.status.upIndex; + let position = DragFolder.status.position; + DragFolder.resetStatus(); //重置 + + console.log('拖拽松开'); + if (downIndex != null && upIndex != null && downIndex != upIndex) { + DragFolder.status.callback && DragFolder.status.callback({ downIndex, upIndex, position }); + DragFolder.status.callback = null; + } + + document.removeEventListener('mouseup', DragFolder.onMouseUp); + document.removeEventListener('mousemove', DragFolder.onMouseMove); + return false; + } + + /** + * 鼠标移动 + * @param {*} e + */ + static onMouseMove(e) { + console.log('移动'); + let res = getPosition(e); + setPosition(DragFolder.status.node, res.x + 4, res.y + 4); + } + + /** + * 重置状态 + * @returns + */ + static resetStatus() { + if (DragFolder.status.downIndex == null) + return; + DragFolder.status.downIndex = null; + DragFolder.status.upIndex = null; + DragFolder.status.upIndex = null; + DragFolder.status.time = null; + + if (DragFolder.status.node != null) { + DragFolder.status.node.style.cssText = DragFolder.status.cssText; + DragFolder.status.node.style.position = "static"; + + } + + if (DragFolder.status.transparentNode != null) { + DragFolder.status.transparentNode.remove(); + DragFolder.status.transparentNode = null; + } + if (DragFolder.status.multipleChoice != null) { + DragFolder.status.multipleChoice.remove(); + DragFolder.status.multipleChoice = null; + } + + + + } + + constructor(el, option = {}) { + let config = { + direction: 'x', //默认配置 左右方向 + callback: null, + } + Object.assign(config, option); + this.option = config; + + this.el = typeof el == 'string' ? document.getElementById(el) : el; + + // console.log(this.el); + this.downTime = 300; + this.init(); + } + + /** + * 初始化 + */ + init() { + // console.log(this.option); + + // debugger + this.el.onmousedown = (e) => { + // debugger + this.onMouseDown(e) + // return false + } + + this.el.onmousemove = (e) => { + this.onMouseMove(e); + } + // console.log('folder初始化', this.el,this.el.onmousedown); + } + + /** + * 鼠标按下事件 + * @param {*} e + */ + onMouseDown(e) { + document.addEventListener('mouseup', DragFolder.onMouseUp, true); + + DragFolder.status.time = setTimeout(() => { + DragFolder.status.downIndex = this.option.index; + DragFolder.status.callback = this.option.callback; + + if (this.option.downCallback) { + // debugger + let temp = this.option.downCallback(); + + let select = temp.indexOf(this.option.index) > -1 ? temp : [this.option.index]; + console.log(this.option.index,temp,select) + //创建数量的提醒 + if (select.length > 1) { + DragFolder.status.multipleChoice = document.createElement('div'); + DragFolder.status.multipleChoice.innerHTML = select.length; + let style = { + width: '24px', + height: '24px', + lineHeight: '24px', + borderRadius: '100%', + background: "#D84A4A", + color: '#fff', + fontSize: '12px', + position: "absolute", + top: '-12px', + right: '-12px', + boxShadow: '0px 0px 10px rgba(0, 0, 0, 0.3)', + textAlign: 'center' + } + Object.assign(DragFolder.status.multipleChoice.style, style) + } + console.error('按下回调', select); + } + + DragFolder.status.node = this.el; + DragFolder.status.transparentNode = this.el.cloneNode(true); //克隆节点 + // DragFolder.status.node = this.el.cloneNode(true); //克隆节点 + + console.log(this.el.offsetWidth); + + DragFolder.status.cssText = DragFolder.status.node.style.cssText; + DragFolder.status.node.style.width = this.el.offsetWidth + 4 + "px"; + DragFolder.status.node.style.height = this.el.offsetHeight + 4 + "px" + + //处理节点显示 + DragFolder.status.node.style.position = "fixed"; + DragFolder.status.node.style.background = "#2a98ff"; + DragFolder.status.node.style.zIndex = "101"; + + DragFolder.status.transparentNode.style.cssText += ";border: 1px solid #797979" + + DragFolder.status.multipleChoice && DragFolder.status.node.appendChild(DragFolder.status.multipleChoice) + insertBefore(DragFolder.status.transparentNode, this.el); + + document.addEventListener('mousemove', DragFolder.onMouseMove); + }, this.downTime); + } + + + /** + * 鼠标移动事件 + * @param {*} e + * @returns + */ + onMouseMove(e) { + if (DragFolder.status.downIndex == null) + return false; + if (DragFolder.status.moveNode != null) { + DragFolder.status.moveNode.style.cssText = DragFolder.status.moveCssTest; + DragFolder.status.moveNode = null; + } + + DragFolder.status.moveNode = this.el; + DragFolder.status.moveCssTest = this.el.style.cssText; + + // let elTop = getTop(this.el) + let elTop = this.el.getBoundingClientRect().top + let top = elTop + this.el.offsetHeight / 10 * 3; + let bottom = elTop + this.el.offsetHeight / 10 * 7; + + let obj = getPosition(e); + + //左右方向进行拖拽 + DragFolder.status.upIndex = this.option.index; + + //上下方向拖拽 + if (obj.y < top) { + this.el.style.borderTop = '1px solid #2a98ff'; + DragFolder.status.position = 'top' + } else if (obj.y > bottom) { + this.el.style.borderBottom = '1px solid #2a98ff' + DragFolder.status.position = 'bottom' + + } else { + DragFolder.status.position = 'center' + this.el.style.border = '1px solid #2a98ff'; + this.el.style.background = 'rgba(42,152,255,0.2)'; + } + } +} + +export default DragFolder; \ No newline at end of file diff --git a/AdminPanel/plugins/utils/drag/dragtagToimage.ts b/AdminPanel/plugins/utils/drag/dragtagToimage.ts new file mode 100644 index 0000000..c8a2949 --- /dev/null +++ b/AdminPanel/plugins/utils/drag/dragtagToimage.ts @@ -0,0 +1,189 @@ + + +//引入操作dom元素的 +import { insertBefore, getTop, getPosition, setPosition } from './dom.js' + +interface IOption { + index?:string, + callback?:Function, + downCallback?: Function, +} + +export class DragTag { + public el: HTMLElement + public option: IOption + public downTime: number + + static status = { + node: null, + transparentNode: null, + moveNode: null, + moveCssTest: null, + time: null, + callback: null, + cssText: null, + position: null, + multipleChoice: null,//多选样式节点 + option: null + } + constructor(el, option = {}) { + let config = { + direction: 'x', //默认配置 左右方向 + callback: null, + } + Object.assign(config, option); + this.option = config; + + this.el = typeof el == 'string' ? document.getElementById(el) : el; + + // console.log(this.el); + this.downTime = 300; + this.init(); + } + /** + * 鼠标松开 + * @returns + */ + static onMouseUp() { + DragTag.status.time && clearTimeout(DragTag.status.time); + + if (DragTag.status.moveNode != null) { + DragTag.status.moveNode.style.cssText = DragTag.status.moveCssTest; + DragTag.status.moveNode = null; + } + + + DragTag.resetStatus(); //重置 + + console.log('拖拽松开'); + DragTag.status.callback && DragTag.status.callback(); + + document.removeEventListener('mouseup', DragTag.onMouseUp); + document.removeEventListener('mousemove', DragTag.onMouseMove); + return false; + } + + /** + * 鼠标移动 + * @param {*} e + */ + static onMouseMove(e) { + console.log('移动'); + let res = getPosition(e); + setPosition(DragTag.status.node, res.x + 4, res.y + 4); + } + + /** + * 重置状态 + * @returns + */ + static resetStatus() { + + DragTag.status.time = null; + + if (DragTag.status.node != null) { + DragTag.status.node.style.cssText = DragTag.status.cssText; + DragTag.status.node.style.position = "static"; + + } + + if (DragTag.status.transparentNode != null) { + DragTag.status.transparentNode.remove(); + DragTag.status.transparentNode = null; + } + if (DragTag.status.multipleChoice != null) { + DragTag.status.multipleChoice.remove(); + DragTag.status.multipleChoice = null; + } + } + + + + /** + * 初始化 + */ + init() { + // console.log('初始化',this.el) + this.el.onmousedown = (e) => { + this.onMouseDown(e) + } + this.el.onmousemove = (e) => { + this.onMouseMove(e); + } + + } + + /** + * 鼠标按下事件 + * @param {*} e + */ + onMouseDown(e) { + e.preventDefault(); + e.stopPropagation(); + if (e.button != 0) return + console.log('按下', e.button) + document.addEventListener('mouseup', DragTag.onMouseUp); + DragTag.status.time = setTimeout(() => { + DragTag.status.callback = this.option.callback; + if (this.option.downCallback) { + // debugger + let temp = this.option.downCallback(this.option.index); + let select = temp.indexOf(this.option.index) > -1 ? temp : [this.option.index]; + console.log(this.option.index, select) + //创建数量的提醒 + if (select.length > 1) { + DragTag.status.multipleChoice = document.createElement('div'); + DragTag.status.multipleChoice.innerHTML = select.length; + let style = { + width: '14px', + height: '14px', + lineHeight: '14px', + borderRadius: '100%', + background: "#6450FF", + color: '#fff', + fontSize: '10px', + position: "absolute", + top: '-10px', + right: '0px', + boxShadow: '0px 0px 10px rgba(0, 0, 0, 0.3)', + textAlign: 'center' + } + Object.assign(DragTag.status.multipleChoice.style, style) + } + // console.error('按下回调',select); + } + + DragTag.status.node = this.el; + DragTag.status.transparentNode = this.el.cloneNode(true); //克隆节点 + // DragTag.status.node = this.el.cloneNode(true); //克隆节点 + + + + DragTag.status.cssText = DragTag.status.node.style.cssText; + DragTag.status.node.style.width = this.el.offsetWidth + 4 + "px"; + DragTag.status.node.style.height = this.el.offsetHeight + 4 + "px" + + //处理节点显示 + DragTag.status.node.style.position = "fixed"; + DragTag.status.node.style.background = "#8070FF"; + DragTag.status.node.style.zIndex = "101"; + + let res = getPosition(e); + setPosition(DragTag.status.node, res.x + 4, res.y + 4); + + DragTag.status.multipleChoice && DragTag.status.node.appendChild(DragTag.status.multipleChoice) + insertBefore(DragTag.status.transparentNode, this.el); + document.addEventListener('mousemove', DragTag.onMouseMove); + }, this.downTime); + } + + /** + * 鼠标移动事件 + * @param {*} e + * @returns + */ + onMouseMove(e) { + + } +} +export default DragTag; \ No newline at end of file diff --git a/AdminPanel/plugins/utils/json/.gitattributes b/AdminPanel/plugins/utils/json/.gitattributes new file mode 100644 index 0000000..5dcec35 --- /dev/null +++ b/AdminPanel/plugins/utils/json/.gitattributes @@ -0,0 +1 @@ +*.js linguist-detectable=false \ No newline at end of file diff --git a/Server/Designer/js/json2.js b/AdminPanel/plugins/utils/json/json2.js similarity index 100% rename from Server/Designer/js/json2.js rename to AdminPanel/plugins/utils/json/json2.js diff --git a/AdminPanel/plugins/utils/path.ts b/AdminPanel/plugins/utils/path.ts new file mode 100644 index 0000000..9260fe2 --- /dev/null +++ b/AdminPanel/plugins/utils/path.ts @@ -0,0 +1,3 @@ +export function join(...arr: string[]) { + return arr.join('/') +} \ No newline at end of file diff --git a/AdminPanel/plugins/utils/utils/aeft.ts b/AdminPanel/plugins/utils/utils/aeft.ts new file mode 100644 index 0000000..6e36b04 --- /dev/null +++ b/AdminPanel/plugins/utils/utils/aeft.ts @@ -0,0 +1,97 @@ +import { fs, path } from "../cep/node"; +import { csi } from "./bolt"; + +const getLatestFile = (dir: string, suffix: string): string | null => { + const getModified = (filePath: string) => + fs.statSync(filePath).mtime.valueOf(); + let latestFile: string | null = null; + fs.readdirSync(dir) + .filter((file) => file.includes(suffix)) + .map((file) => { + if ( + latestFile === null || + getModified(path.join(dir, file)) > + getModified(path.join(dir, latestFile)) + ) { + latestFile = file; + } + }); + return latestFile; +}; + +export const getPrefsDir = (): string => { + const appVersion = csi.getHostEnvironment().appVersion; + const { platform, env } = window.cep_node.process; + const mainDir = + platform == "darwin" + ? `${env.HOME}/Library/Preferences` + : env.APPDATA || ""; + const prefsDir = path.join( + mainDir, + "Adobe", + "After Effects", + parseFloat(appVersion).toFixed(1).toString() + ); + return prefsDir; +}; + +export const getOutputModules = (): string[] => { + const prefsDir = getPrefsDir(); + const prefsSuffix = "indep-output.txt"; + const outputPref = getLatestFile(prefsDir, prefsSuffix); + if (outputPref) { + const txt = fs.readFileSync(path.join(prefsDir, outputPref), { + encoding: "utf-8", + }); + const matches = txt.match( + /\"Output Module Spec Strings Name .* = \".*.\"/g + ); + if (matches) { + let outputModules: string[] = []; + matches.map((line) => { + const str = line.split("=").pop()?.trim().replace(/"/g, ""); + if (str && !str.includes("_HIDDEN X-Factor")) { + outputModules.push(str); + } + }); + return outputModules; + } + } + return []; +}; + +export const getRenderSettingsList = (): string[] => { + const prefsDir = getPrefsDir(); + const prefsSuffix = "indep-render.txt"; + const renderPref = getLatestFile(prefsDir, prefsSuffix); + if (renderPref) { + const txt = fs.readFileSync(path.join(prefsDir, renderPref), { + encoding: "utf-8", + }); + const lines = txt.match(/[^\r\n]+/g); + if (lines) { + const firstLine = lines.findIndex((line) => + line.includes("Render Settings List") + ); + const lastLine = lines.findIndex((line) => + line.includes("Still Frame RS Index") + ); + const settingBlock = lines + .slice(firstLine, lastLine) + .join("") + .trim() + .replace(/^.*\=/g, "") + .replace(/\t/g, "") + .replace(/\\/g, "") + .replace(/\"\"/g, ""); + let renderSettings: string[] = []; + settingBlock.match(/\".*?\"/g)?.map((str) => { + if (str && !str.includes("_HIDDEN X-Factor")) { + renderSettings.push(str.replace(/\"/g, "")); + } + }); + return renderSettings; + } + } + return []; +}; diff --git a/AdminPanel/plugins/utils/utils/bolt.ts b/AdminPanel/plugins/utils/utils/bolt.ts new file mode 100644 index 0000000..b877539 --- /dev/null +++ b/AdminPanel/plugins/utils/utils/bolt.ts @@ -0,0 +1,253 @@ +import CSInterface from "../cep/csinterface"; +import Vulcan, { VulcanMessage } from "../cep/vulcan"; +import { ns } from "../../../shared/shared"; +import { fs } from "../cep/node"; + +export const csi = new CSInterface(); +export const vulcan = new Vulcan(); + +// jsx utils + +/** + * @function EvalES + * Evaluates a string in ExtendScript scoped to the project's namespace + * Optionally, pass true to the isGlobal param to avoid scoping + * + * @param script The script as a string to be evaluated + * @param isGlobal Optional. Defaults to false, + * + * @return String Result. + */ + +export const evalES = (script: string, isGlobal = false): Promise => { + return new Promise(function (resolve, reject) { + const pre = isGlobal + ? "" + : `var host = typeof $ !== 'undefined' ? $ : window; host["${ns}"].`; + const fullString = pre + script; + csi.evalScript( + "try{" + fullString + "}catch(e){alert(e);}", + (res: string) => { + resolve(res); + } + ); + }); +}; + +import type { Scripts } from "@esTypes/index"; + +type ArgTypes = F extends (...args: infer A) => any + ? A + : never; +type ReturnType = F extends (...args: infer A) => infer B + ? B + : never; + +/** + * @description End-to-end type-safe ExtendScript evaluation with error handling + * Call ExtendScript functions from CEP with type-safe parameters and return types. + * Any ExtendScript errors are captured and logged to the CEP console for tracing + * + * @param functionName The name of the function to be evaluated. + * @param args the list of arguments taken by the function. + * + * @return Promise resolving to function native return type. + * + * @example + * // CEP + * evalTS("myFunc", 60, 'test').then((res) => { + * console.log(res.word); + * }); + * + * // ExtendScript + * export const myFunc = (num: number, word: string) => { + * return { num, word }; + * } + * + */ + +export const evalTS = < + Key extends string & keyof Scripts, + Func extends Function & Scripts[Key] +>( + functionName: Key, + ...args: ArgTypes +): Promise> => { + return new Promise(function (resolve, reject) { + const formattedArgs = args + .map((arg) => { + console.log(JSON.stringify(arg)); + return `${JSON.stringify(arg)}`; + }) + .join(","); + csi.evalScript( + `try{ + var host = typeof $ !== 'undefined' ? $ : window; + var res = host["${ns}"].${functionName}(${formattedArgs}); + JSON.stringify(res); + }catch(e){ + e.fileName = new File(e.fileName).fsName; + JSON.stringify(e); + }`, + (res: string) => { + try { + //@ts-ignore + if (res === "undefined") return resolve(); + const parsed = JSON.parse(res); + if (parsed.name === "ReferenceError") { + console.error("REFERENCE ERROR"); + reject(parsed); + } else { + resolve(parsed); + } + } catch (error) { + reject(res); + } + } + ); + }); +}; + +export const evalFile = (file: string) => { + return evalES( + "typeof $ !== 'undefined' ? $.evalFile(\"" + + file + + '") : fl.runScript(FLfile.platformPathToURI("' + + file + + '"));', + true + ); +}; + +// js utils + +export const initBolt = (log = true) => { + if (window.cep) { + const extRoot = csi.getSystemPath("extension"); + const jsxSrc = `${extRoot}/jsx/index.js`; + const jsxBinSrc = `${extRoot}/jsx/index.jsxbin`; + if (fs.existsSync(jsxSrc)) { + if (log) console.log(jsxSrc); + evalFile(jsxSrc); + } else if (fs.existsSync(jsxBinSrc)) { + if (log) console.log(jsxBinSrc); + evalFile(jsxBinSrc); + } + } +}; + +export const posix = (str: string) => str.replace(/\\/g, "/"); + +export const openLinkInBrowser = (url: string) => { + if (window.cep) { + csi.openURLInDefaultBrowser(url); + } else { + location.href = url; + } +}; + +export const getAppBackgroundColor = () => { + const { green, blue, red } = JSON.parse( + window.__adobe_cep__.getHostEnvironment() as string + ).appSkinInfo.panelBackgroundColor.color; + return { + rgb: { + r: red, + g: green, + b: blue, + }, + hex: `#${red.toString(16)}${green.toString(16)}${blue.toString(16)}`, + }; +}; + +export const subscribeBackgroundColor = (callback: (color: string) => void) => { + const getColor = () => { + const newColor = getAppBackgroundColor(); + console.log("BG Color Updated: ", { rgb: newColor.rgb }); + const { r, g, b } = newColor.rgb; + return `rgb(${r}, ${g}, ${b})`; + }; + // get current color + callback(getColor()); + // listen for changes + csi.addEventListener( + "com.adobe.csxs.events.ThemeColorChanged", + () => callback(getColor()), + {} + ); +}; + +// vulcan + +declare type IVulcanMessageObject = { + event: string; + callbackID?: string; + data?: string | null; + payload?: object; +}; + +export const vulcanSend = (id: string, msgObj: IVulcanMessageObject) => { + const msg = new VulcanMessage(VulcanMessage.TYPE_PREFIX + id, null, null); + const msgStr = JSON.stringify(msgObj); + msg.setPayload(msgStr); + vulcan.dispatchMessage(msg); +}; + +export const vulcanListen = (id: string, callback: Function) => { + vulcan.addMessageListener( + VulcanMessage.TYPE_PREFIX + id, + (res: any) => { + var msgStr = vulcan.getPayload(res); + const msgObj = JSON.parse(msgStr); + callback(msgObj); + }, + null + ); +}; + +export const isAppRunning = (targetSpecifier: string) => { + const { major, minor, micro } = csi.getCurrentApiVersion(); + const version = parseFloat(`${major}.${minor}`); + if (version >= 11.2) { + return vulcan.isAppRunningEx(targetSpecifier.toUpperCase()); + } else { + return vulcan.isAppRunning(targetSpecifier); + } +}; + +interface IOpenDialogResult { + data: string[]; +} +export const selectFolder = ( + dir: string, + msg: string, + callback: (res: string) => void +) => { + const result = window.cep.fs.showOpenDialog( + false, + true, + msg, + dir + ) as IOpenDialogResult; + if (result.data?.length > 0) { + const folder = decodeURIComponent(result.data[0].replace("file://", "")); + callback(folder); + } +}; + +export const selectFile = ( + dir: string, + msg: string, + callback: (res: string) => void +) => { + const result = window.cep.fs.showOpenDialog( + false, + false, + msg, + dir + ) as IOpenDialogResult; + if (result.data?.length > 0) { + const folder = decodeURIComponent(result.data[0].replace("file://", "")); + callback(folder); + } +}; diff --git a/AdminPanel/plugins/utils/utils/cep.ts b/AdminPanel/plugins/utils/utils/cep.ts new file mode 100644 index 0000000..f3ed884 --- /dev/null +++ b/AdminPanel/plugins/utils/utils/cep.ts @@ -0,0 +1,28 @@ +import { csi } from "./bolt"; + +/** + * Register all possible keyboard shortcuts on Mac and Windows for you CEP Panel + * Warning: Note that certain keys will not work per OS regardless of registration + */ + +export const keyRegisterOverride = () => { + const platform = navigator.platform.substring(0, 3); + let maxKey = 0; + if (platform === "Mac") maxKey = 126; // Mac Max Key Code + else if (platform === "Win") maxKey = 222; // HTML Max Key Code + let allKeys = []; + for (let k = 0; k <= maxKey; k++) { + for (let j = 0; j <= 15; j++) { + const guide = (j >>> 0).toString(2).padStart(4, "0"); + allKeys.push({ + keyCode: k, + ctrlKey: guide[0] === "1", + altKey: guide[1] === "1", + shiftKey: guide[2] === "1", + metaKey: guide[3] === "1", + }); + } + } + const keyRes = csi.registerKeyEventsInterest(JSON.stringify(allKeys)); + console.log("Key Events Registered Completed: " + keyRes); +}; diff --git a/AdminPanel/plugins/utils/utils/ppro.ts b/AdminPanel/plugins/utils/utils/ppro.ts new file mode 100644 index 0000000..17f7952 --- /dev/null +++ b/AdminPanel/plugins/utils/utils/ppro.ts @@ -0,0 +1,175 @@ +import { fs, os, path } from "../cep/node"; +import { csi } from "./bolt"; + +const readDirSafe = (dir: string) => + fs.existsSync(dir) ? fs.readdirSync(dir) : []; + +export const getAllLuts = (): { creative: string[]; technical: string[] } => { + const isWin = os.platform() === "win32"; + + const appPath = path.dirname(csi.getSystemPath("hostApplication")); + const appLutsDir = path.join( + isWin ? appPath : path.dirname(appPath), + "Lumetri", + "LUTs" + ); + + const winLocal = path.join( + os.homedir(), + "AppData", + "Roaming", + "Adobe", + "Common", + "LUTs" + ); + const winGlobal = path.join("C:", "Program Files", "Adobe", "Common", "LUTs"); + const macLocal = path.join( + os.homedir(), + "Library", + "Application Support", + "Adobe", + "Common", + "LUTs" + ); + const macGlobal = path.join( + "Library", + "Application Support", + "Adobe", + "Common", + "LUTs" + ); + + const appCreative = path.join(appLutsDir, "Creative"); + const appTechnical = path.join(appLutsDir, "Technical"); + const localCreative = isWin + ? path.join(winLocal, "Creative") + : path.join(macLocal, "Creative"); + const localTechnical = isWin + ? path.join(winLocal, "Technical") + : path.join(macLocal, "Technical"); + const globalCreative = isWin + ? path.join(winGlobal, "Creative") + : path.join(macGlobal, "Creative"); + const globalTechnical = isWin + ? path.join(winGlobal, "Technical") + : path.join(macGlobal, "Technical"); + + const appCreativeLuts = readDirSafe(appCreative); + const appTechnicalLuts = readDirSafe(appTechnical); + + const localCreativeLuts = readDirSafe(localCreative); + const localTechnicalLuts = readDirSafe(localTechnical); + const globalCreativeLuts = readDirSafe(globalCreative); + const globalTechnicalLuts = readDirSafe(globalTechnical); + const creative = [ + ...appCreativeLuts, + ...localCreativeLuts, + ...globalCreativeLuts, + ] + .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())) + .map((lut) => path.basename(lut, path.extname(lut))); + const technical = [ + ...appTechnicalLuts, + ...localTechnicalLuts, + ...globalTechnicalLuts, + ] + .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())) + .map((lut) => path.basename(lut, path.extname(lut))); + + return { creative, technical }; +}; + +export const allowedImportFiles: string[] = [ + "264", + "3g2", + "3gp", + "3gpp", + "aac", + "aaf", + "ac3", + "ai", + "aif", + "aiff", + "ari", + "asf", + "asnd", + "asx", + "avc", + "avi", + "bmp", + "bwf", + "cin", + "cine", + "crm", + "dfxp", + "dib", + "dif", + "dng", + "dpx", + "dv", + "eps", + "exr", + "f4v", + "f4v", + "fli", + "gif", + "icb", + "ico", + "jfif", + "jpe", + "jpeg", + "jpg", + "m15", + "m1a", + "m1s", + "m1v", + "m2a", + "m2p", + "m2t", + "m2ts", + "m2v", + "m4a", + "m4v", + "m75", + "mcc", + "m0d", + "mov", + "mp2", + "mp3", + "mp4", + "mpa", + "mpe", + "mpeg", + "mpg", + "mpg4", + "mpm", + "mpv", + "mts", + "mxf", + "mxv", + "mxr", + "pct", + "pict", + "png", + "prt", + "ptl", + "qt", + "r3d", + "rle", + "rmf", + "scc", + "srt", + "stl", + "sxr", + "tga", + "tif", + "tiff", + "ts", + "vda", + "vob", + "vst", + "wav", + "wma", + "wmv", + "psd", +]; diff --git a/Server/Designer/CSInterface.js b/AdminPanel/public/CSInterface.js similarity index 100% rename from Server/Designer/CSInterface.js rename to AdminPanel/public/CSInterface.js diff --git a/test_unzip/vite.svg b/AdminPanel/public/vite.svg similarity index 100% rename from test_unzip/vite.svg rename to AdminPanel/public/vite.svg diff --git a/AdminPanel/src/App.vue b/AdminPanel/src/App.vue new file mode 100644 index 0000000..7f5a458 --- /dev/null +++ b/AdminPanel/src/App.vue @@ -0,0 +1,35 @@ + + + + + + diff --git a/AdminPanel/src/hooks/useTheme.ts b/AdminPanel/src/hooks/useTheme.ts new file mode 100644 index 0000000..68e6ffb --- /dev/null +++ b/AdminPanel/src/hooks/useTheme.ts @@ -0,0 +1,40 @@ +import { ref, onMounted, onUnmounted } from 'vue'; +import { initThemeListener } from '@/utils/theme'; + +export function useTheme() { + const isDark = ref(true); + + // 简易的判断当前是否是深色主题的逻辑 + // 实际逻辑由 utils/theme.ts 中的 updateTheme 处理,它会更新 body 的 arco-theme 属性 + const checkTheme = () => { + isDark.value = document.body.getAttribute('arco-theme') === 'dark'; + }; + + onMounted(() => { + // 初始化并开始监听 + initThemeListener(); + + // 初始检查 + checkTheme(); + + // 监听 body 属性变化 (以便在 theme.ts 更新 body 属性时我们能感知到) + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.type === 'attributes' && mutation.attributeName === 'arco-theme') { + checkTheme(); + } + }); + }); + + observer.observe(document.body, { attributes: true }); + + // Cleanup + onUnmounted(() => { + observer.disconnect(); + }); + }); + + return { + isDark + }; +} diff --git a/AdminPanel/src/main.ts b/AdminPanel/src/main.ts new file mode 100644 index 0000000..62bfcb1 --- /dev/null +++ b/AdminPanel/src/main.ts @@ -0,0 +1,20 @@ +import { createApp } from 'vue' +import App from './App.vue' +import router from './router' +import ArcoVue from '@arco-design/web-vue' +import '@arco-design/web-vue/dist/arco.css' +import './style/index' +import { initThemeListener } from './utils/theme' + +const app = createApp(App) + +app.use(ArcoVue) +app.use(router) + +app.mount('#app') + +// 初始化 PS 主题监听(自动跟随 PS 主题变换颜色) +initThemeListener() + +console.log('🎨 Designer Admin Panel 已启动') + diff --git a/AdminPanel/src/router/index.ts b/AdminPanel/src/router/index.ts new file mode 100644 index 0000000..63452cc --- /dev/null +++ b/AdminPanel/src/router/index.ts @@ -0,0 +1,22 @@ +import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router' + +const routes: RouteRecordRaw[] = [ + { + path: '/', + name: 'Home', + component: () => import('@/view/Home.vue') + }, + { + path: '/iframe', + name: 'IframePage', + component: () => import('@/view/IframePage.vue') + } +] + +const router = createRouter({ + history: createWebHashHistory(), + routes +}) + +export default router + diff --git a/AdminPanel/src/style/base/flex.css b/AdminPanel/src/style/base/flex.css new file mode 100644 index 0000000..ec6d2f3 --- /dev/null +++ b/AdminPanel/src/style/base/flex.css @@ -0,0 +1,130 @@ +/* flex 布局的定义 + ========================================================================== */ + + +/* 基础样式 , 从左到右,不压缩子元素,超出则换行排列 */ + +.f-base { + display: flex; + flex-flow: row wrap; + align-content: flex-start; +} + + +/* 基础样式,垂直居中,从左到右排序 会压缩子元素*/ + +.f-baseX { + display: flex; + align-items: center; +} + + +/* 基础样式,从上到下排序元素 */ + +.f-baseY { + display: flex; + flex-direction: column; + flex-wrap: nowrap; + align-items: center; +} + +.f-baseLR { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.f-arrayX { + display: flex; + flex-direction: row; +} + + +/* 横向排列 */ + +.f-arrayY { + display: flex; + display: -webkit-flex; + flex-direction: column; +} + +.f-alignNone { + display: flex; + display: -webkit-flex; + justify-content: space-between; +} + + +/* 上下左右居中 */ + +.f-center { + display: flex; + justify-content: center; + align-items: center; +} + + +/* 不压缩所有子元素 */ + +.f-allFull { + flex-flow: row wrap; + align-content: center; +} + + +/* 水平对齐方向 向左对齐 */ + +.f-levelL { + justify-content: flex-start; +} + + +/* 水平对齐方向 居中对齐 */ + +.f-levelC { + justify-content: center; +} + + +/* 水平对齐方向 向右对齐 */ + +.f-levelR { + justify-content: flex-end; +} + + +/* 控制垂直对齐方式 上对齐 */ + +.f-verticalT { + align-items: flex-start; +} + + +/* 控制垂直对齐方式 居中 */ + +.f-verticalC { + display: flex; + align-items: center; +} + + +/* 控制垂直对齐方式 下对齐 */ + +.f-verticalB { + display: flex; + align-items: flex-end; +} + + +/* 这个用在子元素,用于分配剩余空间 */ + +.f-space { + flex-grow: 1; +} + + +/* 不压缩子元素,既保留元素的完整大小,应用在元素身上 */ + +.f-full { + flex-shrink: 0; +} \ No newline at end of file diff --git a/AdminPanel/src/style/base/flex.less b/AdminPanel/src/style/base/flex.less new file mode 100644 index 0000000..b1e2c6c --- /dev/null +++ b/AdminPanel/src/style/base/flex.less @@ -0,0 +1,228 @@ +/* 基础样式 , 从左到右,不压缩子元素,超出不换行*/ + +.f-lr { + display: flex; + align-content: flex-start; + > * { + flex-shrink: 0; + } +} + +/* 基础样式 , 从右到左,不压缩子元素,超出不换行*/ + +.f-rl { + display: flex; + align-content: flex-start; + flex-direction: row-reverse; + > * { + flex-shrink: 0; + } +} + +/* 从左到右,上下居中,超出不换行*/ + +.f-lr-center { + display: flex; + align-items: center; + > * { + flex-shrink: 0; + } +} + +/* 从右到左,上下居中,超出不换行*/ + +.f-rl-center { + display: flex; + align-items: center; + flex-direction: row-reverse; + > * { + flex-shrink: 0; + } +} + +/* 基础样式 , 从左到右,不压缩子元素,超出则自动换行 */ + +.f-lr-wrap { + display: flex; + align-content: flex-start; + flex-flow: row wrap; + > * { + flex-shrink: 0; + } +} + +/* 基础样式 , 从右到左,不压缩子元素,超出则自动换行 */ + +.f-rl-wrap { + display: flex; + align-content: flex-start; + flex-flow: row-reverse wrap; + > * { + flex-shrink: 0; + } +} + +/*横向左右均匀分布 不压缩子元素 (元素间距离平均分配)*/ +.f-lr-evenly { + display: flex; + flex-direction: row; + justify-content: space-evenly; + > * { + flex-shrink: 0; + } +} + +/*横向左右均匀分布 从右到左 不压缩子元素 (元素间距离平均分配)*/ +.f-rl-evenly { + display: flex; + flex-direction: row; + justify-content: space-evenly; + flex-direction: row-reverse; + > * { + flex-shrink: 0; + } +} +/*左中右分布 左到右 (第一个元素靠起点,最后一个元素靠终点,余下元素平均分配空间)*/ +.f-lr-between { + display: flex; + flex-direction: row; + justify-content: space-between; + > * { + flex-shrink: 0; + } +} + +/*左中右分布 右到左 (第一个元素靠起点,最后一个元素靠终点,余下元素平均分配空间)*/ +.f-rl-between { + display: flex; + flex-direction: row; + justify-content: space-between; + flex-direction: row-reverse; + > * { + flex-shrink: 0; + } +} +/*纵向上下分布 不压缩子元素*/ +.f-tb { + display: flex; + flex-flow: column nowrap; + > * { + flex-shrink: 0; + } +} +/*纵向上下分布 从下到上 不压缩子元素*/ +.f-bt { + display: flex; + flex-flow: column-reverse nowrap; + > * { + flex-shrink: 0; + } +} +/*纵向上下分布 左右居中 不压缩子元素*/ +.f-tb-center { + display: flex; + align-items: center; + flex-flow: column nowrap; + > * { + flex-shrink: 0; + } +} + +/*纵向上下分布 从下到上 左右居中 不压缩子元素*/ +.f-bt-center { + display: flex; + align-items: center; + flex-flow: column-reverse nowrap; + > * { + flex-shrink: 0; + } +} + +// 纵向上下分布 ,不压缩子元素,超出则自动换行 +.f-tb-wrap { + display: flex; + align-content: flex-start; + flex-flow: column wrap; + > * { + flex-shrink: 0; + } +} + +// 纵向上下分布 ,从下到上,不压缩子元素,超出则自动换行 +.f-bt-wrap { + display: flex; + align-content: flex-start; + flex-flow: column-reverse wrap; + > * { + flex-shrink: 0; + } +} + +// 纵向上下均匀分布 不压缩子元素 (元素间距离平均分配) +.f-tb-evenly { + display: flex; + flex-flow: column nowrap; + justify-content: space-evenly; + > * { + flex-shrink: 0; + } +} + +// 纵向上下均匀分布 不压缩子元素 (元素间距离平均分配) +.f-bt-evenly { + display: flex; + flex-flow: column-reverse nowrap; + justify-content: space-evenly; + > * { + flex-shrink: 0; + } +} + +// 纵向上下分布 上到下  (第一个元素靠起点,最后一个元素靠终点,余下元素平均分配空间) +.f-tb-between { + display: flex; + flex-flow: column nowrap; + justify-content: space-between; + > * { + flex-shrink: 0; + } +} + +// 纵向上下分布 上到下  (第一个元素靠起点,最后一个元素靠终点,余下元素平均分配空间) +.f-bt-between { + display: flex; + flex-flow: column-reverse nowrap; + justify-content: space-between; + > * { + flex-shrink: 0; + } +} + +/*垂直水平居中*/ +.f-center { + display: flex; + justify-content: center; + align-items: center; + > * { + flex-shrink: 0; + } +} + +/* 元素在主交叉轴上的对齐方式——居中 */ +.f-align-center { + align-items: center; +} + +/*自动填充剩余空间*/ +.f-space { + flex-grow: 1; + flex-shrink: 1; +} + +.f-full { + flex-shrink: 0; +} + +.f-shrink { + flex-shrink: 1; +} diff --git a/AdminPanel/src/style/base/layout.less b/AdminPanel/src/style/base/layout.less new file mode 100644 index 0000000..7ae3f1b --- /dev/null +++ b/AdminPanel/src/style/base/layout.less @@ -0,0 +1,1605 @@ +/* 常用各种基础样式定义 + +/* 宽度 */ + +.w0 { + width: 0%; +} + +.w5 { + width: 5%; +} + +.w10 { + width: 10%; +} + +.w15 { + width: 15%; +} + +.w20 { + width: 20%; +} + +.w25 { + width: 25%; +} + +.w30 { + width: 30%; +} + +.w35 { + width: 35%; +} + +.w40 { + width: 40%; +} + +.w45 { + width: 45%; +} + +.w50 { + width: 50%; +} + +.w55 { + width: 55%; +} + +.w60 { + width: 60%; +} + +.w65 { + width: 65%; +} + +.w70 { + width: 70%; +} + +.w75 { + width: 75% !important; +} + +.w80 { + width: 80% !important; +} + +.w85 { + width: 85% !important; +} + +.w90 { + width: 90% !important; +} + +.w95 { + width: 95% !important; +} + +.w100 { + width: 100% !important; +} +.h10 { + height: 10%; +} +.h20 { + height: 20%; +} +.h30 { + height: 30%; +} +.h40 { + height: 40%; +} +.h50 { + height: 50%; +} +.h60 { + height: 60%; +} +.h70 { + height: 70%; +} +.h80 { + height: 80%; +} +.h90 { + height: 90%; +} +.h95 { + height:95%; +} +.h100{ + height:100% +} + + +/* ========================================================================== */ + +.ml0 { + margin-left: 0px; +} + +.ml1 { + margin-left: 1px; +} + +.ml2 { + margin-left: 2px; +} + +.ml3 { + margin-left: 3px; +} + +.ml4 { + margin-left: 4px; +} + +.ml5 { + margin-left: 5px; +} + +.ml6 { + margin-left: 6px; +} + +.ml7 { + margin-left: 7px; +} + +.ml8 { + margin-left: 8px; +} + +.ml9 { + margin-left: 9px; +} + +.ml10 { + margin-left: 10px; +} + +.ml11 { + margin-left: 11px; +} + +.ml12 { + margin-left: 12px; +} + +.ml13 { + margin-left: 13px; +} + +.ml14 { + margin-left: 14px; +} + +.ml15 { + margin-left: 15px; +} + +.ml16 { + margin-left: 16px; +} + +.ml17 { + margin-left: 17px; +} + +.ml18 { + margin-left: 18px; +} + +.ml19 { + margin-left: 19px; +} + +.ml20 { + margin-left: 20px; +} + +.ml21 { + margin-left: 21px; +} + +.ml22 { + margin-left: 22px; +} + +.ml23 { + margin-left: 23px; +} + +.ml24 { + margin-left: 24px; +} + +.ml25 { + margin-left: 25px; +} + +.ml26 { + margin-left: 26px; +} + +.ml27 { + margin-left: 27px; +} + +.ml28 { + margin-left: 28px; +} + +.ml29 { + margin-left: 29px; +} + +.ml30 { + margin-left: 30px; +} + +.ml31 { + margin-left: 31px; +} + +.ml32 { + margin-left: 32px; +} + +.ml33 { + margin-left: 33px; +} + +.ml34 { + margin-left: 34px; +} + +.ml35 { + margin-left: 35px; +} + +.ml36 { + margin-left: 36px; +} + +.ml37 { + margin-left: 37px; +} + +.ml38 { + margin-left: 38px; +} + +.ml39 { + margin-left: 39px; +} + +.ml40 { + margin-left: 40px; +} + +.ml41 { + margin-left: 41px; +} + +.ml42 { + margin-left: 42px; +} + +.ml43 { + margin-left: 43px; +} + +.ml44 { + margin-left: 44px; +} + +.ml45 { + margin-left: 45px; +} + +.ml46 { + margin-left: 46px; +} + +.ml47 { + margin-left: 47px; +} + +.ml48 { + margin-left: 48px; +} + +.ml49 { + margin-left: 49px; +} + +.ml50 { + margin-left: 50px; +} + + +/* ========================================================================== */ + +.mr0 { + margin-right: 0px !important; +} + +.mr1 { + margin-right: 1px; +} + +.mr2 { + margin-right: 2px; +} + +.mr3 { + margin-right: 3px; +} + +.mr4 { + margin-right: 4px; +} + +.mr5 { + margin-right: 5px; +} + +.mr6 { + margin-right: 6px; +} + +.mr7 { + margin-right: 7px; +} + +.mr8 { + margin-right: 8px; +} + +.mr9 { + margin-right: 9px; +} + +.mr10 { + margin-right: 10px; +} + +.mr11 { + margin-right: 11px; +} + +.mr12 { + margin-right: 12px; +} + +.mr13 { + margin-right: 13px; +} + +.mr14 { + margin-right: 14px; +} + +.mr15 { + margin-right: 15px; +} + +.mr16 { + margin-right: 16px; +} + +.mr17 { + margin-right: 17px; +} + +.mr18 { + margin-right: 18px; +} + +.mr19 { + margin-right: 19px; +} + +.mr20 { + margin-right: 20px; +} + +.mr21 { + margin-right: 21px; +} + +.mr22 { + margin-right: 22px; +} + +.mr23 { + margin-right: 23px; +} + +.mr24 { + margin-right: 24px; +} + +.mr25 { + margin-right: 25px; +} + +.mr26 { + margin-right: 26px; +} + +.mr27 { + margin-right: 27px; +} + +.mr28 { + margin-right: 28px; +} + +.mr29 { + margin-right: 29px; +} + +.mr30 { + margin-right: 30px; +} + +.mr31 { + margin-right: 31px; +} + +.mr32 { + margin-right: 32px; +} + +.mr33 { + margin-right: 33px; +} + +.mr34 { + margin-right: 34px; +} + +.mr35 { + margin-right: 35px; +} + +.mr36 { + margin-right: 36px; +} + +.mr37 { + margin-right: 37px; +} + +.mr38 { + margin-right: 38px; +} + +.mr39 { + margin-right: 39px; +} + +.mr40 { + margin-right: 40px; +} + +.mr41 { + margin-right: 41px; +} + +.mr42 { + margin-right: 42px; +} + +.mr43 { + margin-right: 43px; +} + +.mr44 { + margin-right: 44px; +} + +.mr45 { + margin-right: 45px; +} + +.mr46 { + margin-right: 46px; +} + +.mr47 { + margin-right: 47px; +} + +.mr48 { + margin-right: 48px; +} + +.mr49 { + margin-right: 49px; +} + +.mr50 { + margin-right: 50px; +} + + +/* ========================================================================== */ + +.mt0 { + margin-top: 0px; +} + +.mt1 { + margin-top: 1px; +} + +.mt2 { + margin-top: 2px; +} + +.mt3 { + margin-top: 3px; +} + +.mt4 { + margin-top: 4px; +} + +.mt5 { + margin-top: 5px; +} + +.mt6 { + margin-top: 6px; +} + +.mt7 { + margin-top: 7px; +} + +.mt8 { + margin-top: 8px; +} + +.mt9 { + margin-top: 9px; +} + +.mt10 { + margin-top: 10px; +} + +.mt11 { + margin-top: 11px; +} + +.mt12 { + margin-top: 12px; +} + +.mt13 { + margin-top: 13px; +} + +.mt14 { + margin-top: 14px; +} + +.mt15 { + margin-top: 15px; +} + +.mt16 { + margin-top: 16px; +} + +.mt17 { + margin-top: 17px; +} + +.mt18 { + margin-top: 18px; +} + +.mt19 { + margin-top: 19px; +} + +.mt20 { + margin-top: 20px; +} + +.mt21 { + margin-top: 21px; +} + +.mt22 { + margin-top: 22px; +} + +.mt23 { + margin-top: 23px; +} + +.mt24 { + margin-top: 24px; +} + +.mt25 { + margin-top: 25px; +} + +.mt26 { + margin-top: 26px; +} + +.mt27 { + margin-top: 27px; +} + +.mt28 { + margin-top: 28px; +} + +.mt29 { + margin-top: 29px; +} + +.mt30 { + margin-top: 30px; +} + +.mt31 { + margin-top: 31px; +} + +.mt32 { + margin-top: 32px; +} + +.mt33 { + margin-top: 33px; +} + +.mt34 { + margin-top: 34px; +} + +.mt35 { + margin-top: 35px; +} + +.mt36 { + margin-top: 36px; +} + +.mt37 { + margin-top: 37px; +} + +.mt38 { + margin-top: 38px; +} + +.mt39 { + margin-top: 39px; +} + +.mt40 { + margin-top: 40px; +} + +.mt41 { + margin-top: 41px; +} + +.mt42 { + margin-top: 42px; +} + +.mt43 { + margin-top: 43px; +} + +.mt44 { + margin-top: 44px; +} + +.mt45 { + margin-top: 45px; +} + +.mt46 { + margin-top: 46px; +} + +.mt47 { + margin-top: 47px; +} + +.mt48 { + margin-top: 48px; +} + +.mt49 { + margin-top: 49px; +} + +.mt50 { + margin-top: 50px; +} + +.mt60 { + margin-top: 60px; +} + +.mt70 { + margin-top: 70px; +} + +.mt80 { + margin-top: 80px; +} + +.mt90 { + margin-top: 90px; +} + +.mt100 { + margin-top: 100px; +} + + +/* ========================================================================== */ + +.mb0 { + margin-bottom: 0px; +} + +.mb1 { + margin-bottom: 1px; +} + +.mb2 { + margin-bottom: 2px; +} + +.mb3 { + margin-bottom: 3px; +} + +.mb4 { + margin-bottom: 4px; +} + +.mb5 { + margin-bottom: 5px; +} + +.mb6 { + margin-bottom: 6px; +} + +.mb7 { + margin-bottom: 7px; +} + +.mb8 { + margin-bottom: 8px; +} + +.mb9 { + margin-bottom: 9px; +} + +.mb10 { + margin-bottom: 10px; +} + +.mb11 { + margin-bottom: 11px; +} + +.mb12 { + margin-bottom: 12px; +} + +.mb13 { + margin-bottom: 13px; +} + +.mb14 { + margin-bottom: 14px; +} + +.mb15 { + margin-bottom: 15px; +} + +.mb16 { + margin-bottom: 16px; +} + +.mb17 { + margin-bottom: 17px; +} + +.mb18 { + margin-bottom: 18px; +} + +.mb19 { + margin-bottom: 19px; +} + +.mb20 { + margin-bottom: 20px; +} + +.mb21 { + margin-bottom: 21px; +} + +.mb22 { + margin-bottom: 22px; +} + +.mb23 { + margin-bottom: 23px; +} + +.mb24 { + margin-bottom: 24px; +} + +.mb25 { + margin-bottom: 25px; +} + +.mb26 { + margin-bottom: 26px; +} + +.mb27 { + margin-bottom: 27px; +} + +.mb28 { + margin-bottom: 28px; +} + +.mb29 { + margin-bottom: 29px; +} + +.mb30 { + margin-bottom: 30px; +} + +.mb31 { + margin-bottom: 31px; +} + +.mb32 { + margin-bottom: 32px; +} + +.mb33 { + margin-bottom: 33px; +} + +.mb34 { + margin-bottom: 34px; +} + +.mb35 { + margin-bottom: 35px; +} + +.mb36 { + margin-bottom: 36px; +} + +.mb37 { + margin-bottom: 37px; +} + +.mb38 { + margin-bottom: 38px; +} + +.mb39 { + margin-bottom: 39px; +} + +.mb40 { + margin-bottom: 40px; +} + +.mb41 { + margin-bottom: 41px; +} + +.mb42 { + margin-bottom: 42px; +} + +.mb43 { + margin-bottom: 43px; +} + +.mb44 { + margin-bottom: 44px; +} + +.mb45 { + margin-bottom: 45px; +} + +.mb46 { + margin-bottom: 46px; +} + +.mb47 { + margin-bottom: 47px; +} + +.mb48 { + margin-bottom: 48px; +} + +.mb49 { + margin-bottom: 49px; +} + +.mb50 { + margin-bottom: 50px; +} + + +/* ========================================================================== */ + +.plr0 { + padding-left: 0px; + padding-right: 0px; +} + +.plr1 { + padding-left: 1px; + padding-right: 1px; +} + +.plr2 { + padding-left: 2px; + padding-right: 2px; +} + +.plr3 { + padding-left: 3px; + padding-right: 3px; +} + +.plr4 { + padding-left: 4px; + padding-right: 4px; +} + +.plr5 { + padding-left: 5px; + padding-right: 5px; +} + +.plr6 { + padding-left: 6px; + padding-right: 6px; +} + +.plr7 { + padding-left: 7px; + padding-right: 7px; +} + +.plr8 { + padding-left: 8px; + padding-right: 8px; +} + +.plr9 { + padding-left: 9px; + padding-right: 9px; +} + +.plr10 { + padding-left: 10px; + padding-right: 10px; +} + +.plr11 { + padding-left: 11px; + padding-right: 11px; +} + +.plr12 { + padding-left: 12px; + padding-right: 12px; +} + +.plr13 { + padding-left: 13px; + padding-right: 13px; +} + +.plr14 { + padding-left: 14px; + padding-right: 14px; +} + +.plr15 { + padding-left: 15px; + padding-right: 15px; +} + +.plr16 { + padding-left: 16px; + padding-right: 16px; +} + +.plr17 { + padding-left: 17px; + padding-right: 17px; +} + +.plr18 { + padding-left: 18px; + padding-right: 18px; +} + +.plr19 { + padding-left: 19px; + padding-right: 19px; +} + +.plr20 { + padding-left: 20px; + padding-right: 20px; +} + +.plr21 { + padding-left: 21px; + padding-right: 21px; +} + +.plr22 { + padding-left: 22px; + padding-right: 22px; +} + +.plr23 { + padding-left: 23px; + padding-right: 23px; +} + +.plr24 { + padding-left: 24px; + padding-right: 24px; +} + +.plr25 { + padding-left: 25px; + padding-right: 25px; +} + +.plr26 { + padding-left: 26px; + padding-right: 26px; +} + +.plr27 { + padding-left: 27px; + padding-right: 27px; +} + +.plr28 { + padding-left: 28px; + padding-right: 28px; +} + +.plr29 { + padding-left: 29px; + padding-right: 29px; +} + +.plr30 { + padding-left: 30px; + padding-right: 30px; +} + +.plr31 { + padding-left: 31px; + padding-right: 31px; +} + +.plr32 { + padding-left: 32px; + padding-right: 32px; +} + +.plr33 { + padding-left: 33px; + padding-right: 33px; +} + +.plr34 { + padding-left: 34px; + padding-right: 34px; +} + +.plr35 { + padding-left: 35px; + padding-right: 35px; +} + +.plr36 { + padding-left: 36px; + padding-right: 36px; +} + +.plr37 { + padding-left: 37px; + padding-right: 37px; +} + +.plr38 { + padding-left: 38px; + padding-right: 38px; +} + +.plr39 { + padding-left: 39px; + padding-right: 39px; +} + +.plr40 { + padding-left: 40px; + padding-right: 40px; +} + +.plr41 { + padding-left: 41px; + padding-right: 41px; +} + +.plr42 { + padding-left: 42px; + padding-right: 42px; +} + +.plr43 { + padding-left: 43px; + padding-right: 43px; +} + +.plr44 { + padding-left: 44px; + padding-right: 44px; +} + +.plr45 { + padding-left: 45px; + padding-right: 45px; +} + +.plr46 { + padding-left: 46px; + padding-right: 46px; +} + +.plr47 { + padding-left: 47px; + padding-right: 47px; +} + +.plr48 { + padding-left: 48px; + padding-right: 48px; +} + +.plr49 { + padding-left: 49px; + padding-right: 49px; +} + +.plr50 { + padding-left: 50px; + padding-right: 50px; +} + + +/* ========================================================================== */ + + +/*对齐方式*/ + +.tal { + text-align: left; +} + +.tac { + text-align: center; +} + +.tar { + text-align: right; +} + +//==========================================定义图标大小================================ +.svg-default{ + width: 22px; + height: 22px; +} +.svg-0 { + width: 0px; + height: 0px; +} + +.svg-1 { + width: 1px; + height: 1px; +} + +.svg-2 { + width: 2px; + height: 2px; +} + +.svg-3 { + width: 3px; + height: 3px; +} + +.svg-4 { + width: 4px; + height: 4px; +} + +.svg-5 { + width: 5px; + height: 5px; +} + +.svg-6 { + width: 6px; + height: 6px; +} + +.svg-7 { + width: 7px; + height: 7px; +} + +.svg-8 { + width: 8px; + height: 8px; +} + +.svg-9 { + width: 9px; + height: 9px; +} + +.svg-10 { + width: 10px; + height: 10px; +} + +.svg-11 { + width: 11px; + height: 11px; +} + +.svg-12 { + width: 12px; + height: 12px; +} + +.svg-13 { + width: 13px; + height: 13px; +} + +.svg-14 { + width: 14px; + height: 14px; +} + +.svg-15 { + width: 15px; + height: 15px; +} + +.svg-16 { + width: 16px; + height: 16px; +} + +.svg-17 { + width: 17px; + height: 17px; +} + +.svg-18 { + width: 18px; + height: 18px; +} + +.svg-19 { + width: 19px; + height: 19px; +} + +.svg-20 { + width: 20px; + height: 20px; +} + +.svg-21 { + width: 21px; + height: 21px; +} + +.svg-22 { + width: 22px; + height: 22px; +} + +.svg-23 { + width: 23px; + height: 23px; +} + +.svg-24 { + width: 24px; + height: 24px; +} + +.svg-25 { + width: 25px; + height: 25px; +} + +.svg-26 { + width: 26px; + height: 26px; +} + +.svg-27 { + width: 27px; + height: 27px; +} + +.svg-28 { + width: 28px; + height: 28px; +} + +.svg-29 { + width: 29px; + height: 29px; +} + +.svg-30 { + width: 30px; + height: 30px; +} + +.svg-31 { + width: 31px; + height: 31px; +} + +.svg-32 { + width: 32px; + height: 32px; +} + +.svg-33 { + width: 33px; + height: 33px; +} + +.svg-34 { + width: 34px; + height: 34px; +} + +.svg-35 { + width: 35px; + height: 35px; +} + +.svg-36 { + width: 36px; + height: 36px; +} + +.svg-37 { + width: 37px; + height: 37px; +} + +.svg-38 { + width: 38px; + height: 38px; +} + +.svg-39 { + width: 39px; + height: 39px; +} + +.svg-40 { + width: 40px; + height: 40px; +} + +.svg-41 { + width: 41px; + height: 41px; +} + +.svg-42 { + width: 42px; + height: 42px; +} + +.svg-43 { + width: 43px; + height: 43px; +} + +.svg-44 { + width: 44px; + height: 44px; +} + +.svg-45 { + width: 45px; + height: 45px; +} + +.svg-46 { + width: 46px; + height: 46px; +} + +.svg-47 { + width: 47px; + height: 47px; +} + +.svg-48 { + width: 48px; + height: 48px; +} + +.svg-49 { + width: 49px; + height: 49px; +} + +.svg-50 { + width: 50px; + height: 50px; +} + +.f-size9 { + font-size: 9px; +} + +.f-size10 { + font-size: 10px; +} + +.f-size11 { + font-size: 11px; +} + +.f-size12 { + font-size: 12px; +} + +.f-size13 { + font-size: 13px; +} + +.f-size14 { + font-size: 14px; +} + +.f-size15 { + font-size: 15px; +} + +.f-size16 { + font-size: 16px; +} + +.f-size17 { + font-size: 17px; +} + +.f-size18 { + font-size: 18px; +} + +.f-size19 { + font-size: 19px; +} + +.f-size20 { + font-size: 20px; +} + +.f-size21 { + font-size: 21px; +} + +.f-size22 { + font-size: 22px; +} + +.f-size23 { + font-size: 23px; +} + +.f-size24 { + font-size: 24px; +} + +.f-size25 { + font-size: 25px; +} + +.f-size26 { + font-size: 26px; +} + +.f-size28 { + font-size: 28px; +} + +.f-size30 { + font-size: 30px; +} + +.f-size32 { + font-size: 32px; +} + +.f-size38 { + font-size: 38px; +} + +.f-size50 { + font-size: 50px; +} + +.f-size52 { + font-size: 52px; +} + + +/* 字体大小9到24 */ + +//======================透明度设置=========================== \ No newline at end of file diff --git a/AdminPanel/src/style/base/myReset.css b/AdminPanel/src/style/base/myReset.css new file mode 100644 index 0000000..33b6601 --- /dev/null +++ b/AdminPanel/src/style/base/myReset.css @@ -0,0 +1,14 @@ +* { + outline: none; + box-sizing: border-box; + margin: 0px; + padding: 0px; +} + +svg, +img { + -webkit-user-select: none; + -moz-user-select: none; + -o-user-select: none; + user-select: none; +} \ No newline at end of file diff --git a/AdminPanel/src/style/base/normalize.css b/AdminPanel/src/style/base/normalize.css new file mode 100644 index 0000000..b0d3f97 --- /dev/null +++ b/AdminPanel/src/style/base/normalize.css @@ -0,0 +1,424 @@ +/*! normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */ + +/** + * 1. Change the default font family in all browsers (opinionated). + * 2. Prevent adjustments of font size after orientation changes in IE and iOS. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + * 2. Add the correct display in IE. + */ + +article, +aside, +details, /* 1 */ +figcaption, +figure, +footer, +header, +main, /* 2 */ +menu, +nav, +section, +summary { /* 1 */ + display: block; +} + +/** + * Add the correct display in IE 9-. + */ + +audio, +canvas, +progress, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Add the correct display in IE 10-. + * 1. Add the correct display in IE. + */ + +template, /* 1 */ +[hidden] { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Remove the outline on focused links when they are also active or hovered + * in all browsers (opinionated). + */ + +a:active, +a:hover { + outline-width: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the bottom border in Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Add the correct background and color in IE 9-. + */ + +mark { + background-color: #ff0; + color: #000; +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct margin in IE 8. + */ + +figure { + margin: 1em 40px; +} + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/* Forms + ========================================================================== */ + +/** + * Change font properties to `inherit` in all browsers (opinionated). + */ + +button, +input, +select, +textarea { + font: inherit; +} + +/** + * Restore the font weight unset by the previous rule. + */ + +optgroup { + font-weight: bold; +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + * 2. Show the overflow in Edge, Firefox, and IE. + */ + +button, +input, /* 1 */ +select { /* 2 */ + overflow: visible; +} + +/** + * Remove the margin in Safari. + * 1. Remove the margin in Firefox and Safari. + */ + +button, +input, +select, +textarea { /* 1 */ + margin: 0; +} + +/** + * Remove the inheritence of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritence of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * Change the cursor in all browsers (opinionated). + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + cursor: pointer; +} + +/** + * Restore the default cursor to disabled elements unset by the previous rule. + */ + +[disabled] { + cursor: default; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS. + */ + +button, +html [type="button"], /* 1 */ +[type="reset"], +[type="submit"] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +input:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Change the border, margin, and padding in all browsers (opinionated). + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * Correct the odd appearance of search inputs in Chrome and Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; +} + +/** + * Remove the inner padding and cancel buttons in Chrome on OS X and + * Safari on OS X. + */ + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} diff --git a/AdminPanel/src/style/global.less b/AdminPanel/src/style/global.less new file mode 100644 index 0000000..e3a6b04 --- /dev/null +++ b/AdminPanel/src/style/global.less @@ -0,0 +1,37 @@ +// 全局样式 +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html, body { + width: 100%; + height: 100%; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; +} + +#app { + width: 100%; + height: 100%; +} + +// 滚动条样式 +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: #f1f1f1; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: #c1c1c1; + border-radius: 4px; + + &:hover { + background: #a1a1a1; + } +} diff --git a/AdminPanel/src/style/index.ts b/AdminPanel/src/style/index.ts new file mode 100644 index 0000000..dfed49d --- /dev/null +++ b/AdminPanel/src/style/index.ts @@ -0,0 +1,2 @@ +// 全局样式入口 +import './global.less' diff --git a/AdminPanel/src/style/theme/common.less b/AdminPanel/src/style/theme/common.less new file mode 100644 index 0000000..8bb3f43 --- /dev/null +++ b/AdminPanel/src/style/theme/common.less @@ -0,0 +1,3 @@ +@appPadding: 0px 16px; +@appBgColor: #202020; +@appTextColor: #fff; \ No newline at end of file diff --git a/AdminPanel/src/style/theme/theme.ts b/AdminPanel/src/style/theme/theme.ts new file mode 100644 index 0000000..316905d --- /dev/null +++ b/AdminPanel/src/style/theme/theme.ts @@ -0,0 +1,23 @@ +import { logger } from '@/utils/logger'; + +/** + * 初始化 Arco Design 暗色主题 + * 为 CEP 插件环境配置适配的暗色主题 + */ +export function initTheme() { + // 设置 Arco Design 主题为暗色模式 + document.body.setAttribute('arco-theme', 'dark'); + + // 如果需要自定义 Arco Design 的颜色变量,可以在这里设置 + const root = document.documentElement; + + // 设置主色调为蓝色(可根据需要调整) + root.style.setProperty('--primary-6', 'rgb(64, 128, 255)'); + + // 可选:设置背景色以适应 CEP 插件 + root.style.setProperty('--color-bg-1', '#1a1a1a'); + root.style.setProperty('--color-bg-2', '#252525'); + root.style.setProperty('--color-bg-3', '#323232'); + + logger.log('✅ Arco Design 暗色主题已初始化'); +} diff --git a/AdminPanel/src/utils/cep.ts b/AdminPanel/src/utils/cep.ts new file mode 100644 index 0000000..dbeed72 --- /dev/null +++ b/AdminPanel/src/utils/cep.ts @@ -0,0 +1,116 @@ +/// + +// CSInterface/CEP 的最小化类型定义,避免 TS 编译报错 +declare class CSInterface { + constructor(); + getHostEnvironment(): any; + addEventListener(type: string, listener: any, obj?: any): void; + evalScript(script: string, callback?: (result: string) => void): void; + openURLInDefaultBrowser(url: string): void; + closeExtension(): void; +} + +declare interface HostEnvironment { + appSkinInfo: any; +} + +declare interface CSEvent { + type: string; + data: any; +} + +/** + * cep.ts + * Adobe CSInterface 的封装类,提供类型安全和环境判断 + */ + +class CepWrapper { + private csInterface: CSInterface | null = null; + public inCEP: boolean = false; + + constructor() { + // @ts-ignore + if (typeof CSInterface !== 'undefined') { + // @ts-ignore + this.csInterface = new CSInterface(); + this.inCEP = true; + } else { + // 延迟导入 logger 以避免循环依赖 + import('./logger').then(({ logger }) => { + logger.warn('未找到 CSInterface,当前运行于浏览器模式。'); + }); + } + } + + /** + * 获取原始 CSInterface 实例 + */ + public getCSInterface(): CSInterface | null { + return this.csInterface; + } + + /** + * 获取宿主环境信息 (如皮肤颜色、版本等) + */ + public getHostEnvironment(): HostEnvironment | null { + if (this.csInterface) { + return this.csInterface.getHostEnvironment(); + } + return null; + } + + /** + * 添加 CEP 事件监听 + */ + public addEventListener(type: string, listener: (event: CSEvent) => void, obj?: any): void { + if (this.csInterface) { + this.csInterface.addEventListener(type, listener, obj); + } + } + + /** + * 执行 ExtendScript (JSX) 脚本 + * 返回 Promise 封装的结果 + */ + public evalScript(script: string): Promise { + return new Promise((resolve, reject) => { + if (!this.csInterface) { + // 浏览器模式下的模拟行为 + import('./logger').then(({ logger }) => { + logger.log(`[Mock CEP] 执行脚本: ${script}`); + }); + // 返回合法的 JSON 字符串以避免 Parse Error + resolve('{"success": true, "message": "MOCK_RESULT"}'); + return; + } + + this.csInterface.evalScript(script, (result: string) => { + if (result === 'EvalScript error.') { + reject(new Error(result)); + } else { + resolve(result); + } + }); + }); + } + + /** + * 在默认系统浏览器中打开 URL + */ + public openURLInDefaultBrowser(url: string): void { + if (this.csInterface) { + this.csInterface.openURLInDefaultBrowser(url); + } else { + window.open(url, '_blank'); + } + } + + /** + * 关闭扩展面板 + */ + public closeExtension(): void { + this.csInterface?.closeExtension(); + } +} + +export const cep = new CepWrapper(); diff --git a/AdminPanel/src/utils/cep/fs.ts b/AdminPanel/src/utils/cep/fs.ts new file mode 100644 index 0000000..6f0b5b7 --- /dev/null +++ b/AdminPanel/src/utils/cep/fs.ts @@ -0,0 +1,7 @@ +import { isNodeJSEnabled } from "./tool" + +/** + * cep_node 为ps内置的全局变量 + */ +//@ts-ignore +export const fs = (isNodeJSEnabled() ? cep_node.require('fs') : {}) as typeof import('fs') \ No newline at end of file diff --git a/AdminPanel/src/utils/cep/path.ts b/AdminPanel/src/utils/cep/path.ts new file mode 100644 index 0000000..be50289 --- /dev/null +++ b/AdminPanel/src/utils/cep/path.ts @@ -0,0 +1,9 @@ +import { isNodeJSEnabled } from "./tool" +console.error('isNodeJSEnabled()'+isNodeJSEnabled()); + +/** + * cep_node 为ps内置的全局变量 + */ +//@ts-ignore +export const path = (isNodeJSEnabled() ? cep_node.require('path') : {}) as typeof import('path') + diff --git a/AdminPanel/src/utils/cep/tool.ts b/AdminPanel/src/utils/cep/tool.ts new file mode 100644 index 0000000..fa7a14c --- /dev/null +++ b/AdminPanel/src/utils/cep/tool.ts @@ -0,0 +1,17 @@ +/**是否开启了node模块 */ +export function isNodeJSEnabled() { + //@ts-ignore + if (typeof (cep_node) !== 'undefined') { + //if require and process is available, it should be mixed context + //@ts-ignore + if ((typeof (cep_node.require) !== 'undefined') && (typeof (cep_node.process) !== 'undefined')) { + return true + } + else { + return false + } + } + else { + return false + } +} diff --git a/AdminPanel/src/utils/logger.ts b/AdminPanel/src/utils/logger.ts new file mode 100644 index 0000000..de66f4a --- /dev/null +++ b/AdminPanel/src/utils/logger.ts @@ -0,0 +1,181 @@ +/** + * 全局日志管理工具 + * + * 提供统一的日志管理,支持一键开启/关闭所有日志 + * + * @example + * import { logger } from '@/utils/logger'; + * + * // 使用日志 + * logger.log('普通日志'); + * logger.info('信息日志'); + * logger.warn('警告日志'); + * logger.error('错误日志'); + * logger.debug('调试日志'); + * + * // 控制日志开关 + * logger.enable(); // 开启日志 + * logger.disable(); // 关闭日志 + * + * // 或者设置 + * logger.setEnabled(true); // 开启 + * logger.setEnabled(false); // 关闭 + */ + +type LogLevel = 'log' | 'info' | 'warn' | 'error' | 'debug'; + +class Logger { + private _enabled: boolean = false; // 默认关闭日志 + + /** + * 获取日志开启状态 + */ + get enabled(): boolean { + return this._enabled; + } + + /** + * 开启日志 + */ + enable(): void { + this._enabled = true; + console.log('[Logger] 日志已开启'); + } + + /** + * 关闭日志 + */ + disable(): void { + console.log('[Logger] 日志已关闭'); + this._enabled = false; + } + + /** + * 设置日志开启状态 + */ + setEnabled(enabled: boolean): void { + if (enabled) { + this.enable(); + } else { + this.disable(); + } + } + + /** + * 切换日志状态 + */ + toggle(): void { + this.setEnabled(!this._enabled); + } + + /** + * 普通日志 + */ + log(...args: any[]): void { + if (this._enabled) { + console.log(...args); + } + } + + /** + * 信息日志 + */ + info(...args: any[]): void { + if (this._enabled) { + console.info(...args); + } + } + + /** + * 警告日志 + */ + warn(...args: any[]): void { + if (this._enabled) { + console.warn(...args); + } + } + + /** + * 错误日志 - 错误日志始终显示,不受开关控制 + * 如果需要控制错误日志,使用 errorSilent + */ + error(...args: any[]): void { + // 错误日志始终输出,便于调试问题 + console.error(...args); + } + + /** + * 可控制的错误日志 + */ + errorSilent(...args: any[]): void { + if (this._enabled) { + console.error(...args); + } + } + + /** + * 调试日志 + */ + debug(...args: any[]): void { + if (this._enabled) { + console.debug(...args); + } + } + + /** + * 分组日志开始 + */ + group(...args: any[]): void { + if (this._enabled) { + console.group(...args); + } + } + + /** + * 分组日志结束 + */ + groupEnd(): void { + if (this._enabled) { + console.groupEnd(); + } + } + + /** + * 折叠分组日志开始 + */ + groupCollapsed(...args: any[]): void { + if (this._enabled) { + console.groupCollapsed(...args); + } + } + + /** + * 表格日志 + */ + table(data: any, columns?: string[]): void { + if (this._enabled) { + console.table(data, columns); + } + } + + /** + * 分隔线日志 + */ + separator(char: string = '=', length: number = 60): void { + if (this._enabled) { + console.log(char.repeat(length)); + } + } +} + +// 导出单例 +export const logger = new Logger(); + +// 默认导出 +export default logger; + +// 在开发环境下,可以通过 window.logger 访问 +if (typeof window !== 'undefined') { + (window as any).logger = logger; +} + diff --git a/AdminPanel/src/utils/theme.ts b/AdminPanel/src/utils/theme.ts new file mode 100644 index 0000000..9b341bf --- /dev/null +++ b/AdminPanel/src/utils/theme.ts @@ -0,0 +1,146 @@ +/// + +/** + * theme.ts + * 处理 Photoshop 主题颜色同步 + * 支持两种模式: + * 1. 直接 CEP 模式(CSInterface 可用) + * 2. iframe 模式(通过 postMessage 接收主题) + */ + +import { cep } from './cep'; +import { logger } from './logger'; + +interface Color { + red: number; + green: number; + blue: number; + alpha: number; +} + +interface PSThemeMessage { + type: 'PS_THEME'; + theme: { + bgColor: string; + isLight: boolean; + fontSize: number; + }; +} + +/** + * 将 Adobe 颜色对象转换为 CSS RGB 字符串 + */ +function toHex(color: Color): string { + const r = Math.round(color.red).toString(16).padStart(2, '0'); + const g = Math.round(color.green).toString(16).padStart(2, '0'); + const b = Math.round(color.blue).toString(16).padStart(2, '0'); + return `#${r}${g}${b}`; +} + +/** + * 计算颜色的亮度 (0-255) + */ +function getBrightness(color: Color): number { + return (color.red * 299 + color.green * 587 + color.blue * 114) / 1000; +} + +/** + * 应用主题到页面 + */ +function applyTheme(bgColor: string, isLight: boolean, fontSize?: number) { + const root = document.documentElement; + + let textColorHex, borderColorHex, iconColorHex; + + if (isLight) { + document.body.removeAttribute('arco-theme'); + textColorHex = '#222222'; + borderColorHex = '#d0d0d0'; + iconColorHex = '#333333'; + } else { + document.body.setAttribute('arco-theme', 'dark'); + textColorHex = '#dfdfdf'; + borderColorHex = '#4a4a4a'; + iconColorHex = '#f0f0f0'; + } + + // 设置 CSS 变量 + root.style.setProperty('--ps-bg', bgColor); + root.style.setProperty('--ps-text', textColorHex); + root.style.setProperty('--ps-border', borderColorHex); + root.style.setProperty('--ps-icon', iconColorHex); + if (fontSize) { + root.style.setProperty('--ps-font-size', `${fontSize}px`); + } + + // Arco Design 主题变量 + root.style.setProperty('--color-bg-1', bgColor); + root.style.setProperty('--color-bg-2', bgColor); + root.style.setProperty('--color-bg-3', borderColorHex); + root.style.setProperty('--color-text-1', textColorHex); + root.style.setProperty('--color-border', borderColorHex); + + // 应用到 body + document.body.style.backgroundColor = bgColor; + document.body.style.color = textColorHex; + + logger.log(`[Theme] 已应用主题: ${isLight ? '浅色' : '深色'}, 背景: ${bgColor}`); +} + +/** + * 从 CSInterface 直接获取并更新主题 + */ +export const updateTheme = () => { + if (!cep.inCEP) { + // 浏览器模式 - 使用默认深色主题 + applyTheme('#323232', false); + return; + } + + const hostEnv = cep.getHostEnvironment(); + if (!hostEnv) return; + + const skinInfo = hostEnv.appSkinInfo; + const panelBgColor = skinInfo.panelBackgroundColor.color; + const bgColorHex = toHex(panelBgColor); + const brightness = getBrightness(panelBgColor); + const isLight = brightness > 128; + + applyTheme(bgColorHex, isLight, skinInfo.baseFontSize); +}; + +/** + * 处理来自父窗口的主题消息(iframe 模式) + */ +function handleThemeMessage(event: MessageEvent) { + const data = event.data as PSThemeMessage; + if (data && data.type === 'PS_THEME' && data.theme) { + logger.log('[Theme] 收到父窗口主题消息'); + applyTheme(data.theme.bgColor, data.theme.isLight, data.theme.fontSize); + } +} + +/** + * 初始化主题监听 + */ +export const initThemeListener = () => { + // 检测是否在 iframe 中运行 + const inIframe = window !== window.parent; + + if (inIframe) { + // iframe 模式:监听来自父窗口的消息 + logger.log('[Theme] iframe 模式 - 监听 postMessage'); + window.addEventListener('message', handleThemeMessage); + // 请求父窗口发送主题 + window.parent.postMessage({ type: 'REQUEST_THEME' }, '*'); + } else if (cep.inCEP) { + // 直接 CEP 模式 + logger.log('[Theme] CEP 模式 - 直接监听主题变化'); + updateTheme(); + cep.addEventListener('com.adobe.csxs.events.ThemeColorChanged', updateTheme); + } else { + // 纯浏览器模式 + logger.log('[Theme] 浏览器模式 - 使用默认主题'); + applyTheme('#323232', false); + } +}; diff --git a/AdminPanel/src/view/IframePage.vue b/AdminPanel/src/view/IframePage.vue new file mode 100644 index 0000000..7ac807e --- /dev/null +++ b/AdminPanel/src/view/IframePage.vue @@ -0,0 +1,132 @@ +