Как мне передать объект в Adobe ExtendScript из Javascript (Adobe CEP)?

#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() просто отлично, и в документе, над которым я работаю, появляется многоточие. Однако выполнение скрипта / вызов функции с помощью конкатенации кажется очень неправильным. Итак, вкратце,

  1. Я хотел бы какой-нибудь (более аккуратный) способ превратить dataObject в строку и передать ее drawCircle() через evalScript() ,
  2. и я хотел бы вернуться 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 это устарело)