Skip to main content
Inspiring
August 9, 2022
Answered

Collapse single group of layers

  • August 9, 2022
  • 2 replies
  • 4483 views

Is it possible to collapse only currently selected group of layers in PS using javascript?
I have the problem that after completing my script, selected group stay expanded, even it is collapsed when i run script.
I found some solutions where all groups are collapsed,  but is possible to do it for a single group?

Thanks in advance

Correct answer r-bin

Is there a way not to change the group to open or close state, but to know is the group is open or closed?


var id = activeDocument.activeLayer.id;

var r = new ActionReference();    
r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("layerSectionExpanded"));
r.putIdentifier(stringIDToTypeID("layer"), id);

var rez = executeActionGet(r).getBoolean(stringIDToTypeID("layerSectionExpanded"));

alert(rez?"Expanded":"Collapsed");

2 replies

Stephen Marsh
Community Expert
Community Expert
August 10, 2022

@milevic & @Zesty_wanderlust15A7 

 

Please try the following script, I have extended it with some of the ideas from this thread. Thank you @Zesty_wanderlust15A7 for the discussion and bouncing ideas back and forth!

 

I believe that it is a better option than my script linked in the other topic.

 

This is still a hack to overcome missing features of Photoshop, which only allows one to:

Collapse All Groups...

But why not collapse the active group? Why not expand all groups? Why not expand the active group? ...However, I digress!

 

Note: Script updated 17th August 2022

 

/*
Collapse Active Group.jsx
Modified by Stephen Marsh, 17th August 2022
https://gist.github.com/MarshySwamp/a39e3e1efee41174b3b92ee68c40fcd8
https://community.adobe.com/t5/photoshop-ecosystem-discussions/collapse-single-group-of-layers/m-p/13132297

Based on:
https://community.adobe.com/t5/photoshop-ecosystem/expand-collapse-a-group-via-javascript/m-p/7286298
By Vova_p, 16th February 2016

*** KNOWN LIMITATIONS & GOTCHAS ***
This script is a hack to overcome a shortcoming of the original implementation of layer groups/sets:
+ Layers clipped to the group will lose their clipping group property
+ Default layer names such as "Layer 6" may be auto-renamed by Photoshop to "Layer 10" etc.
*/

#target photoshop

if (app.documents.length > 0) {

    function main() {

        if (activeDocument.activeLayer.typename === "LayerSet") {

            // Set the original document
            var origDoc = app.activeDocument;

            // Doc name variable
            var origDocName = activeDocument.name;

            // Store the name of the group
            var groupname = activeDocument.activeLayer.name;

            // Copy the active layer properties to a layer style (opacity, fill, blend mode, blend-if etc)
            var idcopyEffects = stringIDToTypeID("copyEffects");
            executeAction(idcopyEffects, undefined, DialogModes.NO);

            // Toggle the active layer visibility
            toggleLayerVisibility(true);

            // Create the temp doc from active layer group
            newDocFromLayer("_tempDoc");

            // Set the "destination" group variable
            var destinationGroup = activeDocument.activeLayer.name;

            // Dupe the set into a temp group
            activeDocument.activeLayer.duplicate();

            // Set the duped "source" group variable
            var sourceGroup = activeDocument.layers[0].name;

            // Ungroup the group to select all the child elements
            unGroup();

            // Group the selected layers to collapse the group
            groupSelectedLayers();

            // Recall the original group name
            activeDocument.activeLayer.name = groupname;

            // Copy the layer mask with all properties from the temp group
            copyLayerMask();

            // Restore the layer style to the new collapsed group
            pasteEffects(true);

            // Select and remove the temp group
            activeDocument.activeLayer = activeDocument.layers[0];
            activeDocument.activeLayer.remove();

            // Dupe the group back to the original doc
            dupeLayer();

            // Close the temp doc
            activeDocument.close(SaveOptions.DONOTSAVECHANGES);

            // Return to the original document
            app.activeDocument = origDoc;

            // Select the visible backward layer
            selectForwardORBackwardLayer(false, "backwardEnum");

            // Delete the original expanded group
            removeGroup();

            // Select the visible forward layer
            selectForwardORBackwardLayer(false, "forwardEnum");

            // Toggle the original active layer visibility
            toggleLayerVisibility(true);

        } else {
            alert("Only layer groups can be collapsed!");
        }

        /***** Functions *****/

        function dupeLayer() {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var list = new ActionList();
            var reference = new ActionReference();
            var reference2 = new ActionReference();
            reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(s2t("null"), reference);
            reference2.putName(s2t("document"), origDocName);
            descriptor.putReference(s2t("to"), reference2);
            descriptor.putInteger(s2t("version"), 5);
            list.putInteger(0);
            descriptor.putList(s2t("ID"), list);
            executeAction(s2t("duplicate"), descriptor, DialogModes.NO);
        }

        function toggleLayerVisibility(toggleOptionsPalette) {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var list = new ActionList();
            var reference = new ActionReference();
            reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            list.putReference(reference);
            descriptor.putList(s2t("null"), list);
            descriptor.putBoolean(s2t("toggleOptionsPalette"), toggleOptionsPalette);
            executeAction(s2t("show"), descriptor, DialogModes.NO);
        }

        function newDocFromLayer(docName) {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var reference = new ActionReference();
            var reference2 = new ActionReference();
            reference.putClass(s2t("document"));
            descriptor.putReference(s2t("null"), reference);
            descriptor.putString(s2t("name"), docName);
            reference2.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(s2t("using"), reference2);
            descriptor.putInteger(s2t("version"), 0);
            executeAction(s2t("make"), descriptor, DialogModes.NO);
        }

        function unGroup() {
            function c2t(s) {
                return app.charIDToTypeID(s);
            }
            var s2t = function (s) {
                return app.stringIDToTypeID(s);
            };
            var descriptor = new ActionDescriptor();
            var reference = new ActionReference();
            reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(c2t("null"), reference);
            executeAction(s2t("ungroupLayersEvent"), descriptor, DialogModes.NO);
        }

        function groupSelectedLayers() {
            function c2t(s) {
                return app.charIDToTypeID(s);
            }
            var s2t = function (s) {
                return app.stringIDToTypeID(s);
            };
            var descriptor = new ActionDescriptor();
            var reference = new ActionReference();
            var reference2 = new ActionReference();
            reference.putClass(s2t("layerSection"));
            descriptor.putReference(c2t("null"), reference);
            reference2.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(s2t("from"), reference2);
            executeAction(s2t("make"), descriptor, DialogModes.NO);
        }

        function copyLayerMask() {
            // Copy layer mask - preserving feather, density
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var reference = new ActionReference();
            var reference2 = new ActionReference();
            descriptor.putClass(s2t("new"), s2t("channel"));
            reference.putEnumerated(s2t("channel"), s2t("channel"), s2t("mask"));
            reference.putName(s2t("layer"), destinationGroup); // Destination group name
            descriptor.putReference(s2t("at"), reference);
            reference2.putEnumerated(s2t("channel"), s2t("channel"), s2t("mask"));
            reference2.putName(s2t("layer"), sourceGroup); // Source group name
            descriptor.putReference(s2t("using"), reference2);
            executeAction(s2t("make"), descriptor, DialogModes.NO);
        }

        function selectForwardORBackwardLayer(makeVisible, forwardORbackward) {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var list = new ActionList();
            var reference = new ActionReference();
            // "forwardEnum" or "backwardEnum"
            reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t(forwardORbackward));
            descriptor.putReference(s2t("null"), reference);
            // true or false
            descriptor.putBoolean(s2t("makeVisible"), makeVisible);
            list.putInteger(15);
            descriptor.putList(s2t("layerID"), list);
            executeAction(s2t("select"), descriptor, DialogModes.NO);
        }

        function removeGroup() {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            var reference = new ActionReference();
            reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(s2t("null"), reference);
            executeAction(s2t("delete"), descriptor, DialogModes.NO);
        }

        function pasteEffects(allowPasteFXOnLayerSet) {
            function s2t(s) {
                return app.stringIDToTypeID(s);
            }
            var descriptor = new ActionDescriptor();
            descriptor.putBoolean(s2t("allowPasteFXOnLayerSet"), allowPasteFXOnLayerSet);
            executeAction(s2t("pasteEffects"), descriptor, DialogModes.NO);
        }
    }
    app.activeDocument.suspendHistory("Collapse Active Group.jsx", "main()");

} else {
    alert('You must have a document open!');
}

 

Zesty_wanderlust15A7
Known Participant
August 10, 2022

Cool. I agree this is a better direction and I suspect you can get there all the way.

This one still loses the mask as well...

I PM'd you yesterday what I use to copy a mask, preserving Feather and Density. If you want to save the mask as a channel, you run into the problem that you mentioned of possibly not being able to read some specs of a Group mask (which you need, as making it a channel loses these specs).

-

I think I would first rename the Group to a failsafe name, as I'd want that for the function restoring the mask. If possible, I might then go up and count how many layers are clipped to the Group (and reselect the failsafe group name). At the end, I'd use this number in a loop to reclip layers above the Group.

-

(I haven't been getting many notifications either, but a few today.)

Stephen Marsh
Community Expert
Community Expert
August 9, 2022

You can try the script that I created here:

 

https://community.adobe.com/t5/photoshop-ecosystem-discussions/action-or-script-to-expand-unfold-layer-groups/m-p/13077014#U13088415

 

I just updated it, it has not had exhaustive testing so it may or may not work as intended with your unique layer structure.

 

Feedback (good or bad) would be appreciated!

 

Zesty_wanderlust15A7
Known Participant
August 9, 2022

I didn't try it but came across that code recently.

Wouldn't it be easier to move all layers out of the Group, delete the Group, and regroup the layers?

Maybe it's what you're doing in a dupe; haven't checked it out line by line...

Stephen Marsh
Community Expert
Community Expert
August 9, 2022

@Zesty_wanderlust15A7 wrote:

I didn't try it but came across that code recently.

Wouldn't it be easier to move all layers out of the Group, delete the Group, and regroup the layers?

Maybe it's what you're doing in a dupe; haven't checked it out line by line...


 

@Zesty_wanderlust15A7  Please do try it, I'd appreciate the feedback.

 

What is easy for one person may not be easy for another, I did it the way that was easiest for me which produced the required end result, while trying to keep the solution robust and maintaining all properties of the original parent group and child layers.

 

I'd be interested in seeing your solution, always keen to find another and or better way to do the same thing. It's a shame that a hack like this is required.