Copy link to clipboard
Copied
The case is that we have random number of figures with random shapes and colours that are named inside layer (with random name) with ALL CAPS. The goal is after running the script to change all figure names from "ALL CAPS" to "Small Caps".
Exaple:
RANDOM FIGURE 1
Endgoal:
Random Figure 1
Copy link to clipboard
Copied
Hi @D.S.., I think this will do it.
- Mark
/**
* Turn names of all page items to title case.
* @author m1b
* @discussion https://community.adobe.com/t5/illustrator-discussions/can-someone-share-script-that-changes-figure-name-inside-layer-from-quot-all-caps-quot-to-quot-small/m-p/14453811
*/
(function () {
var doc = app.activeDocument;
for (var i = 0; i < doc.pageItems.length; i++)
if (doc.pageItems[i].name)
doc.pageItems[i].name = titleCase(doc.pageItems[i].name);
app.redraw();
function titleCase(str) {
return str
.toLowerCase()
.replace(/\b\w/g, function (ch) {
return ch.toUpperCase();
});
};
})();
Copy link to clipboard
Copied
Script is working sometimes sometimes it crashes illustrator.
Example:
There were like 12-15 objects inside the layer. Object names were "XX-XXX TEXT TEXT TEXT X" where X is number. When script is used illustrator goes "Not Responding" and never responds, like it is stuck.
Copy link to clipboard
Copied
Are all layers and objects always unlocked and visible when you execute the script?
Copy link to clipboard
Copied
I can't replicate the problem What about removing this line: app.redraw();
Copy link to clipboard
Copied
I can't replicate either—the script works for me whether locked or visible or not.
Could you do a test to see if it a memory issue? Try copy/pasting half the page items into a new document and run script on that. If that works, then now try the same thing with the other half of the page items. Still worked? Try copy/pasting ALL the page items into a new document and try again—maybe corrupt document.
Or please post your test document (the one that crashes) or send to me via PM, and I'll see what I can discover.
- Mark
Copy link to clipboard
Copied
Ok I found out why it is "Not Responding" by some tests. Work documents contain a lot of layers with lot of objects 200K plus. When I use the scripts it tries to do every single object "Small Caps" no mather if the layer is locked, unlocked, selected or deselected. If I use the script in new document with 15-20 objects it works perfectly.
Is it possible to modify the script to change object names to "Small Caps" only to objects inside the selected layer, the layer will always be visible and unlocked?
Thank you in advance for your time! 🙂
Copy link to clipboard
Copied
Right, thanks @D.S.. I think it sounds like a memory problem—Illustrator scripting isn't very careful with memory.
Tomorrow I will re-write the script, to try to fix it. Hang in there!
- Mark
Copy link to clipboard
Copied
Okay, I've brought a bigger gun this time—my `getItems` function—and sorry it's a long script—it has evolved over many years. I've just modified to also collect Layers so hopefully I didn't introduce any bugs.
I've configured the script below to apply the titleCase to every unlocked, visible page item and layer in the document. I'm interested how it goes with your complex-document, so please let me know. (I'd also like to know if it still crashed even if you set getLockedItems and getHiddenItems both to true.)
- Mark
/**
* Page item and layer names to title case.
* NOTE: sometimes you must refresh the layers panel to see the changes.
* @author m1b
* @discussion https://community.adobe.com/t5/illustrator-discussions/can-someone-share-script-that-changes-figure-name-inside-layer-from-quot-all-caps-quot-to-quot-small/m-p/14453811
*/
(function () {
var counter = 0;
// I'm using my `getItems` function just as
// an engine for applying the titleCase to
// every visible, unlocked page item and layer
getItems({
from: app.activeDocument,
getLayers: true,
getGroupItems: true,
getLockedItems: false,
getHiddenItems: false,
filter: function (item) {
if (item.name) {
item.name = titleCase(item.name);
counter++;
}
return false;
},
});
app.redraw();
alert('Examined ' + counter + ' items.');
})();
/**
* Formats string as title case.
* @Param {String} str
* @Returns {String}
*/
function titleCase(str) {
return str
.toLowerCase()
.replace(/\b\w/g, function (ch) {
return ch.toUpperCase();
});
};
/** ------------------------------------------------------------------- *
* GET ITEMS *
* -------------------------------------------------------------------- *
* @author m1b *
* @version 2024-03-01 *
* -------------------------------------------------------------------- *
* Collects page items from a `from` source, eg. a Document, Layer, *
* GroupItem, or Array. Will look inside group items up to `maxDepth`. *
* Search can be filtered using `filter` function. Note that the *
* filter function is evaluated last in the filtering process. *
* -------------------------------------------------------------------- *
* Example 1. Get all items in document: *
* *
* var myItems = getItems({ from: app.activeDocument }); *
* *
* -------------------------------------------------------------------- *
* Example 2. Get all selected items except groups: *
* *
* var myItems = getItems({ *
* from: app.activeDocument.selection, *
* getGroupItems: false, *
* }); *
* *
* -------------------------------------------------------------------- *
* Example 3. Using `filter` function to choose item type: *
* *
* var myItems = getItems({ *
* from: app.activeDocument, *
* filter: function (item) { *
* return ( *
* 'PathItem' === item.typename *
* || 'CompoundPathItem' === item.typename *
* ); *
* } *
* }); *
* *
* -------------------------------------------------------------------- *
* Example 4. Using `filter` function: *
* *
* var myItems = getItems({ *
* from: app.activeDocument, *
* filter: onlyPngLinks *
* }); *
* *
* function onlyPngLinks(item, depth) { *
* return ( *
* 'PlacedItem' === item.typename *
* && '.png' === item.file.name.slice(-4).toLowerCase() *
* ); *
* }; *
* *
* -------------------------------------------------------------------- *
* Example 4. Using the `filter` function for custom collecting: *
* *
* This example bypasses the normal returned array and instead *
* captures items in an "external" array `itemsByDepth`. *
* *
* var itemsByDepth = []; *
* *
* function getItemsByDepth(item, depth) { *
* if (undefined == itemsByDepth[depth]) *
* itemsByDepth[depth] = []; *
* itemsByDepth[depth].push(item); *
* }; *
* *
* getItems({ *
* from: app.activeDocument, *
* filter: getItemsByDepth *
* }); *
* *
* -------------------------------------------------------------------- *
* @Param {Object} options - parameters
* @Param {PageItem|Array<PageItem>|Document|Layer} options.from - the thing(s) to look in, eg. a selection.
* @Param {Function} [options.filter] - function that, given a found item, must return true (default: no filtering).
* @Param {Boolean} [options.getPageItems] - whether to include page items in returned items (default: true).
* @Param {Boolean} [options.getGroupItems] - whether to include GroupItems in returned items (default: true).
* @Param {Boolean} [options.getLayers] - whether to include Layers in returned items (default: false).
* @Param {Boolean} [options.getHiddenItems] - whether to include hidden items in returned items (default: true).
* @Param {Boolean} [options.getLockedItems] - whether to include locked items in returned items (default: true).
* @Param {Boolean} [options.getGuideItems] - whether to include guide items in returned items (default: false).
* @Param {Number} [options.maxDepth] - deepest folder level (recursion depth limit) (default: 99).
* @Param {Boolean} [options.returnFirstMatch] - whether to return only the first found item (default: false).
* @Param {Number} [depth] - the current depth (private).
* @Returns {Array|PageItem} - all the found items in a flat array, or the first found item if `returnFirstMatch`.
*/
function getItems(options, depth) {
// defaults
options = options || {};
var found = [],
depth = depth || 0,
items = options.from;
if (!options.initialized)
// once-off initialization
if (!initialize())
return [];
itemsLoop:
for (var i = 0, item, len = items.length; i < len; i++) {
item = items[i];
if (
false === excludeFilter(item)
&& true === includeFilter(item)
) {
// item found!
found.push(item);
if (options.returnFirstMatch)
break itemsLoop;
}
if (
'GroupItem' !== item.constructor.name
&& 'Layer' !== item.typename
)
// only items with children from here
continue itemsLoop;
if (
excludeHidden(item)
|| excludeLocked(item)
)
// don't look into excluded containers
continue itemsLoop;
if (depth >= options.maxDepth)
// don't go deeper
continue itemsLoop;
// set up for the next depth
options.from = item.pageItems;
// look inside
found = found.concat(getItems(options, depth + 1));
}
// this level done
if (true == options.returnFirstMatch)
return found[0];
else
return found;
/**
* Returns true when the item should be not be found.
* @Param {PageItem|Layer} item
* @Returns {Boolean}
*/
function excludeFilter(item) {
return (
isAlreadyFound(item)
// is hidden
|| excludeHidden(item)
// is locked
|| excludeLocked(item)
// is guide
|| (
false === options.getGuideItems
&& true === item.guides
)
// is layer
|| (
false === options.getLayers
&& 'Layer' === item.typename
)
// is group item
|| (
false === options.getGroupItems
&& 'GroupItem' === item.typename
)
// is page item
|| (
false === options.getPageItems
&& 'GroupItem' !== item.typename
&& undefined != item.uuid
)
);
};
/**
* Returns true when the item should be included.
* @Param {PageItem|Layer} item
* @Returns {Boolean}
*/
function includeFilter(item) {
return (
undefined == options.filter
|| options.filter(item, depth)
);
};
/**
* Returns true when the item should
* be excluded because it is hidden.
* @Param {PageItem|Layer} item
* @Returns {Boolean}
*/
function excludeHidden(item) {
return (
false === options.getHiddenItems
&& (
true === item.hidden
|| false === item.visible
)
);
};
/**
* Returns true when the item should
* be excluded because it is locked.
* @Param {PageItem|Layer} item
* @Returns {Boolean}
*/
function excludeLocked(item) {
return (
false === options.getLockedItems
&& true === item.locked
);
};
/**
* Returns true if item was already
* found, and marks item as found,
* to avoid finding same item twice.
* @Param {PageItem|Layer} item
* @Returns {Boolean}
*/
function isAlreadyFound(item) {
var uuid = item.hasOwnProperty('uuid')
? item.uuid
: item.typename + item.zOrderPosition,
isFound = !!options.isFound[uuid];
options.isFound[uuid] = true;
return isFound;
}
/**
* Returns the initialised `options` object.
* @Returns {Object}
*/
function initialize() {
// make a new object, so we don't pollute the original
options = {
initialized: true,
depth: 0,
isFound: {},
filter: options.filter,
getPageItems: false !== options.getPageItems,
getGroupItems: false !== options.getGroupItems,
getLayers: true === options.getLayers,
getHiddenItems: false !== options.getHiddenItems,
getLockedItems: false !== options.getLockedItems,
getGuideItems: true === options.getGuideItems,
maxDepth: options.maxDepth,
returnFirstMatch: options.returnFirstMatch,
};
if (
undefined == options.maxDepth
|| !options.maxDepth instanceof Number
)
options.maxDepth = 99;
// items is a single layer
if ('Layer' === items.typename)
items = [items];
// items is a document
else if ('Document' === items.constructor.name) {
var layers = items.layers;
items = [];
for (var i = 0; i < layers.length; i++)
items.push(layers[i]);
}
else if ('Array' !== items.constructor.name)
items = [items];
return items.length > 0;
};
};