Skip to main content
New Participant
August 13, 2024
Answered

#targetengite directive never works with #include directive

  • August 13, 2024
  • 1 reply
  • 971 views

Imagine you have files

  • main.jsx
  • utils.jsx

In "main.jsx" you specify #target, #targetengine directives so some of your variables could be persistent and use #include to get your utils functions so you could use them later.

 

And... Here you go, your values are not persistent. They become persistent only if you get rid of #include statement. Is it intended behaviour? How do i make #targetengine work and keep my variables at next script run with #include directive? Unfortunately i can't serialize my values to string and save it later so session is my only option.

Example code below:

--- main.jsx ---

 

#target illustrator
#targetengine "session001"

#include 'utils.jsx';


if (isNaN(foo)) var foo = 0;

foo += 2;

alert(foo);

 

--- utils.jsx ---

 

var bar = null;

 

 

 
 

 

 

This topic has been closed for replies.
Correct answer m1b

Hi @some_5675, DOM reference in Illustrator are fragile, so I wouldn't waste any time trying to keep one. They are broken by many common actions, such as closing/re-opening the document, or simply adding or removing a page item "before" the reference page item (altering the DOM "after" the page item should be fine).

 

One of your problems is the speed to retrieve your page items graph. Have you tried using 

var myItem = doc.getPageItemFromUuid(myPageItemID);

exclusively to create your graph? Is it too slow?

- Mark

 

P.S. As you noticed the JSON library cannot stringify DOM items. This is for two immediate reasons: (1) they contain cyclic structures that would cause JSON.stringify to loop forever if not aborted, eg. there are properties that return a parent object, which itself has properties that return the original child object, and (2) Illustrator crashes when trying to read some properties of some DOM items! Not to mention that you really don't want to serialize the entire thing—it can be quite long and slow process.

 

The usual approach is to provide JSON.stringify with a `replacer` function (and JSON.parse with a `reviver` function, if necessary). Here is a little example of a replacer for stringifying a PathItem:

/**
 * Example replacer for PathItem
 * @param {String|Number} [key] - the access key (default: undefined).
 * @param {*} value - the value to replace.
 * @returns {*?} - the value to serialize.
 */
function pathItemReplacer(key, value) {

    // unfortunately we have to try/catch here
    // because some DOM objects throw weird errors
    // for no good reasons
    try {

        if ('parent' === key)
            // parent objects usually cause cyclic structure
            // and we don't want them anyway
            return undefined;

        if ('Number' === key.constructor.name)
            // don't interfere with normal array access
            return value;

        if (
            'PathItem' === value.typename
            || 'PathPoint' === value.typename
        )
            // send this back for further serialising
            return value;

        switch (key) {

            case 'uuid':
            case 'anchor':
            case 'leftDirection':
            case 'rightDirection':
                // JSON can stringify these
                return value;

            case 'note':
                // only if exists
                return '' !== value ? value : undefined;

            case 'pointType':
                // special handling
                return String(value);

            case 'pathPoints':
                // JSON can't always handle "collections"
                // so return a normal Array
                var pathPoints = [];
                for (var i = 0; i < value.length; i++)
                    pathPoints[i] = value[i];
                return pathPoints;

            case 'fillColor':
            case 'strokeColor':
                // just for an example, we'll
                // only stringify a swatch name
                if (
                    value
                    && value.typename
                    && 'SpotColor' === value.typename
                )
                    return value.spot.name;

            default:
                // ignore everything else
                return undefined;

        };

    }

    catch (error) {
        // we definitely don't want anything that throws errors!
        return undefined;
    }

};

 

1 reply

jduncan
Adobe Expert
August 13, 2024

It seems `targetengine` may not be supported in newer versions of Ai (docs), but I've never used that directive so I don't know for sure (docs just may be old). It is hard to tell what you are trying to accomplish with your code but if you need something to persist you could always write it to a file (and read it later) or use `$.setenv()` and `$.getenv()`. I use both options a lot with "include" files and it works great.

some_5675Author
New Participant
August 13, 2024

Thank you for the reply. It's a pitty if it not works that way.

quote

It is hard to tell what you are trying to accomplish with your code

I have graph-like structure inside SVG. Each item is a native PathItem object. I parse all objects from layer and build graph structure to manipulate it later but it builds everytime i run the script and could take a while. I want to keep the data i parsed last time.

 

I tried to use json2 library but it refuses to serialize my object (probably because it has PathItem objects inside and they are not serializable) and script fails without an error. So i need a way to somehow keep my data persistent.

jduncan
Adobe Expert
August 13, 2024

You can save "JSON-like" data to a file and read it back using `eval()` (docs) without an external library.