Files
tools/Mac工具/Yeomai-Toolbox-CEP/js/panel.js
T

313 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function () {
"use strict";
var scriptList = document.getElementById("scriptList");
var emptyState = document.getElementById("emptyState");
var statusText = document.getElementById("statusText");
var searchInput = document.getElementById("searchInput");
var refreshButton = document.getElementById("refreshButton");
var openFolderButton = document.getElementById("openFolderButton");
var runExternalButton = document.getElementById("runExternalButton");
var scripts = [];
var extensionPathToken = "";
function getExtensionPath() {
if (!window.__adobe_cep__ || !window.__adobe_cep__.getSystemPath) {
return "";
}
var path = window.__adobe_cep__.getSystemPath("extension") || "";
path = decodeURI(path);
if (/^file:\/\/\/[A-Za-z]:/i.test(path)) {
path = path.substring(8);
} else if (/^file:\/\//i.test(path)) {
path = path.substring(7);
}
return path;
}
function setStatus(message, isError) {
statusText.textContent = message || "";
statusText.className = isError ? "status error" : "status";
statusText.title = message || "";
}
function evalHost(code, callback) {
if (!window.__adobe_cep__ || !window.__adobe_cep__.evalScript) {
callback("ERROR|当前页面不在 Photoshop CEP 环境中运行");
return;
}
window.__adobe_cep__.evalScript(code, callback);
}
function buildListCode() {
return '(function(){try{' +
'var folder=new Folder(decodeURIComponent("' + extensionPathToken + '")+"/jsx/scripts");' +
'if(!folder.exists){return "ERROR|脚本文件夹不存在:"+folder.fsName;}' +
'var result=[];' +
'function walk(current,prefix,depth){' +
'if(depth>20){return;}' +
'var entries=current.getFiles();' +
'entries.sort(function(a,b){' +
'var af=a instanceof Folder;var bf=b instanceof Folder;' +
'if(af!==bf){return af?-1:1;}' +
'var left=File.decode(a.displayName).toLowerCase();' +
'var right=File.decode(b.displayName).toLowerCase();' +
'return left<right?-1:(left>right?1:0);' +
'});' +
'for(var i=0;i<entries.length;i++){' +
'var entry=entries[i];' +
'if(entry instanceof Folder){' +
'var folderName=File.decode(entry.name);' +
'if(!entry.alias&&folderName.charAt(0)!=="."){' +
'walk(entry,prefix+folderName+"/",depth+1);' +
'}' +
'}else if(entry.name&&/\\.jsx$/i.test(entry.name)){' +
'var fileName=File.decode(entry.name);' +
'var label=File.decode(entry.displayName)' +
'.replace(/\\.jsx$/i,"").replace(/_/g," ");' +
'result.push(encodeURIComponent(label)+"|"+' +
'encodeURIComponent(prefix+fileName));' +
'}' +
'}' +
'}' +
'walk(folder,"",0);' +
'return result.join("\\n");' +
'}catch(error){return "ERROR|读取脚本列表失败:"+error.message;}}())';
}
function buildRunCode(encodedRelativePath) {
return '(function(){try{' +
'var folder=new Folder(decodeURIComponent("' + extensionPathToken + '")+"/jsx/scripts");' +
'var relativePath=decodeURIComponent("' + encodedRelativePath + '");' +
'var parts=relativePath.split("/");' +
'if(relativePath.charAt(0)==="/"||relativePath.indexOf("\\\\")!==-1||' +
'!/\\.jsx$/i.test(relativePath)){' +
'return "ERROR|脚本路径不安全";' +
'}' +
'for(var i=0;i<parts.length;i++){' +
'if(!parts[i]||parts[i]==="."||parts[i]===".."){return "ERROR|脚本路径不安全";}' +
'}' +
'var file=new File(folder.fsName+"/"+relativePath);' +
'if(!file.exists){return "ERROR|找不到脚本:"+relativePath;}' +
'$.evalFile(file);return "OK";' +
'}catch(error){return "ERROR|运行失败:"+error.message+"(第 "+error.line+" 行)";}}())';
}
function buildOpenFolderCode() {
return '(function(){try{' +
'var folder=new Folder(decodeURIComponent("' + extensionPathToken + '")+"/jsx/scripts");' +
'if(!folder.exists&&!folder.create()){' +
'return "ERROR|无法创建脚本文件夹:"+folder.fsName;' +
'}' +
'if(!folder.execute()){return "ERROR|无法打开脚本文件夹:"+folder.fsName;}' +
'return "OK";' +
'}catch(error){return "ERROR|无法打开脚本文件夹:"+error.message;}}())';
}
function buildExternalScriptCode() {
return '(function(){try{' +
'var file=File.openDialog("选择要运行的 Photoshop JSX 脚本");' +
'if(file===null){return "CANCEL";}' +
'if(!/\\.jsx$/i.test(file.name)){return "ERROR|请选择扩展名为 .jsx 的文件";}' +
'$.evalFile(file);return "OK";' +
'}catch(error){return "ERROR|运行失败:"+error.message+"(第 "+error.line+" 行)";}}())';
}
function parseScriptList(raw) {
if (raw === "EvalScript error.") {
throw new Error("Photoshop 拒绝执行目录扫描,请重新打开面板");
}
if (!raw) {
return [];
}
if (raw.indexOf("ERROR|") === 0) {
throw new Error(raw.substring(6));
}
var result = [];
var lines = raw.split("\n");
for (var i = 0; i < lines.length; i++) {
if (!lines[i]) {
continue;
}
var parts = lines[i].split("|");
if (parts.length >= 2) {
result.push({
label: decodeURIComponent(parts[0]),
relativePath: decodeURIComponent(parts[1])
});
}
}
return result;
}
function runBundledScript(script) {
var buttons = scriptList.querySelectorAll("button");
for (var i = 0; i < buttons.length; i++) {
buttons[i].disabled = true;
}
setStatus("正在运行:" + script.label, false);
evalHost(buildRunCode(encodeURIComponent(script.relativePath)), function (result) {
for (var j = 0; j < buttons.length; j++) {
buttons[j].disabled = false;
}
if (result && result.indexOf("ERROR|") === 0) {
setStatus(result.substring(6), true);
} else if (result === "EvalScript error.") {
setStatus("脚本运行失败,请检查 JSX 语法", true);
} else {
setStatus("已完成:" + script.label, false);
}
});
}
function makeTreeNode() {
return {folders: {}, scripts: []};
}
function addScriptToTree(root, script) {
var parts = script.relativePath.split("/");
parts.pop();
var node = root;
for (var i = 0; i < parts.length; i++) {
if (!node.folders[parts[i]]) {
node.folders[parts[i]] = makeTreeNode();
}
node = node.folders[parts[i]];
}
node.scripts.push(script);
}
function countScripts(node) {
var count = node.scripts.length;
var names = Object.keys(node.folders);
for (var i = 0; i < names.length; i++) {
count += countScripts(node.folders[names[i]]);
}
return count;
}
function createScriptButton(script) {
var button = document.createElement("button");
button.type = "button";
button.className = "script-button";
button.textContent = script.label;
button.title = script.relativePath;
button.addEventListener("click", function () {
runBundledScript(script);
});
return button;
}
function appendTree(node, container, depth, expandAll) {
var folderNames = Object.keys(node.folders).sort(function (a, b) {
var left = a.toLowerCase();
var right = b.toLowerCase();
return left < right ? -1 : (left > right ? 1 : 0);
});
for (var i = 0; i < folderNames.length; i++) {
var folderName = folderNames[i];
var childNode = node.folders[folderName];
var details = document.createElement("details");
details.className = "folder-group";
details.open = expandAll;
var summary = document.createElement("summary");
summary.className = "folder-summary";
summary.textContent = folderName + "(" + countScripts(childNode) + ")";
var content = document.createElement("div");
content.className = "folder-content";
appendTree(childNode, content, depth + 1, expandAll);
details.appendChild(summary);
details.appendChild(content);
container.appendChild(details);
}
for (var j = 0; j < node.scripts.length; j++) {
container.appendChild(createScriptButton(node.scripts[j]));
}
}
function renderScripts() {
var query = searchInput.value.toLowerCase().replace(/^\s+|\s+$/g, "");
scriptList.innerHTML = "";
var visibleCount = 0;
var root = makeTreeNode();
for (var i = 0; i < scripts.length; i++) {
var searchable = (scripts[i].label + " " + scripts[i].relativePath).toLowerCase();
if (query && searchable.indexOf(query) === -1) {
continue;
}
visibleCount++;
addScriptToTree(root, scripts[i]);
}
appendTree(root, scriptList, 0, query.length > 0);
emptyState.hidden = visibleCount !== 0;
}
function loadScripts() {
refreshButton.disabled = true;
setStatus("正在读取脚本…", false);
evalHost(buildListCode(), function (raw) {
refreshButton.disabled = false;
try {
scripts = parseScriptList(raw);
renderScripts();
setStatus("已载入 " + scripts.length + " 个脚本", false);
} catch (error) {
scripts = [];
renderScripts();
setStatus(error.message, true);
}
});
}
refreshButton.addEventListener("click", loadScripts);
searchInput.addEventListener("input", renderScripts);
openFolderButton.addEventListener("click", function () {
evalHost(buildOpenFolderCode(), function (result) {
if (result && result.indexOf("ERROR|") === 0) {
setStatus(result.substring(6), true);
} else if (result === "EvalScript error.") {
setStatus("无法执行打开文件夹命令", true);
} else {
setStatus("已打开脚本文件夹", false);
}
});
});
runExternalButton.addEventListener("click", function () {
setStatus("请选择一个 JSX 文件…", false);
evalHost(buildExternalScriptCode(), function (result) {
if (result && result.indexOf("ERROR|") === 0) {
setStatus(result.substring(6), true);
} else if (result === "CANCEL") {
setStatus("已取消", false);
} else if (result === "EvalScript error.") {
setStatus("外部脚本运行失败", true);
} else {
setStatus("外部脚本已运行", false);
}
});
});
var extensionPath = getExtensionPath();
extensionPathToken = encodeURIComponent(extensionPath);
if (!extensionPath) {
setStatus("无法获取扩展目录,请重启 Photoshop", true);
} else {
loadScripts();
}
}());