
Silly-V
Valorous Hero
Silly-V
Valorous Hero
Activity
‎Apr 14, 2025
07:33 AM
1 Upvote
You know, this works and it is quite convenient: https://github.com/Silly-V/Adobe-Illustrator/blob/master/Script%20Panel%202/ScriptPanel_2.jsx
... View more
‎Oct 11, 2024
10:42 AM
2 Upvotes
In my case and anything I foresee in the future for it, I saw how the items that are not associated with an 'on-page' item can have a parent of XmlStory, and although I have not used parentPage as of yet, I was able to eliminate going down the branch that had the 'phantom' items by sensing if the xmlContent's parent was an XmlStory. I noticed that the Root was parented by XmlStory, so I made my collection method to ignore items which such a parent type of their xmlContent when it's one-level down. Maybe this isn't quite correct, but for me just in the cases where I delete a page - it works.
... View more
‎Oct 08, 2024
08:36 AM
So it just sounds like the non-associated XML should just be removed, yea? Thank you for the detailed investigation and insights!
... View more
‎Oct 08, 2024
07:34 AM
Yes, the file is attached here.
... View more
‎Oct 08, 2024
05:31 AM
Hello! There is an issue I am experiencing where when a page is deleted that used to have structure somehow has one piece of the structure thinking there's still a document element attached to it. Does anyone have advice on how to detect these items? I think maybe they all have "XMLStory" as the page-element parent at the top of it all, just thinking.
I would like to create a method that can be fed an XML element, and it needs to find its XML parents all the way to the top, and return true if the parent of the xmlContent is an instance of XMLStory. Apparently the ones which do not have a representation in the pages are called "XMLStory", which under it has some kind of all valid elements even if they are not on the document pages. I found some issue which may be a bug, where indeed I was getting a false positive with the parentTextFrame technique for one item and sure enough, when I visited it in the XML Structure panel, it had a "Go to Item" menu option available. However, clicking this option just made InDesign unresponsive for a second, before in the XML Structure it underlined the nodes (this is what it does when it 'selects' an item on the page normally related to an XML node), but nothing effectively happens in the document. So the problem as I would like to call it is "phantom XML".
I wish to ignore all these non-existing-item XML nodes, does anyone have an idea on how to accomplish this?
<Title renamed by MOD>
... View more
‎Nov 02, 2022
01:36 AM
1 Upvote
This kind of work is probably in the same vein what you had to do with the liveEffects catalogue!
... View more
‎Nov 01, 2022
08:27 AM
5 Upvotes
https://github.com/Silly-V/Adobe-TS-ExtendScript/blob/master/AdobeTypes/xmp.d.ts
I saw that there was no types file for XMP. It seemed that for VSCode this is one of the more obscure apis that had no online types file. So I copied the whole set of information from the xmp javascript online tools guide documentation page and put it into a typescript declarations format.
It is kind of helpful, maybe it can be made even better. However, it seems ok to start using.
At the end of the file is an example of making an array and putting custom object elements into it.
Using this types file combined with the online doc, an ESTK debugger of the old kind which I happened to have, it made the process of dissecting and figuring out the example code easier. I got the hint about using bracket accessors and a one-based index as the field-name from here: https://indisnip.wordpress.com/2010/09/07/storing-custom-data-into-indesign-file-xmp/
// * Making an array which contains object elements with properties.
var theFile = File("~/Desktop/test.pdf");
if (xmpLib==undefined) var xmpLib = new ExternalObject('lib:AdobeXMPScript');
var xmpFile = new XMPFile(theFile.fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE);
var xmpPackets = xmpFile.getXMP();
var mt = new XMPMeta(xmpPackets.serialize());
XMPMeta.registerNamespace("http://ns.my-special-namespace/1.0/", "myNs:");
var arrayToSet = [
{ name : "ABC", width : 50, height : 100 },
{ name : "Name-2", width : 125, height : 75 },
];
mt.setProperty("http://ns.my-special-namespace/1.0/", "mySpecialArray", "", XMPConst.PROP_IS_ARRAY);
for (var i = 0; i < arrayToSet.length; i++) {
var oneBasedIndex = i + 1;
var x = arrayToSet[i];
mt.setStructField("http://ns.my-special-namespace/1.0/", "mySpecialArray[" + oneBasedIndex + "]", XMPConst.NS_RDF, "name", x.name);
mt.setStructField("http://ns.my-special-namespace/1.0/", "mySpecialArray[" + oneBasedIndex + "]", XMPConst.NS_RDF, "width", x.width);
mt.setStructField("http://ns.my-special-namespace/1.0/", "mySpecialArray[" + oneBasedIndex + "]", XMPConst.NS_RDF, "height", x.height);
}
if (xmpFile.canPutXMP(xmpPackets)) {
xmpFile.putXMP(mt);
}
xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);
// app.open(theFile); // View the result XMP in the app
... View more
‎Oct 26, 2022
04:37 PM
1 Upvote
Very good, this worked! Thank you.
... View more
‎Oct 25, 2022
12:53 PM
I am actually able to achieve my goal which is to make Bridge to go a folder using the document thumbnail property. However, Bridge never comes up front like I wish it would, here on Win11. Does Bridge stay in the background for you? I tried to bring it with BridgeTalk.bringToFront("bridge"), but to no avail.
... View more
‎Aug 29, 2022
07:37 AM
You can also use text threading. Thread two text frames, they can have individual graphic styles. When text is too large for the first text frame, it will spill over into the next one that is threaded. With hyphenation and justification controls you can somewhat manipulate the way this happens. A technique with multiple styles could be made whereby empty spaces are used to create the next-lines and push a non-whitespace text to the 2nd or 3rd text frame. For this to work though, you have to know in advanced about how long the typical text character count is.
... View more
‎Aug 19, 2022
05:22 AM
1 Upvote
The types are located in this repository: https://github.com/aenhancers/Types-for-Adobe/tree/master/Illustrator/2015.3
As you see, they have some reference files in this file, so you have to find them and ensure they are in your folder too, and if that path changes, then make sure to edit the <reference> statements.
Here is an example of using JSDoc with very simple files: I have 1 folder, in there I have a .d.ts file which contains the typing stuff. And there is one jsx file which will use this type information.
You don't have to do reference paths if you have this types file actually opened up in your VSCode window.
To use JSDoc, you write a multi-line comment which has this format: /** @TyPe {string} */.
When you are hovering over this special comment in the JSX file you can see it knows stuff:
But the moment you close the opened .d.ts file, this disappears.
To handle this you can either make a jsconfig.json file in the project, or a tsconfig.json file that has allowJS on.
But for very simple, we can just add the reference statement:
Now that the reference statement is in place, the type information appears again.
Now, check this out: use the comment at the top that says ///@ts-check which will cause type-script-powered type-checking to be going on in your file.
Now it knows that what you want isn't it:
It will complain and draw your attention to the issue.
You can use quick-actions by pressing Ctrl+. to bring up any auto-helpful menus.
Most useful is "add missing properties":
This will auto-write the properties and put sample values into them to satisfy the type checker.
It really helps when you start having a lot of more complex objects.
And, when you use the code it will auto-complete relevant properties with type-ahead:
When I was writing prop_1, it gave me only things that work on strings and when I did prop_2, it showed only properties/methods and apply to the number data type.
If you can replicate this simple setup, afterwards you can take the example and put in the types for adobe declaration files to take advantage of auto-completion of Illustrator-specific data types. The types at the repo are helpful, but they are for 2015. I have taken my types files and edited them to include more meaningful checks, such as when the input type was "string" but I know that the only 'string' this particular object takes is "row" or "column" or "stack". So I edited the types file to help auto-complete only these 3 strings when using that object, and it also puts up an error in the problems panel when I accidentally typed "colunm".
... View more
‎Aug 18, 2022
08:44 PM
Well just try this: make a new folder, then open that folder up with VSCode.
YourFolder/AdobeTypes/index.d.ts
YourFolder/AdobeTypes/JavaScript.d.ts
... and so on
Put the types for adobe .d.ts files inside it.
Make a new JSX file and at the top of this file write the following:
/// <reference types="./YourFolder/AdobeTypes"/>
When you put no semi-colon at the end of this, VSCode will better highlight the file path and it will tell you if the path is missing. Unfortunately, for me, VSCode does not auto-complete the path in this statement like it does with some other things. At least it tells you when the path is wrong. In types for adobe files you can also see the reference statements being included, they help bring in the other types files. For example, Illustrator-stuff index.d.ts contains reference statements that bring in code from JavaScript.d.ts and global.d.ts, etc.
You then can use JSDoc. Since an Adobe types file contains the "app" variable declaration, it will now know when you type in "app.activeDocument" that it's an Illustrator document and you can auto-complete the properties when you write all the code. You can also put in special comments such as:
/** @TyPe {string[]} */
var stringArray = [];
alert(stringArray.length);
When you type the dot after stringArray it will pop in with all kinds of properties. VSCode will do this anyway, because it will know you have an array, I think. But if you also put a ///@ts-check comment in your JSX file, it will also tell you that stringArray[0] can only be a string. I did it this way for a couple of years, and ended up putting in all the polyfills for modern array methods for example, in my library jsx files. The auto-completion for what your javascript of the moment can do is controlled by a tsconfig.json or jsconfig.json file's "lib" property, so absent the file and only using the open VSCode folder and reference statement, you may have to put in the directive no-default-lib="true" into the /// <reference statement. Anyway, just look into JSDoc to get you up and running with intellisense, it can go a very long way without any TypeScript. When you use JSDoc it will work in your js files and you won't have to do anything different, but it will still use TypeScript to carry out its type-checking and auto-completion. So if you use it, it's just like using TypeScript, minus the transpiling feature which takes modern JS you write in and compiles it down to ES3 for ExtendScript.
... View more
‎Aug 18, 2022
08:08 AM
4 Upvotes
Given simple line-art you can simply loop the items to correct their .top and .left properties. As these objects are the same dimensions with the example they will by definition already be aligned centrally to the targets.
Assuming that your layers are just as you have them: var targetObjects = doc.layers.getByName("Target Position").pathItems; var objectsToMove = [ doc.layers.getByName("To move aligned objects").layers[0].pathItems[0],
doc.layers.getByName("To move aligned objects").layers[1].pathItems[0],
doc.layers.getByName("To move aligned objects").layers[2].pathItems[0] ];
for (var i = 0; i < objectsToMove.length; i++) {
objectsToMove[i].top = targetObjects[i].top;
objectsToMove[i].left = targetObjects[i].left;
}
This is a very rudimentary example and it can work with your specific situation because of the object dimensions and the order of target and source items is the same. The order actually does not have to be the same in the layers, as long as you ensure to put them into the same order within your code so when the loop runs, it will be directed to match the proper target and source items.
... View more
‎Aug 17, 2022
09:57 PM
Keep in mind that what makes the recursive methods work is a [data structure] that contains a property which is an array of.. the [data structure].
So a layer will always have the .layers property, and each object in the array-like object that is layer.layers is also a Layer. Therefore a Layer object contains a collection of Layer objects, each one contains its own and so on. You could write numerous loops an keep track of a crazy number of arrays in custom objects, but it will never truly work when you do not know the amount of nested items and they're dynamic. So you never know what you're gonna get and no matter how many loops are written, the users can always have just one more layer in some layer. Therefore, the answer to this conundrum is a function that can run itself.
var node = {
name : (entryContainer instanceof Document) ? "DOCUMENT" : entryContainer.name,
layers : [],
};
This part creates the node object, as you see it has a property that isn't an array and it's symbolic for any node's random properties that one may create as needed - in this case just the layer's name. But the array one is a special property because it will end up containing some nested node objects.
var thisLayer;
for (var i = 0; i < entryContainer.layers.length; i++) {
thisLayer = entryContainer.layers[i];
node.layers.push(getNestedLayerInfo(thisLayer));
}
This part here goes over the Illustrator Layer's .layers collection and uses the same function that we're in right now, to process those nested layers. So our original "var node = ..." object will have a .layers array of our custom node objects. If there were no nested layers in the variable "entryContainer", this same loop still works by iterating 0 times and pushing nothing to the node's .layers array because it doesn't get a chance to run and the recursion stops. However, if there was just one layer, the line node.layers.push(getNestedLayerInfo(thisLayer)) will run, and that one layer actually may have 20 layers in its .layers.
Finally, the node object is returned from the recursive function:
return node;
The logic is actually simple if you think of it in terms of this one function working on just the one layer. An Illustrator layer is passed in, we create an object that features its name and starts an empty array for its layers. Then it goes through any layers and runs itself, but we can stop thinking about what nesting level it's at and just proceed to the return and be out of it mental-wise. The only question is: when this function ran through the layer's array, is it going to process a layer? Yes, of course. And how would it do so? Well, we go to the top and see that a Layer object is our parameter, and yes indeed we are processing a layer.. check. Then we create an object that features its name and starts an emty array for its layers. Does the Layer object that is being worked on have a .layers property that is an array that can be full of other Layer objects only? Check. So is this function going to work on any layer? Yep, it sure will!
... View more
‎Aug 17, 2022
03:04 AM
1 Upvote
It can be a bit of a mess, but at least we are confined to only Layer objects, and a recursive traversal can yield to you such information as nested layer names and indexes.
You can make a 'mirror' object to put instructions about layers into. This object would be a 'node'. A node can have information about it as well as most importantly - other nodes. And those nodes can have their own information and other nodes and so on. Once you have the snapshot of what the original names are you could recursively traverse this tree and assign new names based on that. Here is some code which has a simple recursive function and traversal example. This example starts out assuming I have "Layer 4" which contains a nested "Layer 5". This Layer 4 is copied, so it gets named "Layer 4 copy" and the nested layer is "Layer 5 copy". Now we can run the code and edit the names however one wishes.
Note: JSDoc is handled badly by these forums, it bakes in some poor soul's user-name when you go @ type or @ param (without the spaces). I wonder if those couple of people get awesome forum emails each time I paste such snippets up!
/**
* @typedef LayerNodeTree
* @property {string} name
* @property {LayerNodeTree[]} layers
*/
/**
* Collects layer information into a node tree.
* @Param {Document | Layer} entryContainer - Where to start the node tree.
*/
function getNestedLayerInfo (entryContainer) {
/** @TyPe {LayerNodeTree} */
var node = {
name : (entryContainer instanceof Document) ? "DOCUMENT" : entryContainer.name,
layers : [],
};
var thisLayer;
for (var i = 0; i < entryContainer.layers.length; i++) {
thisLayer = entryContainer.layers[i];
node.layers.push(getNestedLayerInfo(thisLayer));
}
return node;
}
/**
* Processes a layer node tree with arbitrary processing.
* @Param {LayerNodeTree} nodeTree
* @Param {Layer | Document} newContainer
*/
function processLayerTree (nodeTree, newContainer) {
// alert(nodeTree.name + " : " + newRootContainer.name);
if (newContainer instanceof Layer && nodeTree.name == newContainer.name.replace(/ copy$/, "")) {
newContainer.name = newContainer.name.replace(/ copy$/, " legit!");
}
var thisLayer;
for (var i = 0; i < newContainer.layers.length; i++) {
thisLayer = newContainer.layers[i];
processLayerTree(nodeTree.layers[i], thisLayer);
}
}
var layerInfo = getNestedLayerInfo(app.activeDocument.layers.getByName("Layer 4"));
// alert(layerInfo.toSource());
processLayerTree(layerInfo, app.activeDocument.layers.getByName("Layer 4 copy"));
... View more
‎Aug 16, 2022
07:07 PM
You did save the action part as a .aia file and loaded it, no?
Make sure to save this part as .aia and load in the actions panel. Then the part of the script which is
app.doScript("target layer", "Test Set 2");
will work. But that action text cannot be part of your javascript.
... View more
‎Aug 16, 2022
12:36 PM
2 Upvotes
Oh, this just IN! A brand-new technique which uses more actions to highlight any layer.
What it does is put a temporary path item to your desired layer and selects that item, then runs an action which uses "Locate Object" from the layers' panel to bring a highlighted selection to that item. Apparently the behavior of Illustrator is to automatically highlight the parent layer of an object that has recently exited the Isolation Mode!
This actually works really conveniently for this situation, so much so that this method and action is probably usable for all-time.
/**
* Highlights any layer by inserting a temporary item into it and using an action which enters and exists the isolation mode.
* Afterwards, this item is removed.
* @Param {Layer} targetLayer
*/
function highlightLayerInContainer (targetLayer) {
var someTempPath = targetLayer.pathItems.rectangle(0, 0, 200, 200);
someTempPath.name = "TEMP [for highlighting]";
app.activeDocument.selection = null;
someTempPath.selected = true;
app.doScript("target layer", "Test Set 2");
someTempPath.remove();
}
highlightLayerInContainer(app.activeDocument.layers.getByName("Layer 5").layers.getByName("Layer 7"));
// app.doScript("DupeLayer", "Test Set 2"); // * Do custom processing on the layer when it is highlighted. /version 3
/name [ 10
54657374205365742032
]
/isOpen 1
/actionCount 2
/action-1 {
/name [ 9
447570654c61796572
]
/keyIndex 0
/colorIndex 0
/isOpen 1
/eventCount 1
/event-1 {
/useRulersIn1stQuadrant 0
/internalName (ai_plugin_Layer)
/localizedName [ 5
4c61796572
]
/isOpen 1
/isOn 1
/hasDialog 0
/parameterCount 2
/parameter-1 {
/key 1836411236
/showInPalette -1
/type (integer)
/value 1
}
/parameter-2 {
/key 1851878757
/showInPalette -1
/type (ustring)
/value [ 19
4475706c69636174652053656c656374696f6e
]
}
}
}
/action-2 {
/name [ 12
746172676574206c61796572
]
/keyIndex 0
/colorIndex 0
/isOpen 1
/eventCount 3
/event-1 {
/useRulersIn1stQuadrant 0
/internalName (ai_plugin_Layer)
/localizedName [ 5
4c61796572
]
/isOpen 0
/isOn 1
/hasDialog 0
/parameterCount 2
/parameter-1 {
/key 1836411236
/showInPalette -1
/type (integer)
/value 19
}
/parameter-2 {
/key 1851878757
/showInPalette -1
/type (ustring)
/value [ 13
4c6f63617465204f626a656374
]
}
}
/event-2 {
/useRulersIn1stQuadrant 0
/internalName (ai_plugin_Layer)
/localizedName [ 5
4c61796572
]
/isOpen 0
/isOn 1
/hasDialog 0
/parameterCount 1
/parameter-1 {
/key 1836411236
/showInPalette -1
/type (integer)
/value 24
}
}
/event-3 {
/useRulersIn1stQuadrant 0
/internalName (ai_plugin_Layer)
/localizedName [ 5
4c61796572
]
/isOpen 0
/isOn 1
/hasDialog 0
/parameterCount 1
/parameter-1 {
/key 1836411236
/showInPalette -1
/type (integer)
/value 25
}
}
}
... View more
‎Aug 16, 2022
12:07 PM
Yea, this is where I think the magic sort of ... stops. The issue is of course that the automatic behavior of Illustrator has stopped accommodating ourthese-here work-arounds.
Well, here's what I think: if the objective is to trigger some Illustrator action which specifically works on layers in a highlighted state at least we can move the things from one layer into a top-level layer, then run the procedure to highlight and do whatever-else such as duplicate, then move the new duplicated layer to the new spot.
Maybe this will still be applicable to you?
... View more
‎Aug 15, 2022
08:04 PM
2 Upvotes
The highlighting of a layer is a big problem because with ExtendScript there's no way to do so. However, what you can do is cause a condition which brings this about. Some sitations could be, adding a new layer for example. Its' behavior is to be automatically highlighted. Another nuance of this behavior is that if a layer happened to be deleted, the layer below it becomes highlighted. So we could apparently use enough redraws during a script which adds and removes a new layer, to cause the highlighting to both appear and stay. However there is a little issue with not being able to highlight a layer whose index is not 0 in the case of there not being a highlight on any layer in the first place, unless beforehand one ensures to highlight the layer at the very top and then do so to their intended layer. This is an experimentation method which highlights my layers according to the code, let me know if it ends up working for you.
/**
* 0-based index Highlights a layer by adding and removing a temporary layer.
* @Param {number} layerIndex
*/
function highlightLayerAtIndex (layerIndex) {
var doc = app.activeDocument;
if (layerIndex >= doc.layers.length) {
throw new Error("The layer index (" + layerIndex + ") is out of bounds (0-" + (doc.layers.length - 1) + ")");
}
var indexLayer = doc.layers[layerIndex];
var tempLayer = doc.layers.add();
app.redraw();
tempLayer.move(indexLayer, ElementPlacement.PLACEBEFORE);
app.redraw();
tempLayer.remove();
app.redraw();
}
// Ensure a highlight for any scenario.
highlightLayerAtIndex(0);
// Highlights the 4th layer.
highlightLayerAtIndex(3);
This is de facto really undo-heavy, as in how the app.redraw() causes an undo point each time it is used.
Nevertheless, when used along with an action which duplicates a layer, this will create the duplication per Illustrator rules and appends " copy" after the name. It then also removes the highlighting. -- not a problem for us, as the same highlight method can surely rehighlight it.
... View more
‎Aug 15, 2022
12:55 AM
With TS we can have the template literals! https://github.com/Silly-V/Adobe-TS-ExtendScript/blob/master/SampleTSScript/src/1_functions.ts
/**
* > An example of template interpolation.
*/
function test (inStr?: string): string {
let resultStr;
if (inStr) {
resultStr = `Your string is: "${inStr}".`;
} else {
resultStr = "Hello World!";
}
return resultStr;
}
/**
* > An example of destructuring an array.
*
* > An example of an Arrow function.
*/
function makeShapes (doc: Document): string[] {
const completedItems = [];
let [x, y] = [0, 0];
new Array(10).join(",").split("").forEach(() => {
const newShape = doc.pathItems.rectangle(y, x, 50, 50);
x += 10;
y += 10;
completedItems.push(newShape.uuid);
});
return completedItems;
}
function makeOtherShapes (doc: Document) {
let [x, y] = [200, 0];
// Make the shapes with a one-line statement.
CircleNames.forEach(m => doc.pathItems.ellipse(y += 10, x += 10, 50, 50));
}
/**
* > An example showing powerful typescript typing: a known-typed object can be used
* to add several properties to another object expecting those known properties.
*/
function initializeDocument () {
const doc = app.activeDocument;
const defaultColorization: Partial<Document> = {
defaultFilled : false,
defaultStroked : true,
};
Object.assign(doc, defaultColorization);
}
... View more
‎Aug 15, 2022
12:42 AM
1 Upvote
You have to use TypeScript these days. The way old ES3 ExtendScript works is that you have #include statements which bring in files. But in the modern way, what you do is specify the compilation target as "ES3" in your tsconfig.json of the TS project and then you can write modern-format type-checked auto-completing code which can compile down to the one long ES3-style JSX file which is a stitched-together version of all your typescript files which have been compiled down to ES3 and put into one large body of text. It takes a bit of time to set up your first typescript project, essentially VSCode gives us the ability to create an auto-completion environment just like the old VB stuff, but even better because you're in control. But once you have got your first project up, you can just copy and paste it to create new projects. A very big benefit is being able to include or exclude various code from different locations, such as using a shared code folder or using some bits of code from separate scripts in each other. This is powered by the type checking, so if anything is wrong, the message will tell you. As opposed to the ESTK and its include statements which one would have to run and see it break to know if any of the files have changed or they aren't there anymore. Here is a sample project I've started with a long time ago, and now it's really updated and I need to update the repo. However, it shows a package structure and a tsconfig.json, and you can download this code to see if it's able to run.
In this old project I have used a .d.ts declaration file which specifies the polyfills such as Array.prototype.map prototype, and I have "allowJS" as true, so the JS files referenced by the .d.ts file are brought in. (EDIT: I just looked at it and forgot I have already updated it to convert the polyfills to TS) However, I since have realized that allowJS can cause some issues for me and it's better to have converted the polyfills files to typescript and include them 'normally', as a .ts file which is inside the "include" block of the tsconfig. I have turned the allowJS off these days, and use the include block along with the "exclude" and "files" blocks when needed.
My summary of this is:
The 'types for Adobe' files should be referenced at the "types" block of the tsconfig.
The code which will be used for the script is in the "include" block, often times as "./src/**/*.ts" to capture simply every ts file in the src folder. Note that you don't have to name it 'src' even, everything is up to you - but most just say 'src' and if you talk to anyone else they will immediately know about 'src'.
Sometimes you may write a script that would do well to just borrow some code from another script. You can simply use the include block to stick in various random ts files from arbitrary filesystem locations. However, maybe one of the inclusion patterns specifies a whole folder of files, but you want every file except certain ones from there. In this case, use the "exclude" block to exclude those undesired files.
However still, there may be a situation where you want to include some items, including folders of files, but maybe it's a folder that has a folder and actually you want to include the parent folder, exclude the child folder but still include just a couple of files from that excluded folder. In this case, use the "files" block to override the exclusion block (which can exclude folders and files) to override the exclusion statement and bring in those specific files. The items in the "files" block cannot be folders as opposed to the include/exclude blocks.
Anyways, that's a bit more of an advanced topic - but to start out if you can make your TS project run, then your magical world of auto-completing intellisense and the code writing itself for you is going to be opened! The question is, how many scripts you're doing and how much javascript do you foresee yourself doing in the future in general. Every javascript project can be a typescript project and it yields substantial benefits. I would say if you even intend to do a single javascript project that will ever need future maintenance, TS is the only way to fly! PS: you can use typescript right away with no additional meta-codes which post-process the files. This way, every separate code file has to contain either variables by themselves or a function but no return statements. The resulting compiled file will have all the functions listed out in the resulting javascript file. But, I like to have every script of mine to be wrapped in a wrapper method, so it is completely scoped in and we can pass arguments to this one big function and therefore be able to activate this script via external means. A simplest way is to make another JSX file (it could be vanilla) and use an extendscript #include statement to bring the code in, into the contents of a method in this JSX file. The arguments passed to the parent function which contains the #include will be referenceable via the arguments keyword in the included code. So that is why there's this whole 'build-code' folder in the project, you can activate the tasks with Ctrl+Shift+B to run tsc-watch and "Build-Export-Watch". The first tsc-watch simply does tsc every time you save, and it writes the file to the _CONTENTS.js file. But, there is extra node js javascript that puts a file watcher on that _CONTENTS file and every time there is a change to that file, it will take that text and put it inside the .template.js file, into a wrapper function.
So, you do not have to do all this, because technically 'all this' is a replacement of having that other JSX file which simply does an #include of the _CONTENTS file. However the reason I did it is because I personally wish to end up with one single file I can email to people.
Oh yea, but you can also just use regular javascript and use JSDoc. You either use tsconfig.json and use allowJS : true - and you don't even have to do any tsc or any typescript, or use jsconfig.json. (but you do have to use a lot of JSDoc comments)
... View more
‎Aug 14, 2022
06:43 PM
Other useful ones are •find, •findIndex, •some and •every. Although extendscript has no 'let', using TypeScript will allow one to use it and the modern coding conventions such as the arrow functions. Besides the modern syntax, TS helps with type checking, so for example if you use the .find method on an array of PathItem, the 'm' variable in the find parameter will automatically know it is a PathItem and VSCode will auto-complete all the various PathItem properties when you type "m.".
... View more
‎Aug 13, 2022
06:12 AM
So your answer is on the side of "it's been a decades-long issue and everyone has just learned to make 'peace with it'" ?
... View more
‎Aug 12, 2022
11:43 AM
I tried it, and full justify is the only way I could get it to expand out. But I want it to not expand more than my settings. In InDesign setting full justify does the same, but having center justify is what makes the text stay in the middle and it gets thinner if the text box width is decreased. It is helpful in some cases to use this, but most of the time when text is shorter in characters they do not want to see the outer characters touching the sides of a wide text frame.
... View more
‎Aug 12, 2022
06:42 AM
I used the justification settings in InDesign to set the glyph scaling to 50% minimum, 100% desired and 100% maximum. When I decreased the width of the text frame in InDesign, the text inside came closer and closer together per the letter spacing settings, then it scaled down the width of the glyphs and the text became compacted inside as expected.
However, in Illustrator all the same settings are available but they just don't work. Decreasing the width of the Illustrator text frame just makes the text wrap, or disappear completely if "No Break" is set in the characters panel. The only time it seems to have any effect is if I set the paragraph justification to 'full justify' and then the text letters get spread out to where they touch the sides of the text frame at all times. But this isn't what I want, I want it to squish down like in InDesign such as when you widen the text frame, the characters will stay in the middle and only decrease in size and spacing when the text gets smaller.
Is this a bug/feature that there's a secret workaround for, or has it been like this for decades and everyone just lives with it?
ILLUSTRATOR:
INDESIGN:
... View more
‎Aug 08, 2022
07:58 PM
1 Upvote
The problem is likely that the loop is too fast to copy items, or something - my suggestion is to use BridgeTalk's onResult method where another method can be used to do the operation. This way it should wait until the BT process is done with the entire copy/paste operation.
... View more
‎Aug 05, 2022
09:46 PM
1 Upvote
Sometime around CS6, I believe checkboxes were broken in Illustrator's ScriptUI ListBox controls and we had to start working around with this using images for list-items, or unicode symbols an prepending to text.
Now with the latest update, in addition to making all buttons have a non-rounded border (I JUST got used to the rounded border on all buttons, why ?), it looks like the checkboxes are back in ListBoxes!
They really work.
This is good news for me right now because I do have a list box as it happens, which needs both a checkbox and an image. Now I will be able to forget about all the checkbox work-arounds and simply use the control as normal.
... View more
‎Jul 31, 2022
06:43 PM
1 Upvote
IMHO the only way to manage anything like that is to parse aia text and to splice together such an aia text that you could erase the old set with the remove method that has no argument for action-name but only one string argument specifying the set name. I am not sure what happens if two action sets with the same name are loaded and the removal method is used though.
But, regardless, it will not throw an error until there is no such action-set named that name left in the panel - so you can keep looping with a while loop until there are no more such-named sets left and you are able to retrieve an error in a try-catch block.
So, only if you have access & management of the text files to be able to 'know' what exactly is loaded inside the actions panel, you could tecnically manipulate the text to add more action events, or splice in action events and replace the target set with your special new spliced set.
... View more
‎May 15, 2022
10:40 AM
Whaaat! 🤯
That's great! Thanks. Now this will be ultimate control, yea.
... View more
‎May 11, 2022
11:00 AM
Vulcan.js is a file always included in documentation for CEP panels.
In simple terms, what is Vulcan.js for and what do people usually do with it?
I know a standard answer is, it helps talk to CC apps, and by the looks of the test panel CEP extension, it helps your extension talk to Creative Cloud.app, something called "CCXProcess.app" and Core Sync.app and finally CCLibrary.app.
Okay, so .. what can one do with these things using Vulcan, and what are they useful for?
... View more