Copy link to clipboard
Copied
Dear community
I am at a loss here and can't find a solution. This is part of a script which opens linked InDesign files, changes the layer visibility on the documents placed in the opened links.
If I put an alert() somewhere between opening and saving the document, everything works fine. If I remove the alert() I get an error, telling me that the file is already open. The error points to the last command in the changeLayerVisibility() Function: layer.currentVisibility = checklist[ft][k].checkedState;
I'm thinking it has something to do with async or timeouts. The alert slowing the process, allowing the loop to finish. But I can't understand why it would ever try to open the same file again...
Here's the relevant part of the script. I hope someone sees where I'm going wrong. If not I can try to create a reduced version of the thing.
function changeNestedLayers(linksArr) {
var thisLink,
thisFile,
thisFileName,
thisDoc;
for (var l = 0; l < linksArr.length; l++) {
thisLink = linksArr[l];
thisFile = File(thisLink.filePath);
thisFileName = thisFile.fullName;
thisDoc = app.open(thisFile, true);
var currentLink,
currentLinkname,
currentLayer,
currentChecklistItem;
for(var s = 0; s < thisDoc.links.length; s++) {
currentLink = thisDoc.links[s];
currentLinkname = currentLink.parent.itemLink.name;
if (currentLink.parent.constructor.name == "ImportedPage" && currentLink.parent.itemLink != null && currentLink.parent.itemLink.linkType == "InDesign Format Name") {
if(hasSubstring(currentLinkname, "FiletypeA")) {
changeLayerVisibility(currentLink, "FiletypeA");
count++;
}
else {
changeLayerVisibility(currentLink, "FiletypeB");
count++;
}
}
}
thisDoc.save(new File(thisFileName));
thisDoc.close(SaveOptions.NO);
}
}
function changeLayerVisibility(thisLink, filetype) {
var ft = filetype.toLowerCase();
var layer;
for (var k = 0; k < layertypes[ft].length; k++) {
layer = thisLink.parent.graphicLayerOptions.graphicLayers.item(layertypes[ft][k].name);
if (layer.isValid) {
layer.currentVisibility = checklist[ft][k].checkedState;
}
}
}
Thanks!
Copy link to clipboard
Copied
I was using similar approach in one of my tools to build catalogs from database - placing INDD files - but I've switched to PDF instead of INDD file - works quicker.
I'm not JS guy so can't help you with your code - but in case of linked files - of any type - you NEED to iterate the collection backwards as every change to the element on the links collection - moves it to the end - looks like InDesign removes original and creates new one - so you'll skip some and process some twice.
Copy link to clipboard
Copied
Hey AdobeScripts, thanks for your reply.
In general our workflow with the placed INDD files works like charm. And we have a single source of truth which we can export when needed.
Iterating backwards... interesting. I remember rewriting the for loops to my liking when adapting the scripts. I quickly tried reversing the outermost loop. Doesn't change anything though. Also, I'm not iterating over the general links collection, but rather an array of collected links.
And the script works exactly as advertised IF there is any alert() somewhere between opening and saving the file. This is what's really bugging me...
Copy link to clipboard
Copied
But you ARE iterating through links collection??
for(var s = 0; s < thisDoc.links.length; s++) { currentLink = thisDoc.links[s];
Yes, you're creating a reference to the item on the links collection - but anything you do to this reference - will modify original object - reference is just for your convenience.
I've had the same problem with the need for alert() in the script I was converting from VBA to JS - script to format Kanji - but I've no idea what was the problem 😞
Copy link to clipboard
Copied
Yes, you are right. I was referring to the outer loop, since I think the problem lies there somewhere. But also reversing the loop you mentioned doesn't change anything.
But good to hear you had the same issue — just too bad you couldn't figure it out either 😉
Copy link to clipboard
Copied
Hi @dersenn , we can’t test your snippet, but have you tried adding some writeIn trace statements to check the file and link names in the debug console?
//before the thisDoc.save line
$.writeln(thisDoc.name)
//at the beginning of the changeLayerVisibility function
$.writeln(thisLink.name)
Copy link to clipboard
Copied
Hey @rob day , thanks for the input. I haven't tried any writeln statements, since there's no toolkit anymore and I have been a bit reluctant to change from my current editor to Visual Studio... But might be a good moment to give it a try.
Still I find it strange that it works perfectly if there simply is an alert somewhere...
Copy link to clipboard
Copied
I would give it a try, the install is a bit tricky but in the end it is better than ESTK. The thing that tripped me up at first was the required .json file at the root of your scripts folder, and the built-in Explorer/Finder. I use this for the launch.json file, but I still don’t fully understand how it works, so someone else might have a better version:
{
"version": "0.2.0",
"configurations": [
{
"name": "Session",
"type": "extendscript-debug",
"request": "launch",
"hostAppSpecifier": "indesign",
"engineName": "session",
}
{
"name": "Main",
"type": "extendscript-debug",
"request": "launch",
"hostAppSpecifier": "indesign",
"engineName": "main",
}
],
"compounds": [
{
"name": "Session/Main",
"configurations": ["Session", "Main"],
"preLaunchTask": "${defaultBuildTask}",
"stopAll": true
}
]
}
Copy link to clipboard
Copied
I quickly gave it a try. So far resulting in two InDesign crashes. I'll give your launch.json a try. Thanks!
Copy link to clipboard
Copied
@dersenn I would definitely recommend moving to VSCode. It is an excellent IDE in my opinion. You need to install the ExtendScript Debugger.
This is my launch.json for Indesign scripting:
{
"type": "extendscript-debug",
"request": "attach",
"name": "Start debugger—IND",
"hostAppSpecifier": "indesign",
"bringToFront": false,
"engineName": "Main",
"debugLevel": 1 /* 0 - No debugging. 1 - Break on breakpoints, errors, or exceptions. 2 - Stop at the first executable line. */
}
It uses the "attach" request, which means you start the debugger once, and then when you run your scripts from VSCode it uses the same debugger instance.
I also have these in my user settings.json file:
"debug.console.closeOnEnd": true,
"debug.internalConsoleOptions": "neverOpen",
"debug.openDebug": "neverOpen",
"debug.toolBarLocation": "docked",
And last, but not least, I have these in my keybindings.json file:
{
"key": "f5",
"command": "-workbench.action.debug.start",
"when": "debuggersAvailable && debugState == 'inactive'"
},
{
"key": "cmd+r",
"command": "extension.extendscript-debug.evalInAttachedHost",
"args": {
"debugLevel": 1,
"bringToFront": false
}
},
{
"key": "cmd+shift+r",
"command": "extension.extendscript-debug.evalInAttachedHost",
"args": {
"debugLevel": 1,
"bringToFront": true
}
},
{
"key": "cmd+.",
"command": "extension.extendscript-debug.haltInHost",
"when": "inDebugMode",
},
{
"key": "ctrl+.",
"command": "workbench.action.debug.stop",
"when": "inDebugMode"
},
I use cmd+r to run a script without activating the host app (eg. if I just want to watch the console or debugger), and cmd+shift+r if I want to activate the host app (note that your scripts may activate the host app anyway if they show a dialog etc).
Well that's my set-up. I hope it gives you some idea of how to customize it to your preferences.
- Mark
Copy link to clipboard
Copied
Hey @m1b , thank you for your thorough guide. I'll definitely give this a try later, when I'm back on that task.
Copy link to clipboard
Copied
Again, thanks. I've got the minimal setup now running (with just the launch.json). Will look into the more refined settings once I need it.
Okay, it is pretty nice to finally have a console for InDesign scripting! 😂
Now I just need to figure out why on earth it wants to open a file on that line...
Copy link to clipboard
Copied
Hi Mark, where do you save the keybindings.json and settings.json files? In the hidden .vscode folder?
Copy link to clipboard
Copied
Hi Rob, the easiest way to edit the "user settings" json file is by invoking the command palette (command-shift-P for me) and typing "settings", then choose "Open User Settings JSON". The file itself is stored in ~/Library/Application Support/Code/User/.
The keybindings.json file is also in that same folder (~/Library/Application Support/Code/User/). One way to open it is to choose Preferences > Keyboard Shortcuts and click the button at the right of the tab bar (for me at least) that looks like a document icon with a little swappy arrow—that switches between the json file and the UI. You can also try typing "keybindings" in the command palette (note you must remove the default ">" first) but you may only see the file there if you've opened it at least once already. Unfortunately you can't (yet) save project-level keybindings in the .vscode folder.
Another feature I would recommend is user snippets—type "snippets" in the command palette. They are a great time saver. Snippets are saved in the same user folder as above. Here's a useful example:
"For loop: Extendscript": {
"prefix": "for",
"body": [
"for (var ${1:i} = 0; ${1:i} < ${2:items}.length; ${1:i}++) {\n var ${3:item = ${2:items}[${1:i}];}$0\n}"
],
"description": "An extendscript-flavoured for loop"
},
"For loop backwards: Extendscript": {
"prefix": "for",
"body": [
"for (var ${1:i} = ${2:items}.length -1; ${1:i} >= 0 ; ${1:i}--) {\n var ${3:item = ${2:items}[${1:i}];}$0\n}"
],
"description": "An extendscript-flavoured for loop"
},
- Mark
Copy link to clipboard
Copied
replace:
Copy link to clipboard
Copied
Thanks for this input. Although I doubt it is the culprit. The error happens before that and it doesn't even get to the saving part.
A little background on why it is saved as a new file with the same name. This is a solution I came across for another script (which updates nested links). Nowadays InDesign gets updated fairly regularly, so files that have not been touched for a few weeks/months get opened as a copy and you need to save them again. You've certainly done this and you need to overwrite the file. Since they get opened as a copy ([converted]), they don't have their original filename and path information. That's why this gets stored before the file is opened.
Copy link to clipboard
Copied
The problem with "converted" file is only when they change a year / version - mid year / version updates do not do that.
Copy link to clipboard
Copied
Nowadays InDesign gets updated fairly regularly, so files that have not been touched for a few weeks/months get opened as a copy and you need to save them again.
Hi @dersenn , Your use of the .fullName property might be causing a problem. Document’s have a .converted property, so if I open a document where .converted returns true, and try to get .fullName, I get the error Unsaved documents have no full name:
var doc = app.activeDocument;
$.writeln(doc.converted)
//if doc.converted returns true doc.fullName throws an error—
//Unsaved documents have no full name.
var fp = doc.fullName;
I use .filepath + .fileName to overwrite converted files:
var doc = app.activeDocument;
var fp = doc.filePath;
var n = doc.name;
if (doc.converted) {
doc.save (File(fp + "/" + n))
} else {
doc.save()
}
Copy link to clipboard
Copied
Hey @rob day. Yes, that's why I grab that filename before opening the doc. But the .converted property is interesting nonetheless and could simplify that. Only do it if it is a converted document. Otherwise just save as usual. Thanks!
Copy link to clipboard
Copied
Which is basically what your snippet does!
Copy link to clipboard
Copied
Yes, that's why I grab that filename before opening the doc
But, you are not getting the name—.fullName is the entire file path, .filePath is the file‘s container, and .name is the file name. So, maybe this would work:
function changeNestedLayers(linksArr) {
var thisLink,
thisFile,
thisDoc;
for (var l = 0; l < linksArr.length; l++) {
thisLink = linksArr[l];
//open the link using fullName, which is the entire path not the name
thisDoc = app.open(File(thisLink.fullName), true);
//the file path for the save below
thisFile = thisDoc.filePath + "/" + thisDoc.name;
//more code....
if (thisDoc.converted) {
thisDoc.save (File(thisFile))
} else {
thisDoc.save()
}
thisDoc.close(SaveOptions.NO);
}
}
Copy link to clipboard
Copied
Hey @rob day, finally I'm having time again to get back to this. Thanks for your input. But I don't think this is the problem. After all, if I take out everything between opening and saving/closing the file, everything works as expected. The Files get opened and saved.
I was mistakenly referring to filename in my previous reply, when I meant the full path and name. Which I get via:
thisFileName = thisFile.fullName;
And using this to save my file is essentially the same as constructing it from path and name afterwards as in your example:
thisFilePath = thisDoc.filePath + "/" + thisDoc.name;
// Changed var name to avoid confusion.
However, I still like the idea of the conditional save involving .converted.
Copy link to clipboard
Copied
And using this to save my file is essentially the same as constructing it from path and name afterwards as in your example:
But when you open a converted file .fullName will throw an error when you try to get it—the document hasn’t been saved:
Copy link to clipboard
Copied
Yes. That's why I grabbed the full filepath and name before opening the link and creating the doc.
Copy link to clipboard
Copied
Interesting. I now tried to create a simplified version including shareable indd files. And it throws me an error exactly when I try to open the file... arrgh. I think I'll have to take a step back again here.