Help with part of a Photoshop script?

I cobbled together quite a large script for Photoshop, but have run into a problem with part of it. Part of the script moves the selected layer in Photoshop to a specified folder/group. The part I’m having difficulty with is if the selected layer is within a folder, or a few nested folders.

If I know how many folders the selected layer is in (and their names) then I can adjust the script accordingly, but I’d like it to work when nested in any amount of folders so I don’t have to keep changing the script

Here’s the part of the script:

tell application id "com.adobe.Photoshop"
	tell current document
		set selectedLayer to name of current layer
		set layerContainer to name of container of current layer
		set rootContainer to name of container of container of current layer

		
		move layer selectedLayer of layer set layerContainer of layer set rootContainer to layer set "mask" of layer set "colour fill" of layer set "Artwork"
	end tell
end tell

So the part at the bottom is fine where it moves the selected layer to ‘Artwork’ folder > ‘colour fill’ folder > ‘mask’ folder.

I guess I’d just need a script to count the number of folders the selected layer is in (and set each nested folder as variables?) so that I could move the selected layer no matter how many folders it’s nested in (it seems you have to specify the folders that the selected layer is nested in, in order to be able to move the layer to another folder).

I’d bypass all the “figuring out how deep the nesting goes” thing by getting the Photoshop Index Number for the selected layer, convert the index to a reference, then move it by reference.

I recently posted this script
https://macscripter.net/viewtopic.php?id=46407
Which does that, except it’s for renaming layers instead of moving layers.

So it would just need a minor modification, as below.

As it stands now, it would move any set of selected layers to the destination - you could do more than one at a time if you wanted.


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

global foundLayer -- recursive function to drill down arbitrary layer nesting, setting global to exit function regardless of how deep the calls go
set selectedLayerIndexes to get_selected_layer_indexes() -- get the index numbers for all selected layers
set selectedLayerReferences to {}
tell application "Adobe Photoshop CC 2018" to tell the current document to set allLayers to the layers

-- convert each layer index to a layer reference
repeat with aLayerIndex in selectedLayerIndexes
	set foundLayer to false
	copy recurse_layer_sets(allLayers, aLayerIndex) to end of selectedLayerReferences
end repeat

-- move each layer
tell application "Adobe Photoshop CC 2018"
	set currentDoc to the current document
	tell currentDoc
		set repeatCount to 0
		repeat with i from (count of selectedLayerReferences) to 1 by -1
			set aLayer to item i of selectedLayerReferences
			move aLayer to layer set "mask" of layer set "colour fill" of layer set "Artwork"
		end repeat
	end tell
end tell

-- drills through all layer sets to look up layers by itemindex and return an Applescript reference to the layer
on recurse_layer_sets(layerList, theItemIndex)
	set theItemIndex to theItemIndex as number -- it's already an integer; not sure why this is necessary
	if foundLayer is not false then return foundLayer
	tell application "Adobe Photoshop CC 2018"
		set currentDoc to the current document
		tell currentDoc
			set layerGroupCount to the count of layerList
			repeat with i from 1 to layerGroupCount
				set aLayer to item i of layerList
				if the (itemindex of aLayer) as number is theItemIndex then
					set foundLayer to aLayer
					exit repeat
				else
					if the class of aLayer is layer set then my recurse_layer_sets((layers of aLayer), theItemIndex)
				end if
			end repeat
		end tell
	end tell
	return foundLayer
end recurse_layer_sets

-- AM code to get the indexes of all selected layers
on get_selected_layer_indexes()
	tell application "Adobe Photoshop CC 2018"
		set selectedLayers to do javascript "
getSelectedLayersIdx()
function getSelectedLayersIdx() {  
    var selectedLayers = new Array;  
    var ref = new ActionReference();  
    ref.putEnumerated(charIDToTypeID(\"Dcmn\"), charIDToTypeID(\"Ordn\"), charIDToTypeID(\"Trgt\"));  
    var desc = executeActionGet(ref);  
    if (desc.hasKey(stringIDToTypeID(\"targetLayers\"))) {  
        desc = desc.getList(stringIDToTypeID(\"targetLayers\"));  
        var c = desc.count  
        var selectedLayers = new Array();  
        for (var i = 0; i < c; i++) {  
            try {  
                docRef.backgroundLayer;  
                selectedLayers.push(desc.getReference(i).getIndex());  
            } catch (e) {  
                selectedLayers.push(desc.getReference(i).getIndex() + 1);  
            }  
        }  
    } else {  
        var ref = new ActionReference();  
        ref.putProperty(charIDToTypeID(\"Prpr\"), charIDToTypeID(\"ItmI\"));  
        ref.putEnumerated(charIDToTypeID(\"Lyr \"), charIDToTypeID(\"Ordn\"), charIDToTypeID(\"Trgt\"));  
        try {  
            docRef.backgroundLayer;  
            selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID(\"ItmI\")) - 1);  
        } catch (e) {  
            selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID(\"ItmI\")));  
        }  
    }  
    return selectedLayers;  
}  "
	end tell
	set selectedLayersListText to text_to_list(selectedLayers, ",") -- Javascript spits out comma delimited list
	-- Javascript also spits out numbers as strings; switch to integers
	set selectedLayersList to {}
	repeat with anItem in selectedLayersListText
		set selectedLayersList to selectedLayersList & (anItem as number)
	end repeat
	return selectedLayersList
end get_selected_layer_indexes

-- converts text delimited strings to AS lists
on text_to_list(someText, aSeparator)
	set {delimitHolder, AppleScript's text item delimiters} to {AppleScript's text item delimiters, aSeparator}
	set outputList to the text items of someText
	set AppleScript's text item delimiters to delimitHolder
	return outputList
end text_to_list

That’s great, thanks a lot!

If I select a single layer it works perfectly. But if I select multiple layers then it doesn’t quite work right, it moves some of the layers but not all of them and shows an error.

For example, here I select 4 layers

Then run script and one of the selected layers doesn’t get moved (green), and a layer that wasn’t selected gets moved (orange).

When running the script it highlights this line

move aLayer to layer set "mask" of layer set "colour fill" of layer set "Artwork"

And the error message in Script Editor says:

error “Adobe Photoshop CC 2018 got an error: Can’t get art layer 4 of layer set 2 of layer set 1 of document "Test_Document.psd".” number -1728 from art layer 4 of layer set 2 of layer set 1 of document “Test_Document.psd”

Any idea on what could be the problem there?

Hi. If I understand the original question, the problem appears to be that the selection is being purposefully deconstructed and reconstructed when the object reference is fine as-is.

tell application "Adobe Photoshop CS3"'s document 1 to move current layer to layer set "mask" of layer set "colour fill" of layer set "Artwork"

Ah, yes, I see the problem here. The AppleScript references are not absolute references to the layers - they are relative references. Once you start moving things, an Applescript reference like:

won’t still refer to the same layer if other layers have moved around.

So it’ll always move a single selected layer correctly, but after that, all bets are off because that first move starts changing what (if anything) the remaining references refer to.

I haven’t experimented yet, but I don’t think Marc’s solution is going to solve this situation with multiple layers, because Applescript’s “current layer” only refers to the active layer, not the other selected layers when there is a multiple-layer selection.

This is certainly fixable. But I need to check and see what layer identifier remains static as the layers are moved, and use that to identify them to perform the move.

I don’t have time for that at the moment, but maybe in the next few days.

I’m posting my whole script below so you can see what’s going on. The script creates the Artwork, colour fill, and mask folders, and in the process loses focus of the selected layer. So in my existing script it has to specify the path to the previously selected layer in order to move it.

But if there’s a better/simpler way then please let me know :slight_smile:

Sure, no hurry. I appreciate the help, so whenever’s good for you :smiley:

Here’s the whole of my script:

set colourFromClipboard to (get the clipboard)


tell application id "com.adobe.Photoshop"
	activate
	tell current document
		set selectedLayer to current layer
		set layerName to name of current layer
		set layerContainer to name of container of current layer
		
		(* Make sure current layer/group as visible *)
		set visible of selectedLayer to true
	end tell
	
	
	(* Fill selected vector shape with black *)
	tell current document
		do javascript "var c = new SolidColor();      
c.rgb.hexValue = '000000'   

set_fill_color(c);
//set_stroke_color(c);
function set_stroke_color(c)
    {
    try {
        var d = new ActionDescriptor();
        var r = new ActionReference();
        r.putEnumerated(stringIDToTypeID('contentLayer'), stringIDToTypeID('ordinal'), stringIDToTypeID('targetEnum'));
        d.putReference(stringIDToTypeID('null'), r);
        var d1 = new ActionDescriptor();
        var d2 = new ActionDescriptor();
        var d3 = new ActionDescriptor();
        var d4 = new ActionDescriptor();
        d4.putDouble(stringIDToTypeID('red'),   c.rgb.red);
        d4.putDouble(stringIDToTypeID('green'), c.rgb.green);
        d4.putDouble(stringIDToTypeID('blue'),  c.rgb.blue);
        d3.putObject(stringIDToTypeID('color'), stringIDToTypeID('RGBColor'), d4);
        d2.putObject(stringIDToTypeID('strokeStyleContent'), stringIDToTypeID('solidColorLayer'), d3);
        d2.putBoolean(stringIDToTypeID('strokeEnabled'), true);
        d1.putObject(stringIDToTypeID('strokeStyle'), stringIDToTypeID('strokeStyle'), d2);
        d.putObject(stringIDToTypeID('to'), stringIDToTypeID('shapeStyle'), d1);
        executeAction(stringIDToTypeID('set'), d, DialogModes.NO);
        }
    catch (e) { throw(e); }
    }
function set_fill_color(c)
    {
    try {
        var d = new ActionDescriptor();
        var r = new ActionReference();
        r.putEnumerated(stringIDToTypeID('contentLayer'), stringIDToTypeID('ordinal'), stringIDToTypeID('targetEnum'));
        d.putReference(stringIDToTypeID('null'), r);
        var d1 = new ActionDescriptor();
        var d2 = new ActionDescriptor();
        var d3 = new ActionDescriptor();
        d3.putDouble(stringIDToTypeID('red'),   c.rgb.red);
        d3.putDouble(stringIDToTypeID('green'), c.rgb.green);
        d3.putDouble(stringIDToTypeID('blue'),  c.rgb.blue);
        d2.putObject(stringIDToTypeID('color'), stringIDToTypeID('RGBColor'), d3);
        d1.putObject(stringIDToTypeID('fillContents'), stringIDToTypeID('solidColorLayer'), d2);
        var d4 = new ActionDescriptor();
        d4.putBoolean(stringIDToTypeID('fillEnabled'), true);
        d1.putObject(stringIDToTypeID('strokeStyle'), stringIDToTypeID('strokeStyle'), d4);
        d.putObject(stringIDToTypeID('to'), stringIDToTypeID('shapeStyle'), d1);
        executeAction(stringIDToTypeID('set'), d, DialogModes.NO);
        }
    catch (e) { throw(e); }
    }" show debugger on runtime error
	end tell
	
	
	(* Create Folders *)
	tell current document
		set artworkFolder to "Artwork"
		if exists layer set named artworkFolder then
			(* Do nothing *)
		else
			make new layer set at beginning with properties {name:artworkFolder}
		end if
		
		set colourFillFolder to "colour fill"
		if exists layer set named colourFillFolder in layer set artworkFolder then
			(* Do nothing *)
		else
			make new layer set in layer set artworkFolder with properties {name:colourFillFolder}
		end if
		
		set blendingMaskFolder to "mask"
		if exists layer set named blendingMaskFolder in layer set colourFillFolder in layer set artworkFolder then
			(* Do nothing *)
		else
			make new layer set in layer set colourFillFolder in layer set artworkFolder ¬
				with properties {name:blendingMaskFolder}
		end if
	end tell
	
	
	(* Set blending mode for mask folder *)
	tell current document
		do javascript "
 blend_if(0,0, 255,255, 0,0, 0,255, 'k');
function blend_if(db0,db1, dw0,dw1, sb0,sb1, sw0,sw1, ch)
    {
    try {
        if (db0 == undefined) db0 = 0;
        if (db1 == undefined) db1 = db0;
        if (dw0 == undefined) dw0 = 255;
        if (dw1 == undefined) dw1 = dw0;
        if (sb0 == undefined) sb0 = 0;
        if (sb1 == undefined) sb1 = sb0;
        if (sw0 == undefined) sw0 = 255;
        if (sw1 == undefined) sw1 = sw0;
        if (ch == undefined) ch = 'krgb';
        var use_r = false;
        var use_g = false;
        var use_b = false;
        var use_k = false;
        if (ch.indexOf('r') >= 0) use_r = true;
        if (ch.indexOf('g') >= 0) use_g = true;
        if (ch.indexOf('b') >= 0) use_b = true;
        if (ch.indexOf('k') >= 0) use_k = true;
        var desc3 = new ActionDescriptor();
        var desc4 = new ActionDescriptor();
        var ref1 = new ActionReference();
        var list1 = new ActionList();
        ref1.putEnumerated( charIDToTypeID( 'Lyr ' ), charIDToTypeID( 'Ordn' ), charIDToTypeID( 'Trgt' ) );
        desc3.putReference( charIDToTypeID( 'null' ), ref1 );
        for (var i = 0; i < 4; i++)
            {
            var desc5 = new ActionDescriptor();
            var ref2 = new ActionReference();
            use_cont = false;
              switch ( i )
                {
                case 0: if (!use_k) { use_cont = true; break; } ref2.putEnumerated( charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Gry ' ) ); break;
                case 1: if (!use_r) { use_cont = true; break; } ref2.putEnumerated( charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Rd  ' ) ); break;
                case 2: if (!use_g) { use_cont = true; break; } ref2.putEnumerated( charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Grn ' ) ); break;
                case 3: if (!use_b) { use_cont = true; break; } ref2.putEnumerated( charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Bl  ' ) ); break;
                }
            if (use_cont) continue;
            desc5.putReference( charIDToTypeID( 'Chnl' ), ref2 );
            desc5.putInteger( charIDToTypeID( 'SrcB' ), sb0 );
            desc5.putInteger( charIDToTypeID( 'Srcl' ), sb1 );
            desc5.putInteger( charIDToTypeID( 'SrcW' ), sw0 );
            desc5.putInteger( charIDToTypeID( 'Srcm' ), sw1 );
            desc5.putInteger( charIDToTypeID( 'DstB' ), db0 );
            desc5.putInteger( charIDToTypeID( 'Dstl' ), db1 );
            desc5.putInteger( charIDToTypeID( 'DstW' ), dw0 );
            desc5.putInteger( charIDToTypeID( 'Dstt' ), dw1 );
            list1.putObject( charIDToTypeID( 'Blnd' ), desc5 );
            }
        desc4.putList( charIDToTypeID( 'Blnd' ), list1 );
        desc3.putObject( charIDToTypeID( 'T   ' ), charIDToTypeID( 'Lyr ' ), desc4 );
        executeAction( charIDToTypeID( 'setd' ), desc3, DialogModes.NO );
        }
    catch (e) { alert(e); }
}" show debugger on runtime error
	end tell
	
	
	(* Move selected layer to 'mask' folder *)
	tell current document
		move layer layerName of layer set layerContainer to layer set blendingMaskFolder of layer set colourFillFolder of layer set artworkFolder
		(* Select 'colour fill' folder *)
		set current layer to layer set colourFillFolder of layer set artworkFolder
	end tell
end tell


(* Show dialog & ask to choose colour *)
activate me
set colourList to {"Clipboard (#" & colourFromClipboard & ")", "Black", "White"}
set chosenColour to (choose from list colourList with prompt "Fill Colour?" without multiple selections allowed) as text

if chosenColour is "Clipboard (#" & colourFromClipboard & ")" then
	set theColour to colourFromClipboard
	
else if chosenColour is "Black" then
	set theColour to "000000"
	
else if chosenColour is "White" then
	set theColour to "FFFFFF"
end if


(* Add chosen colour to folder as colour overlay style *)
tell application id "com.adobe.Photoshop"
	tell current document
		do javascript "var c = new SolidColor();    
c.rgb.hexValue = " & quoted form of theColour & " 
  
app.activeDocument.suspendHistory('TMP', 'aaa()');      
executeAction( charIDToTypeID( 'undo' ), undefined, DialogModes.NO );    
executeAction( charIDToTypeID( 'PaFX' ), undefined, DialogModes.NO );    
function aaa()    
    {    
    app.activeDocument.artLayers.add();    
    var idsetd = charIDToTypeID( 'setd' );      
        var desc9 = new ActionDescriptor();      
        var idnull = charIDToTypeID( 'null' );      
            var ref1 = new ActionReference();      
            var idPrpr = charIDToTypeID( 'Prpr' );      
            var idLefx = charIDToTypeID( 'Lefx' );      
            ref1.putProperty( idPrpr, idLefx );      
            var idLyr = charIDToTypeID( 'Lyr ' );      
            var idOrdn = charIDToTypeID( 'Ordn' );      
            var idTrgt = charIDToTypeID( 'Trgt' );      
            ref1.putEnumerated( idLyr, idOrdn, idTrgt );      
        desc9.putReference( idnull, ref1 );      
        var idT = charIDToTypeID( 'T   ' );      
            var desc10 = new ActionDescriptor();      
            var idScl = charIDToTypeID( 'Scl ' );      
            var idPrc = charIDToTypeID( '#Prc' );      
            desc10.putUnitDouble( idScl, idPrc, 100.000000 );      
            var idSoFi = charIDToTypeID( 'SoFi' );      
                var desc11 = new ActionDescriptor();      
                var idenab = charIDToTypeID( 'enab' );      
                desc11.putBoolean( idenab, true );      
                var idpresent = stringIDToTypeID( 'present' );      
                desc11.putBoolean( idpresent, true );      
                var idshowInDialog = stringIDToTypeID( 'showInDialog' );      
                desc11.putBoolean( idshowInDialog, true );      
                var idMd = charIDToTypeID( 'Md  ' );      
                var idBlnM = charIDToTypeID( 'BlnM' );      
                var idNrml = charIDToTypeID( 'Nrml' );      
                desc11.putEnumerated( idMd, idBlnM, idNrml );      
                var idClr = charIDToTypeID( 'Clr ' );      
                    var desc12 = new ActionDescriptor();      
                    var idRd = charIDToTypeID( 'Rd  ' );      
                    desc12.putDouble( idRd, c.rgb.red );     // RED    
                    var idGrn = charIDToTypeID( 'Grn ' );      
                    desc12.putDouble( idGrn, c.rgb.green );  // GREEN    
                    var idBl = charIDToTypeID( 'Bl  ' );      
                    desc12.putDouble( idBl, c.rgb.blue );    // BLUE    
                var idRGBC = charIDToTypeID( 'RGBC' );      
                desc11.putObject( idClr, idRGBC, desc12 );      
                var idOpct = charIDToTypeID( 'Opct' );      
                var idPrc = charIDToTypeID( '#Prc' );      
                desc11.putUnitDouble( idOpct, idPrc, 100.000000 );      
            var idSoFi = charIDToTypeID( 'SoFi' );      
            desc10.putObject( idSoFi, idSoFi, desc11 );      
        var idLefx = charIDToTypeID( 'Lefx' );      
        desc9.putObject( idT, idLefx, desc10 );      
    executeAction( idsetd, desc9, DialogModes.NO );           
    executeAction( charIDToTypeID( 'CpFX' ), undefined, DialogModes.NO );    
    }" show debugger on runtime error
	end tell
end tell


(* Select previously selected layer *)
tell application id "com.adobe.Photoshop"
	activate
	tell current document
		set current layer to layer layerName of layer set blendingMaskFolder ¬
			of layer set colourFillFolder of layer set artworkFolder
	end tell
end tell

Current layer is problematic, as there can be only one and the references are relative, as noted by t.spoon. The best option may be to abandon your desired multi-selection method, which become even more troublesome with nested items. Your best alternative to that option may be to move the selecting into the script, excepting the first instance.

tell application "Adobe Photoshop CS3"'s document 1
	set isTarget to current layer
	if exists layer set "art"'s layer set "fill"'s layer set "mask" then
		set nextTarget to layer set "art"'s layer set "fill"'s layer set "mask"
	else
		set nextTarget to make layer set with properties {name:"mask"} at make layer set with properties {name:"fill"} at make layer set with properties {name:"art"}
	end if
	if isTarget's container's class = document then
		try --prevent action on immovable objects
			repeat with focus in my (choose from list (get art layers's name) with multiple selections allowed)
				move layer (focus's contents) to nextTarget
			end repeat
		end try
	else
		try --ditto
			repeat with focus in my (choose from list (get isTarget's container's art layers's name) with multiple selections allowed)
				move current layer's container's layer (focus's contents) to nextTarget
			end repeat
		end try
	end if
end tell

Being able to select multiple layers and have them moved would be good, but not essential :slight_smile:

I tried your script, but unfortunately thew up an error:

error "Can’t get container of current layer." number -1728 from «class ctnr» of «class crLr»

What are you initially selecting? It’s fine to select a layer within a layer set, but I haven’t accounted for the eventuality that the initial item actually is a layer set. Try a couple different choices and post more detail if it continues to fail.

I’m sure this could be much, much simpler if I knew more Javascript AM code.

But in some testing I did, it seems to be working.

Photoshop’s “layer index” that the javascript function returns is the same as the Applescript references in that it’s relative - move one layer, and the rest of the references change what they refer to.

There’s “layer ID,” which stays static with moves.

I couldn’t find code to return the layer ID’s though.

So I’m still getting the indexes of the selected layers, then converting them to a list of Layer ID’s. Then I one by one convert the layer ID’s to references and move them. Let me know if this works for you.


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

tell application "Adobe Photoshop CC 2018"
	tell the current document
		set allLayers to the layers
		set moveToLayerSet to layer set "Move To Folder" -- set the location you want the files moved to here
	end tell
end tell

global foundLayerID -- recursive function to drill down arbitrary layer nesting, setting global to exit function regardless of how deep the calls go
global foundLayerReference
set selectedLayerIndexes to get_selected_layer_indexes() -- get the index numbers for all selected layers
set selectedLayerIDs to {}

-- convert each layer index to a layer reference
repeat with aLayerIndex in selectedLayerIndexes
	set foundLayerID to false
	copy get_layer_ID_from_layer_index(allLayers, aLayerIndex) to end of selectedLayerIDs
end repeat

move_layers_by_layer_ID(moveToLayerSet, allLayers, selectedLayerIDs)

on move_layers_by_layer_ID(moveLocation, layerList, moveLayerIDs)
	set moveLayerCount to the count of moveLayerIDs
	repeat with i from 1 to moveLayerCount
		set aLayerID to item i of moveLayerIDs
		set foundLayerReference to false
		set layerRef to my get_layer_reference_from_layerID(layerList, aLayerID)
		tell application "Adobe Photoshop CC 2018" to tell the current document to move layerRef to moveLocation
	end repeat
	
end move_layers_by_layer_ID

on get_layer_reference_from_layerID(layerList, layerID)
	set layerID to layerID as number
	if foundLayerReference is not false then return foundLayerReference
	tell application "Adobe Photoshop CC 2018"
		tell the current document
			set layerGroupCount to the count of layerList
			repeat with i from 1 to layerGroupCount
				set aLayer to item i of layerList
				if the (id of aLayer) as number is layerID then
					set foundLayerReference to aLayer
					exit repeat
				else
					if the class of aLayer is layer set then my get_layer_reference_from_layerID((layers of aLayer), layerID)
				end if
			end repeat
		end tell
	end tell
	return foundLayerReference
end get_layer_reference_from_layerID


on get_layer_ID_from_layer_index(layerList, theItemIndex)
	set theItemIndex to theItemIndex as number -- it's already an integer; not sure why this is necessary
	if foundLayerID is not false then return foundLayerID
	tell application "Adobe Photoshop CC 2018"
		tell the current document
			set layerGroupCount to the count of layerList
			repeat with i from 1 to layerGroupCount
				set aLayer to item i of layerList
				if the (itemindex of aLayer) as number is theItemIndex then
					set foundLayerID to the id of aLayer
					exit repeat
				else
					if the class of aLayer is layer set then my get_layer_ID_from_layer_index((layers of aLayer), theItemIndex)
				end if
			end repeat
		end tell
	end tell
	return foundLayerID
end get_layer_ID_from_layer_index

-- AM code to get the indexes of all selected layers
on get_selected_layer_indexes()
	tell application "Adobe Photoshop CC 2018"
		set selectedLayers to do javascript "
getSelectedLayersIdx()
function getSelectedLayersIdx() {  
    var selectedLayers = new Array;  
    var ref = new ActionReference();  
    ref.putEnumerated(charIDToTypeID(\"Dcmn\"), charIDToTypeID(\"Ordn\"), charIDToTypeID(\"Trgt\"));  
    var desc = executeActionGet(ref);  
    if (desc.hasKey(stringIDToTypeID(\"targetLayers\"))) {  
        desc = desc.getList(stringIDToTypeID(\"targetLayers\"));  
        var c = desc.count  
        var selectedLayers = new Array();  
        for (var i = 0; i < c; i++) {  
            try {  
                docRef.backgroundLayer;  
                selectedLayers.push(desc.getReference(i).getIndex());  
            } catch (e) {  
                selectedLayers.push(desc.getReference(i).getIndex() + 1);  
            }  
        }  
    } else {  
        var ref = new ActionReference();  
        ref.putProperty(charIDToTypeID(\"Prpr\"), charIDToTypeID(\"ItmI\"));  
        ref.putEnumerated(charIDToTypeID(\"Lyr \"), charIDToTypeID(\"Ordn\"), charIDToTypeID(\"Trgt\"));  
        try {  
            docRef.backgroundLayer;  
            selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID(\"ItmI\")) - 1);  
        } catch (e) {  
            selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID(\"ItmI\")));  
        }  
    }  
    return selectedLayers;  
}  "
	end tell
	set selectedLayersListText to text_to_list(selectedLayers, ",") -- Javascript spits out comma delimited list
	-- Javascript also spits out numbers as strings; switch to integers
	set selectedLayersList to {}
	repeat with anItem in selectedLayersListText
		set selectedLayersList to selectedLayersList & (anItem as number)
	end repeat
	return selectedLayersList
end get_selected_layer_indexes

-- converts text delimited strings to AS lists
on text_to_list(someText, aSeparator)
	set {delimitHolder, AppleScript's text item delimiters} to {AppleScript's text item delimiters, aSeparator}
	set outputList to the text items of someText
	set AppleScript's text item delimiters to delimitHolder
	return outputList
end text_to_list

I just tried selecting ‘regular’ single layers.

One inside a single folder, and one not in a folder. When it shows the error message in Script Editor it also highlights ‘document’ in this line of the script:

if isTarget's «class ctnr»'s class = document then

Yeah, you would have thought it would be much more straightforward than this!

But this works perfectly (with multiple layers selected), thank you so much for the help! :smiley:

Hmm. t.spoon’s code appears to not be backwards compatible, as it states a requested property is unavailable, and I don’t understand enough JavaScript to attempt to modify the method for my use.

I suspect that you edited my code to reflect the application ID as the tell object, as in your other posts; my dictionary loses the connection when telling “com.adobe…” and returns the same raw events and subsequent error you reported. For my reference, if you restart PS and plug in your literal version into the code in post #7, does it work? If it still errors, please post the event log from this:


tell application "Adobe Photoshop CS3" --change to your version... Adobe Photoshop CC?
	activate (launch)
	tell (make document) to {its class, current layer's class, current layer's container, current layer's container's class}
end tell

Thanks for persevering with this :slight_smile:

I tried your original script again, but only changed ‘tell application “Adobe Photoshop CS3”’ to ‘tell application "Adobe Photoshop CC 2018’.

After playing around with it I have managed to get it to work… sort of.

When I run it for the first time I get the same error as always (but can see that the ‘art’, ‘fill’ and ‘mask’ folders were successfully created). If I select the layer I want to move again, and then run the script again (after the folders have been created when the script ran for the first time) then it works fine.

Could it be that after the script has run the part that creates the folders (and the ‘mask’ folder is selected in the layers list in Ps) it loses focus/reference to the original selected layer?
And so it works the second time around because focus is on the selected layer, and it doesn’t need to create the folders again?

Here’s the result of the last script you posted:

tell application "Adobe Photoshop CC 2018"
	launch
	activate
	make new document
		--> document "Untitled-1"
	get class of document "Untitled-1"
		--> document
	get class of current layer of document "Untitled-1"
		--> art layer
	get container of current layer of document "Untitled-1"
		--> document "Untitled-1"
	get class of container of current layer of document "Untitled-1"
		--> document
end tell
Result:
{document, art layer, document "Untitled-1" of application "Adobe Photoshop CC 2018", document}

So I’m trying to integrate this with my original script, but have run into a problem.

The first part of my script creates folders/layer sets (code below), but means the previously selected layers become unselected before this part of the script is run (so your script doesn’t know which layers were selected in order to move them). And if I don’t create the folders then your script won’t work because it can’t find the target folders

Any ideas on the best way to make this work properly, and how the rest of my code (in my previous post) should fit in with it?

	(* Create Folders *)
	tell current document
		set artworkFolder to "Artwork"
		if exists layer set named artworkFolder then
			(* Do nothing *)
		else
			make new layer set at beginning with properties {name:artworkFolder}
		end if
		
		set colourFillFolder to "colour fill"
		if exists layer set named colourFillFolder in layer set artworkFolder then
			(* Do nothing *)
		else
			make new layer set in layer set artworkFolder with properties {name:colourFillFolder}
		end if
		
		set blendingMaskFolder to "mask"
		if exists layer set named blendingMaskFolder in layer set colourFillFolder in layer set artworkFolder then
			(* Do nothing *)
		else
			make new layer set in layer set colourFillFolder in layer set artworkFolder ¬
				with properties {name:blendingMaskFolder}
		end if
	end tell

Yes, you’ll want to start by running the parts of my script up through the repeat loop that builds the list of selectedLayerIDs.

The layer ID’s will not change as you create new layers, so this will be a list of what layers were selected before you do anything else and lose the selection.

Then go ahead and modify the document any way you need to - make the new folders, set the variable for moveToLayerSet to the new folder you made.

Then resume with my script for the move.

Thanks a lot (again)!

I managed to get it to work placing my other code where you said :smiley: