#javascript #extendscript #ecmascript-3
#javascript #extendscript #ecmascript-3
Вопрос:
Я работаю с Adobe CEP (это позволяет разработчикам создавать оконные расширения для продуктов Adobe CC). Основная часть моего кода — современный JavaScript (платформа использует Chromium 57, Node.js 7.7.4). Однако, чтобы получить доступ к DOM, мне нужно написать некоторые функции в Adobe ExtendScript и выполнить их из обычного JS. Единственный способ — выполнить скрипт, используя предоставленный ими csInterface.evalScript(script, callback)
. script
должна быть строка, которая в моем случае является вызовом функции, преобразованным в строку. Я хочу иметь возможность передавать объект в ExtendScript и из него через evalScript
, но evalScript
принимает и возвращает только строку.
В настоящее время я передаю каждое свойство объекта в качестве его собственного аргумента. Это громоздко, но это работает.
Моя первая мысль была JSON.stringify()
, но, к сожалению, ExtendScript — это диалект ECMAScript 3, что означает отсутствие JSON.parse()
поддержки.
Я не могу просто объединить аргумент object в вызов функции script, потому что тогда строка принимает значение foo([object Object])
.
Я видел, что есть такие функции, как eval()
/ uneval()
или Object.toSource()
, но они не поддерживаются Chromium.
Вот пример, аналогичный моему текущему методу:
functions.js (ES3/ ExtendScript)
function drawCircle(x, y, name) {
// pick a layer
var layer = app.activeDocument.layers[0];
var diameter = 10;
var top = y diameter / 2;
var left = x - diameter / 2;
// draw ellipse in layer
var circle = layer.pathItems.ellipse(top, left, diameter, diameter);
circle.name = name;
circle.filled = true;
return true;
}
app.js (ES6)
const csInterface = new CSInterface(); // provided by Adobe
async function circle() {
const dataObject = {x: 10, y: 10, name: 'Hello world!'};
// the script to call
// evaluates to drawCircle(10,10,'Hello world!');
const script = "drawCircle(" dataObject.x "," dataObject.y ",'" dataObject.name "');";
return new Promise((resolve, reject) => {
csInterface.evalScript(script, (result) => {
resolve(result);
});
});
}
Как и ожидалось, circle()
вызывает drawCircle()
просто отлично, и в документе, над которым я работаю, появляется многоточие. Однако выполнение скрипта / вызов функции с помощью конкатенации кажется очень неправильным. Итак, вкратце,
- Я хотел бы какой-нибудь (более аккуратный) способ превратить
dataObject
в строку и передать ееdrawCircle()
черезevalScript()
, - и я хотел бы вернуться
dataObject
изdrawCircle()
и получить его обратно как объект. В настоящее время возврат объекта приводит только к"[object Object]"
возвращаемому значению.
Ответ №1:
Javascript -> ExtendScript
Единственный способ передать объекты из Javascript в ExtendScript — отправить их в виде строки JSON с JSON.stringify()
.
Да, вы правы насчет отсутствия JSON.parse()
поддержки, однако вам это и не нужно.
Вы все еще можете отправить объект в виде строки, и он прибудет в ExtendScript как объект.
const dataObject = {x: 10, y: 10, name: 'Hello world!'};
const script = "drawCircle(" JSON.stringify(dataObject) ")";
И затем в ExtendScript вы можете сделать что-то вроде этого:
function drawCircle(obj) {
var layer = app.activeDocument.layers[0];
var radius = 10;
var top = obj.y 5;
var left = obj.x - 5;
var circle = layer.pathItems.ellipse(top, left, radius, radius);
circle.name = obj.name;
circle.filled = true;
return true;
}
ExtendScript -> Javascript
Вам понадобится этот модуль ExtendScript, скопированный в ту же папку, что и ваш jsx
Ссылка на модуль Unscripts ExtendScript JSON
Затем включите его с #include 'json.jsx';
(или //@include 'json.jsx'
, чтобы избежать ошибок linter) в верхней части вашего jsx. Это добавляет глобальную функцию JSON, которая предоставляет два метода: JSON.eval()
и JSON.lave()
.
Нам нужен метод, lave()
который позволяет вам преобразовать объект обратно в Javascript. Считайте это более удобной версией JSON.stringify()
.
function drawCircle(obj) {
var layer = app.activeDocument.layers[0];
var radius = 10;
var top = obj.y 5;
var left = obj.x - 5;
// draw ellipse in layer
var circle = layer.pathItems.ellipse(top, left, radius, radius);
circle.name = obj.name;
circle.filled = true;
return JSON.lave(circle);
}
Затем в javascript вы можете выполнить синтаксический анализ объекта еще раз:
const dataObject = {x: 10, y: 10, name: 'Hello world!'};
const script = "drawCircle(" JSON.stringify(dataObject) ")";
csInterface.evalScript(script, (result) => {
console.log(JSON.parse(result));
});
Я протестировал это в последней версии среды выполнения CEP (v9).
Комментарии:
1. Спасибо, понятия не имел о возможности прямой передачи строковых объектов! Я также нашел более общее заполнение JSON . Оба метода изменяются
$.global
, поэтому мне пришлось перезапустить Illustrator для очистки,JSON.stringify()
прежде чем я смогу использоватьJSON.lave()
.2. Если у вас есть специальные символы внутри отправляемой строки, вам нужно
escape
их. Если вы используете толькоdecodeURIComponent
, он не будет охватывать некоторые символы. Особенно, если вам нужно поддерживать более старые версии, например, Premiere 2019… (Я знаю, чтоescape
это устарело)