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

Я работаю с Adobe КЭП (это позволяет разработчикам создавать оконные расширения для продуктов Adobe CC). Основная часть моего кода — это современный JavaScript (платформа использует Chromium 57, Node.js 7.7.4). Однако, чтобы получить доступ к DOM, мне нужно написать некоторые функции в Adobe Расширить скрипт и выполнить их из обычного JS. Единственный способ — выполнить скрипт, используя их предоставленные csInterface.evalScript(script, callback). script должна быть строкой, которая в моем случае представляет собой вызов функции, преобразованный в строку. Я хочу иметь возможность передавать объект в и из ExtendScript через evalScript, но evalScript принимает и возвращает только строку.

В настоящее время я передаю каждое свойство объекта как отдельный аргумент. Это громоздко, но это работает.

Моим первым был JSON.stringify(), но, к сожалению, ExtendScript — это диалект ECMAScript 3, что означает нет поддержки JSON.parse().

Я не могу просто объединить аргумент объекта с вызовом функции скрипта, потому что тогда строка оценивается как 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]".
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
2 300
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Javascript -> Расширить скрипт

Единственный способ передать объекты из 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;
}

Расширить скрипт -> Javascript

Вам понадобится этот модуль ExtendScript, скопированный в ту же папку, что и ваш jsx.

Ссылка на модуль Indiscripts ExtendScript JSON

Затем включите его с помощью #include 'json.jsx'; (или //@include 'json.jsx', чтобы избежать ошибок линтера) в верхней части вашего 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.info(JSON.parse(result));
});

Я тестировал это в последней версии CEP Runtime (v9).

Спасибо, я понятия не имел о возможности прямой передачи строковых объектов! Я также нашел более общий Полифил JSON. Оба метода изменяют $.global, поэтому мне пришлось перезапустить Illustrator, чтобы очистить JSON.stringify(), прежде чем я смогу использовать JSON.lave().

Jason Weinzierl 15.04.2019 07:53

Если у вас есть специальные символы внутри отправляемой вами строки, вам нужно escape их. Если вы используете только decodeURIComponent, он не будет охватывать некоторые символы. Особенно, если вам нужно поддерживать более старые версии, например, Premiere 2019... (я знаю, что escape устарела)

Guntram 13.10.2021 15:07

Другие вопросы по теме