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

Script to expand all groups not working if group is empty

Explorer ,
Jan 16, 2023 Jan 16, 2023

Copy link to clipboard

Copied

Hey guys! I have this script that I found here in the community and I've already tested some others. They all close groups containing layers, but if the group is empty, the script stops.
Is there any way for this script to work even on empty groups? My client uses an automation and needs all groups open.
Thanks if anyone can help.

Ther script i am using is this:

// Expand ALL layer groups/sets
openAllLayerSets(app.activeDocument);

function openAllLayerSets(parent) {
    for (var setIndex = 0; setIndex < parent.layerSets.length; setIndex++) {
        app.activeDocument.activeLayer = parent.layerSets[setIndex].layers[0];
        openAllLayerSets(parent.layerSets[setIndex]);
    }
}

The error i get:
rrprec_0-1673886092900.png

 

TOPICS
Actions and scripting

Views

1.5K

Translate

Translate

Report

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

correct answers 2 Correct answers

Guide , Jan 16, 2023 Jan 16, 2023

 

Expands even empty groups.

openAllLayerSets(app.activeDocument);

function openAllLayerSets(parent) {
    for (var setIndex = 0; setIndex < parent.layerSets.length; setIndex++) {
        if (parent.layerSets[setIndex].layers.length) {
            app.activeDocument.activeLayer = parent.layerSets[setIndex].layers[0];
            openAllLayerSets(parent.layerSets[setIndex]);
        } else {
            parent.layerSets[setIndex].artLayers.add()
            app.activeDocument.activeLayer = paren
...

Votes

Translate

Translate
Guide , Jan 16, 2023 Jan 16, 2023

1. Does not affect the visibility of layers

2. Expands all groups, including empty ones

3. Restores the selection of layers

4. Fast as possible

5. Not compatible with old versions of PS (seemingly less  CC 2017) due to the lack of properties 'hasBackgroundLayer' and 'targetLayersIDs' (can be adapted)

 

#target photoshop

activeDocument.suspendHistory('Expand all layerSets', 'openAllLayerSets()')

function openAllLayerSets() {
    var lr = new AM('layer'),
        doc = new AM('document'),
      
...

Votes

Translate

Translate
Adobe
Community Expert ,
Jan 16, 2023 Jan 16, 2023

Copy link to clipboard

Copied

The easy way would be wrapping the affected part in a try-clause. 

Votes

Translate

Translate

Report

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
Guide ,
Jan 16, 2023 Jan 16, 2023

Copy link to clipboard

Copied

 

Expands even empty groups.

openAllLayerSets(app.activeDocument);

function openAllLayerSets(parent) {
    for (var setIndex = 0; setIndex < parent.layerSets.length; setIndex++) {
        if (parent.layerSets[setIndex].layers.length) {
            app.activeDocument.activeLayer = parent.layerSets[setIndex].layers[0];
            openAllLayerSets(parent.layerSets[setIndex]);
        } else {
            parent.layerSets[setIndex].artLayers.add()
            app.activeDocument.activeLayer = parent.layerSets[setIndex]
            openAllLayerSets(parent.layerSets[setIndex]);
            parent.layerSets[setIndex].layers[0].remove()
        }
    };
};

If this is not necessary, then it is better to heed the advice of the @c.pfaffenbichler 

Votes

Translate

Translate

Report

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 ,
Jan 16, 2023 Jan 16, 2023

Copy link to clipboard

Copied

Worked perfectly, Thank @jazz-y 

Votes

Translate

Translate

Report

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 ,
Jan 16, 2023 Jan 16, 2023

Copy link to clipboard

Copied

Excellent @jazz-y – it has always bugged me that there is a "collapse all groups" command, but no command to "expand all groups".

 

I wanted to retain the selected layer from before running the script, which was easy enough.

 

(Script edited)

 

// Expand All Layer Groups

expandAllLayerGroups();

function expandAllLayerGroups() {
    // If no layer is selected, the top layer will be selected... could this be improved?
    // To do: check and restore active layer visibility!
    var origLayer = activeDocument.activeLayer;
    
    openAllLayerSets(app.activeDocument);
    function openAllLayerSets(parent) {
        // by jazz-y
        for (var setIndex = 0; setIndex < parent.layerSets.length; setIndex++) {
            if (parent.layerSets[setIndex].layers.length) {
                app.activeDocument.activeLayer = parent.layerSets[setIndex].layers[0];
                openAllLayerSets(parent.layerSets[setIndex]);
            } else {
                parent.layerSets[setIndex].artLayers.add();
                app.activeDocument.activeLayer = parent.layerSets[setIndex];
                openAllLayerSets(parent.layerSets[setIndex]);
                parent.layerSets[setIndex].layers[0].remove();
            }
        }
    }

    activeDocument.activeLayer = origLayer;
}

 

That being said, if there were no layers selected before running the script, then the top layer will be selected. This is due to the bug in scripting where the top layer is returned when no layer is active/selected. Just wondering if there is a way to improve this further, so if there is no layer selected before running the script, then no layer is selected afterwards. If a layer is selected, then it would still be selected afterwards.

 

Edit: I didn't even consider the complexity of multiple/discontinuous layers being selected!

Votes

Translate

Translate

Report

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
Guide ,
Jan 16, 2023 Jan 16, 2023

Copy link to clipboard

Copied

@Stephen_A_Marsh, this is a recursive function. At the moment, saving the active layer and restoring the selection occurs every time it is called (for all nested groups), which seems redundant. You need to move these commands outside the function.

 

To save layer selection and restore later, I usually use this code:

var s2t = stringIDToTypeID;

// get selected layes count with layers IDs
(r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
var sel = executeActionGet(r).getList(p);

// restore selection
if (sel.count) {
    r = new ActionReference();
    for (var i = 0; i < sel.count; i++) { r.putIdentifier(s2t('layer'), sel.getReference(i).getIdentifier()) }
    (d = new ActionDescriptor()).putReference(s2t('target'), r);
    executeAction(s2t('select'), d, DialogModes.NO);
} else {
    (r = new ActionReference()).putEnumerated(s2t('layer'), s2t('ordinal'), s2t('targetEnum'));
    (d = new ActionDescriptor()).putReference(s2t('target'), r);
    executeAction(s2t('selectNoLayers'), d, DialogModes.NO);
}

Votes

Translate

Translate

Report

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 ,
Jan 16, 2023 Jan 16, 2023

Copy link to clipboard

Copied

quote

@Stephen_A_Marsh, this is a recursive function. At the moment, saving the active layer and restoring the selection occurs every time it is called (for all nested groups), which seems redundant. You need to move these commands outside the function.

 

Thank you! You are of course correct. I wanted to keep it all in the function and didn't think about that!

 

I'll fix up the previous code and look into implementing your layer re-selection code.

Votes

Translate

Translate

Report

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
Guide ,
Jan 16, 2023 Jan 16, 2023

Copy link to clipboard

Copied

1. Does not affect the visibility of layers

2. Expands all groups, including empty ones

3. Restores the selection of layers

4. Fast as possible

5. Not compatible with old versions of PS (seemingly less  CC 2017) due to the lack of properties 'hasBackgroundLayer' and 'targetLayersIDs' (can be adapted)

 

#target photoshop

activeDocument.suspendHistory('Expand all layerSets', 'openAllLayerSets()')

function openAllLayerSets() {
    var lr = new AM('layer'),
        doc = new AM('document'),
        currentSelection = doc.getProperty('targetLayersIDs'),
        layers = expandGroups(getLayersCollection());
    if (layers.length) {
        doc.selectLayers(layers)
        doc.deleteLayers(layers)
    }
    if (currentSelection.count) {
        var s = [];
        for (var i = 0; i < currentSelection.count; i++)
            s.push(currentSelection.getReference(i).getIdentifier())
        doc.selectLayers(s)
    } else doc.selectNoLayers()
    function expandGroups(layers, toDelete) {
        toDelete = toDelete ? toDelete : [];
        for (var a in layers) {
            if (layers[a].layerKind == 7) {
                if (layers[a].length) {
                    lr.selectLayers([layers[a][0].id])
                    expandGroups(layers[a], toDelete)
                }
                else {
                    lr.add()
                    lr.moveLayer(lr.getProperty('itemIndex', layers[a].id) - 2)
                    toDelete.push(lr.getProperty('layerID'))
                }
            }
        }
        return toDelete
    }
    function getLayersCollection() {
        var doc = new AM('document'),
            lr = new AM('layer'),
            indexFrom = doc.getProperty('hasBackgroundLayer') ? 0 : 1,
            indexTo = doc.getProperty('numberOfLayers');
        return layersCollection(indexFrom, indexTo)
        function layersCollection(from, to, parentItem, group) {
            parentItem = parentItem ? parentItem : [];
            for (var i = from; i <= to; i++) {
                var layerSection = lr.getProperty('layerSection', i, true).value;
                if (layerSection == 'layerSectionEnd') {
                    i = layersCollection(i + 1, to, [], parentItem)
                    continue;
                }
                var properties = {};
                properties.id = lr.getProperty('layerID', i, true)
                properties.visible = lr.getProperty('visible', i, true)
                properties.layerKind = lr.getProperty('layerKind', i, true)
                  if (layerSection == 'layerSectionStart') {
                    for (o in properties) { parentItem[o] = properties[o] }
                    group.push(parentItem);
                    return i;
                } else {
                    parentItem.push(properties)
                }
            }
            return parentItem
        }
    }
    function AM(target, order) {
        var s2t = stringIDToTypeID,
            t2s = typeIDToStringID;
        target = target ? s2t(target) : null;
        this.getProperty = function (property, id, idxMode) {
            property = s2t(property);
            (r = new ActionReference()).putProperty(s2t('property'), property);
            id != undefined ? (idxMode ? r.putIndex(target, id) : r.putIdentifier(target, id)) :
                r.putEnumerated(target, s2t('ordinal'), order ? s2t(order) : s2t('targetEnum'));
            return getDescValue(executeActionGet(r), property)
        }
        this.selectLayers = function (IDList) {
            var r = new ActionReference()
            for (var i = 0; i < IDList.length; i++) {
                r.putIdentifier(s2t("layer"), IDList[i])
            }
            (d = new ActionDescriptor()).putReference(s2t("target"), r)
            d.putBoolean(s2t("makeVisible"), false)
            executeAction(s2t("select"), d, DialogModes.NO)
        }
        this.add = function () {
            (r = new ActionReference()).putClass(target);
            (d = new ActionDescriptor()).putReference(s2t("null"), r);
            executeAction(s2t("make"), d, DialogModes.NO);
        }
        this.moveLayer = function (to) {
            (r = new ActionReference()).putEnumerated(s2t("layer"), s2t('ordinal'), s2t('targetEnum'));
            (d = new ActionDescriptor()).putReference(s2t('null'), r);
            (r1 = new ActionReference()).putIndex(s2t('layer'), to);
            d.putReference(s2t('to'), r1);
            executeAction(s2t('move'), d, DialogModes.NO);
        }
        this.selectNoLayers = function () {
            (r = new ActionReference()).putEnumerated(s2t("layer"), s2t('ordinal'), s2t('targetEnum'));
            (d = new ActionDescriptor()).putReference(s2t('target'), r);
            executeAction(s2t('selectNoLayers'), d, DialogModes.NO);
        }
        this.deleteLayers = function (IDList) {
            var r = new ActionReference()
            for (var i = 0; i < IDList.length; i++) {
                r.putIdentifier(s2t("layer"), IDList[i])
            }
            (d = new ActionDescriptor()).putReference(s2t("target"), r)
            executeAction(s2t("delete"), d, DialogModes.NO)
        }
        function getDescValue(d, p) {
            switch (d.getType(p)) {
                case DescValueType.OBJECTTYPE: return { type: t2s(d.getObjectType(p)), value: d.getObjectValue(p) };
                case DescValueType.LISTTYPE: return d.getList(p);
                case DescValueType.REFERENCETYPE: return d.getReference(p);
                case DescValueType.BOOLEANTYPE: return d.getBoolean(p);
                case DescValueType.STRINGTYPE: return d.getString(p);
                case DescValueType.INTEGERTYPE: return d.getInteger(p);
                case DescValueType.LARGEINTEGERTYPE: return d.getLargeInteger(p);
                case DescValueType.DOUBLETYPE: return d.getDouble(p);
                case DescValueType.ALIASTYPE: return d.getPath(p);
                case DescValueType.CLASSTYPE: return d.getClass(p);
                case DescValueType.UNITDOUBLE: return (d.getUnitDoubleValue(p));
                case DescValueType.ENUMERATEDTYPE: return { type: t2s(d.getEnumerationType(p)), value: t2s(d.getEnumerationValue(p)) };
                default: break;
            };
        }
    }
}

 

 

Votes

Translate

Translate

Report

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 ,
Jan 17, 2023 Jan 17, 2023

Copy link to clipboard

Copied

@jazz-y – thank you, just what I wanted to do but couldn't! 

Votes

Translate

Translate

Report

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 ,
Jan 18, 2023 Jan 18, 2023

Copy link to clipboard

Copied

@jazz-y - I used your layer re-selection code and noticed that layer visibility had changed after the script for loop was completed. How hard is it to retain the selected layers on/off visibility with the layer/s selection?

Votes

Translate

Translate

Report

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
Guide ,
Jan 18, 2023 Jan 18, 2023

Copy link to clipboard

Copied

Not difficult. Just add before execute action 'select'

 

d.putBoolean(s2t("makeVisible"), false);

 

Votes

Translate

Translate

Report

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 ,
Jan 18, 2023 Jan 18, 2023

Copy link to clipboard

Copied

Thank you @jazz-y – I just tested again and can't reproduce...

Votes

Translate

Translate

Report

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 ,
Jan 19, 2023 Jan 19, 2023

Copy link to clipboard

Copied

OK, I can get it to mess with visibility. Left before, right after the for loop over top-level layerSets (sorry, they are inside a layerSet which may change things):

 

before-after.png

 

It's the 1.1 version script here:

 

https://community.adobe.com/t5/photoshop-ecosystem-discussions/custom-script-for-renaming-artboards-...

Votes

Translate

Translate

Report

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
Guide ,
Jan 19, 2023 Jan 19, 2023

Copy link to clipboard

Copied

Understood what the problem is. I thought that the task was to avoid changing the visibility of the layer during selection, but it turns out that the task is to preserve the visibility of the layer (even if it was changed during the script).

The easiest way is to save the visibility state of all layers and after the script runs, restore it (all, since we know very well that if you change the visibility of the nested elements of the group, the visibility of the parent group will also change):

var currentLayersState = getLayersVisiblity();

// some code here

setLayersVisiblity(currentLayersState)
function getLayersVisiblity() {
    var s2t = stringIDToTypeID,
        t2s = typeIDToStringID;
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var targetLayers = executeActionGet(r).getList(p),
        seletion = [],
        visiblity = {};
    for (var i = 0; i < targetLayers.count; i++) seletion.push(targetLayers.getReference(i).getIdentifier());
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('numberOfLayers'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var len = executeActionGet(r).getInteger(p);
    for (var i = 1; i <= len; i++) {
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('layerSection'));
        r.putIndex(s2t('layer'), i);
        if (t2s(executeActionGet(r).getEnumerationValue(p)) == 'layerSectionEnd') continue;
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('layerID'));
        r.putIndex(s2t('layer'), i);
        var id = executeActionGet(r).getInteger(p);
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('visible'));
        r.putIndex(s2t('layer'), i);
        var visible = executeActionGet(r).getBoolean(p);
        visiblity[id] = visible;
    }
    return { selection: seletion, visiblity: visiblity }
}
function setLayersVisiblity(layersStateObject) {
    var s2t = stringIDToTypeID;
    for (var a in layersStateObject.visiblity) {
        makeVisible = layersStateObject.visiblity[a] ? "show" : "hide";
        (r = new ActionReference()).putIdentifier(s2t('layer'), a);
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        executeAction(s2t(makeVisible), d, DialogModes.NO);
    }
    if (layersStateObject.selection.length) {
        var r = new ActionReference()
        for (var i = 0; i < layersStateObject.selection.length; i++)
            r.putIdentifier(s2t("layer"), layersStateObject.selection[i]);
        (d = new ActionDescriptor()).putReference(s2t("target"), r);
        d.putBoolean(s2t("makeVisible"), false);
        executeAction(s2t("select"), d, DialogModes.NO);
    } else {
        (r = new ActionReference()).putEnumerated(s2t("layer"), s2t('ordinal'), s2t('targetEnum'));
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        executeAction(s2t('selectNoLayers'), d, DialogModes.NO);
    }
}

Votes

Translate

Translate

Report

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 ,
Jan 19, 2023 Jan 19, 2023

Copy link to clipboard

Copied

Thank you @jazz-y – this works great!

Votes

Translate

Translate

Report

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
People's Champ ,
Jan 19, 2023 Jan 19, 2023

Copy link to clipboard

Copied

quote

Understood what the problem is. I thought that the task was to avoid changing the visibility of the layer during selection, but it turns out that the task is to preserve the visibility of the layer (even if it was changed during the script).

The easiest way is to save the visibility state of all layers and after the script runs, restore it (all, since we know very well that if you change the visibility of the nested elements of the group, the visibility of the parent group will also change):


By @jazz-y

 

var uniq_name = "TMP"+Math.random();

var d = new ActionDescriptor();
var r = new ActionReference();
r.putClass(stringIDToTypeID("compsClass"));
d.putReference(stringIDToTypeID("null"), r);
var d1 = new ActionDescriptor();
d1.putBoolean(stringIDToTypeID("useVisibility"), true);
d1.putBoolean(stringIDToTypeID("usePosition"), false);
d1.putBoolean(stringIDToTypeID("useAppearance"), false);
d1.putString(stringIDToTypeID("title"), uniq_name);
d.putObject(stringIDToTypeID("using"), stringIDToTypeID("compsClass"), d1);
executeAction(stringIDToTypeID("make"), d, DialogModes.NO);


// some code here


var d = new ActionDescriptor();
var r = new ActionReference();
r.putName(stringIDToTypeID("compsClass"), uniq_name);
d.putReference(stringIDToTypeID("null"), r);
executeAction(stringIDToTypeID("applyComp"), d, DialogModes.NO);

var d = new ActionDescriptor();
var r = new ActionReference();
r.putName(stringIDToTypeID("compsClass"), uniq_name);
d.putReference(stringIDToTypeID("null"), r);
executeAction(stringIDToTypeID("delete"), d, DialogModes.NO);

 

 

Votes

Translate

Translate

Report

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
Guide ,
Jan 20, 2023 Jan 20, 2023

Copy link to clipboard

Copied

LATEST

... аааааааааааааааааааа!!!! 🙂 Гениально!
Я думал layerComps только для хипстеров со смузи, которые всякими UI/UX занимаются 🙂 

Votes

Translate

Translate

Report

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
People's Champ ,
Jan 16, 2023 Jan 16, 2023

Copy link to clipboard

Copied

Данный скрипт портит видимость групп (включает её).

 

: )

Votes

Translate

Translate

Report

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
Guide ,
Jan 17, 2023 Jan 17, 2023

Copy link to clipboard

Copied

Мопед не мой, я только гайки подкрутил 🙂

Votes

Translate

Translate

Report

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
People's Champ ,
Jan 18, 2023 Jan 18, 2023

Copy link to clipboard

Copied

Тут чё-тo мне в голову мысля стукнула. Решил озвучить.

Если не добаввлять в каждую папку слой и потом его удалять, а

создать any-слой, и потом

двигать его в папку командой move(target, ElementPlacement.INSIDE),

после его развыделять и выделять опять.

И так со всеми папками. Не нарушает видимость групп.

Если слой не перевыделять, то получим интересный прикол при перемещении в закрытую группу.

Визуально на палитре нет активного(выделенного) слоя, но activeLayer как и положено не layers[0].

 

 

Votes

Translate

Translate

Report

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