Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

UXP: list json for document contents / structure

Explorer ,
Jun 07, 2023 Jun 07, 2023

I've made a script in CEP/jsx that lists the document structure of a given node in the document. E.g. I can ask for "app.activeDocument.graphicLines" and get back a JSON for all lines in the document (se screenshot "CEP_getJson_graphicLines.png"), or if I want the whole document I ask for "app.activeDocument.pageItems" (see screenshot "CEP_getJson_pageItems.png")

 

I want to do the same in UXP, i.e. get back every item / node in the document structure in JSON, but no luck so far

 

Has anyone done this?

 

 

TOPICS
UXP Scripting
956
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Employee ,
Jul 09, 2023 Jul 09, 2023

Could you tell me which InDesign DOM API is exactly not working as expected in UXP scripting?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jul 18, 2023 Jul 18, 2023

I was hoping to be able to do something like this

 

<script> 
    const id = require("indesign");
    const app = id.app;  
    console.log(app.activeDocument);
    console.log(JSON.stringify(app.activeDocument));
</script>​

 

But I can't stringify the object, I only get this in the console

 

Document {}
{}

 

I.e. stringify doesn't work. It seems like everything in the object is functions (+ it is recursive), so I had to make a workaround that loops through the whole object up to a certain level and generate a new object.

Is there any way of getting the document as a "normal JSON object"?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Employee ,
Jul 18, 2023 Jul 18, 2023

These InDesign DOM APIs in UXP mimic the exact behaviour as in ExtendScript/CEP. I see the same behaviour in ExtendScript and UXP on executing alert(app.activeDocument).

So, I wonder how you were able to generate the JSON string from app.activeDocument in CEP.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jul 19, 2023 Jul 19, 2023
LATEST

TLDR; I've gone for getting exactly the data I need in UXP instead of trying to serialize big chunks of the document structure

 

This is how I do it in CEP / ES3 (beware of terrible code):

Let's say I want all page items with data "two levels down", this is what I have in my main HTML page:

 

async function getObject(what) {
    try {
        let res = await runEvalScript(what);
        return JSON.parse(res);
    } catch (error) {
        return [];
    }
}

var pageItemsData = await getObject('objMain.getObjectFromIndesign("app.activeDocument.pageItems", 2)');
console.log(pageItemsData);
// push pageItemsData to server

 

and over to the "CEP-part":

 

#include './json2.jsx';

var doc = app.activeDocument;

// ES3 doesn't have much array functions, so let's use a string-hack instead
// Declare globaly
var dictionaryString = ''
function traverseObject(obj, loopLevel, dictionaryString, traverseLevels) {
    if (loopLevel > traverseLevels) {
        return { 'exitLoop': true };
    }
    loopLevel = loopLevel + 1;
    var newObj = {};
    for (var prop in obj) {
        try {
            if (obj.hasOwnProperty(prop) && obj[prop] !== null) {
                // We could probably just keep as-is, but just to be sure
                newObj[prop] = obj[prop].toString();
            } 
        } catch (error) {
            // Not much to do
        }

        if (newObj[prop] !== undefined) {
            // Not sure we need to convert to string, but just to be sure...
            var stringCheck = newObj[prop].toString();
            if (stringCheck.indexOf('[object')) {
                // Keep
            } else if (prop === 'parent' || prop === 'events' || prop === 'eventListeners' || prop === 'properties' || prop === 'parentStory') {
                // Ignore
                delete newObj[prop];
            } else {
                // Traverse (original) object
                if (dictionaryString.indexOf('|' + stringCheck + '|') > 0) {
                    // If we get a hit on this we probably have a loop / allready have the param
                } else {
                    dictionaryString += stringCheck + '|';
                    newObj[prop] = traverseObject(obj[prop], loopLevel, dictionaryString, traverseLevels);
                }
            }
        }
    }
    return newObj;
}

var objMain = {};
objMain.getObjectFromIndesign = function(object, traverseLevels) {
    if (object === undefined || object === '') {
        return [];
    }

    var returnObject = [];
    var looper = eval(object);

    for (var i = 0; i < looper.length; i++) {
        var obj = looper[i];
        // ES3 doesn't have much array functions, so let's use a string-hack instead to keep track of duplicates
        dictionaryString = '|';
        var newObj = traverseObject(obj, 0, dictionaryString, traverseLevels);

        returnObject.push(newObj);
    }

    return JSON.stringify(returnObject);
}

 

Now, terrible as this looks, this works in CEP -- and gives the result in the screenshot I posted in this thread
It does not work (out of the box) in UXP
 
For my "fix" for UXP, I decided to just get the data I need. I.e. instead of trying to serialize the whole doc-structure I rather just make (smaller) objects of the items I need. Lets say I want to send info about the graphic lines used in a document back to my server, I could then get the (exact fields) I need by doing this

 

const id = require("indesign");
const app = id.app;

const graphicLines = [];
for (i = 0; i < app.activeDocument.graphicLines.length; i += 1) {
  const fields = {
    name: app.activeDocument.graphicLines.item(i).name,
    strokeWeight: app.activeDocument.graphicLines.item(i).strokeWeight,
    fillColor: {
      name: app.activeDocument.graphicLines.item(i).fillColor.name,
    },
  }
  graphicLines.push(fields);
}
console.log(graphicLines);
// send graphicLines to server

 

That said; if there is a solution to getting complete JSON (up to a level) for e.g. graphicLines, I would appreciate to se how it is done 🙂

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jul 09, 2023 Jul 09, 2023

Hi @Øyvind235243823c6v,

Where exactly do you fail in UXP script? Can you share some examples, what does the method getObjectFromInDesign require as an input and what do you get instead when you run the DOM API call in UXP?

-Manan

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jul 18, 2023 Jul 18, 2023

The screenshot is from a CEP plugin I made. With the new (beta) release of UXP scripting for InDesign we're scrapping CEP and moving to UXP

 

The problem now is to get a JSON object I can serialize and push to the server, i.e. the previous comment I made further up in this thread

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines