Dynamic Folderformat: setting folderformat for subfolders but not for parent

TL;DR
A script that can set the folderformat for subfolders of a specified folder but not for the folder itself ("everything below x should have this format"); before or after navigation event fires.

Usecase
In my pictures collection I have a folder where i want to have "newest first" as details list (because there are no images to see at this level), but its subfolders should be displayed as large thumbnails and grouped by date.
DOpus allows folderformats per folder or its subfolders, but not for "anything below this path", as this script does (or at least i did not find any satisfying way to accomplish this) As stated by Leo this is wrong.

Usage:
Add new Dynamicfolderformat objects to the array at the beginning

DynamicFolderFormat(rootPath, callBeforeChange, folderformat, customApplyFunction, useFolderformatAsFallback)
new DynamicFolderFormat("C:\\", true, "!default", function (beforeFolderChange, tabCommand){ Log("do what ever you want to do here"); return true; }, true)
  • rootPath: the folderformat will be applied to subfolders of this path, but not the folder itself
  • callBeforeChange: set format before or after folderchangeevent
  • folderformat: the format that will be applied but only if customApplyFunction is null or returns false and is not set for fallback
  • customApplyFunction: you can define your own event here
    return true if successful or false if not
    if false and useFolderformatAsFallback is true then the defined folderformat will be applied
    otherwise it will look for other DynamicFolderFormats that match this path

When defining a format for a certain folder and one for one of its (indirect) subfolders, make sure to have the "deeper" one further up in the DynamicFolderFormats array because otherwise it will be skipped since the path was already handled by the shorter one.

Resources/Installation
Installation Guide

Version 1.0 - 12.08.2021 - Initial Version Addon.FolderFormat.Dynamic.js.txt (6.3 KB)

// Addon.FolderFormat.Dynamic
// (c) 2021 Felix

// This is a script for Directory Opus.
// See https://www.gpsoft.com.au/DScripts/redirect.asp?page=scripts for development information.


//The actual customization data
var DynamicFolderFormats = 
[
	new DynamicFolderFormat("coll://Fotos/Urlaub/", true, "Dategrouped Image Collection"),
	new DynamicFolderFormat("C:\\Windows", true, "WindowsSystemFolder", function (beforeFolderChange, tabCommand){ Log("do what ever you want to do here"); return true; }, true),
	new DynamicFolderFormat("C:\\", false, "!user", function (afterFolderChangeData, tabCommand){ Log("do what ever you want to do here"); return true; }, true)
	//add your dynamicFolderFormats here
];

// Called by Directory Opus to initialize the script
function OnInit(initData)
{
	initData.name = "Addon.FolderFormat.Dynamic";
	initData.version = "1.0 2021.08.12";
	initData.copyright = "(c) 2021 Felix";
	initData.url = "https://resource.dopus.com/t/dynamic-folderformat-setting-folderformat-for-subfolders-but-not-for-parent/39119";
	initData.desc = "Script that sets custom folderformats for folders below chosen parent folders";
	initData.default_enable = true;
	initData.group = "Addon";
	initData.min_version = "12.0";
}

// Called before a new folder is read in a tab
// Check for dynamicFolderFormats to be applied before folder change
function OnBeforeFolderChange(beforeFolderChange)
{
	var tabCommand = CreateCommandForTab(beforeFolderChange.tab, beforeFolderChange.qualifiers);

	for(var i = 0; i < DynamicFolderFormats.length; i++)
	{
		var dynamicFolderFormat = DynamicFolderFormats[i];
		if(dynamicFolderFormat.callBeforeChange)
		{
			if(StartsWith(beforeFolderChange.path, dynamicFolderFormat.rootPath)) //should be a sufficient check
			{
				if(dynamicFolderFormat.customApplyFunction)
				{
					var result = dynamicFolderFormat.customApplyFunction(beforeFolderChange);
					if(result)
						return; //if true is returned, stop searching for other matching formats;
					else		//otherwise check if folderformat should be used as default, otherwise search for another dynamic folder format
					{
						if(dynamicFolderFormat.useFolderformatAsFallback)
						{
							tabCommand.RunCommand("Set FORMAT=\"" + dynamicFolderFormat.folderformat + "\"");
							return; //job is done
						}
						else
							continue; //look for another folder format
					}
				}
				else
					tabCommand.RunCommand("Set FORMAT=\"" + dynamicFolderFormat.folderformat + "\"");
					
				return; //If paths are matching only the first occurence will be applied
						//Paths that go "deeper" should be defined first
			}
		}			
	}
}

// Called after a new folder is read in a tab
// Check for dynamicFolderFormats to be applied after folder change
function OnAfterFolderChange(afterFolderChangeData)
{
	var tabCommand = CreateCommandForTab(afterFolderChangeData.tab, afterFolderChangeData.qualifiers);
		
	for(var i = 0; i < DynamicFolderFormats.length; i++)
	{
		var dynamicFolderFormat = DynamicFolderFormats[i];
		if(!dynamicFolderFormat.callBeforeChange)
		{
			//if(dynamicFolderFormat.path == afterFolderChangeData.path)
			if(StartsWith(dynamicFolderFormat.rootPath, afterFolderChangeData.path)) //should be a sufficient check
			{
				if(dynamicFolderFormat.customApplyFunction)
				{
					var result = dynamicFolderFormat.customApplyFunction(afterFolderChangeData, tabCommand);
					if(result)
						return; //if true is returned, stop searching for other matching formats;
					else		//otherwise check if folderformat should be used as default, otherwise search for another dynamic folder format
					{
						if(dynamicFolderFormat.useFolderformatAsFallback)
						{
							tabCommand.RunCommand("Set FORMAT=\"" + dynamicFolderFormat.folderformat + "\"");
							return; //job is done
						}
						else
							continue; //look for another folder format
					}
				}
				else
					tabCommand.RunCommand("Set FORMAT=\"" + dynamicFolderFormat.folderformat + "\"");
					
				return; //If paths are matching only the first occurence will be applied
						//Paths that go "deeper" should be defined first
			}
		}			
	}
}

//Create a command that has the tab set as source with the qualifiers applied that were set at folder change event
function CreateCommandForTab(tab, qualifiers)
{
	var cmd = DOpus.Create.Command();
	cmd.SetSourceTab(tab);
	if(qualifiers)
		cmd.SetQualifiers(qualifiers);
	return cmd;
}

//Datastructure for saving the 
function DynamicFolderFormat(rootPath, callBeforeChange, folderformat, customApplyFunction, useFolderformatAsFallback)
{
	this.rootPath 				= rootPath; 					//the folderformat will be applied to subfolders of this path, but not the folder itself
	this.callBeforeChange		= callBeforeChange;				//set format before or after folderchangeevent
	this.folderformat			= folderformat; 				//the format that will be applied but only if customApplyFunction is null or returns false and is not set for fallback
	this.customApplyFunction 	= customApplyFunction || null;	//(after/beforeFolderChangeData, tabCommand): if not null it will be called for custom functionality
																//tabCommand is a command with the tab set as source
																//returns true if folderformat was applied / custom actions was successfull, else false; if callBeforeChange is true and another dynamic folder format is defined for the same path the second one will be called
																//gets passed a beforeFolderChange or obejct depending on callBeforeChange; see
																//https://www.gpsoft.com.au/help/opus12/index.html#!Documents/Scripting/BeforeFolderChangeData.htm
																//https://www.gpsoft.com.au/help/opus12/index.html#!Documents/Scripting/AfterFolderChangeData.htm
	this.useFolderformatAsFallback = useFolderformatAsFallback || true;	//if customApplyFunction returns false use the defined folderformat as fallback action
}

//https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
function StartsWith(baseString, searchString, position) 
{
	baseString = String(baseString);
	searchString = String(searchString);
    position = position || 0;
    return baseString.indexOf(searchString, position) === position;
}

function Log(msg, e)
{
	DOpus.output(String(msg), e || false);
}
1 Like

You can also use wildcard formats to do this. e.g. A wildcard format matching C:\Folder\* will match all the sub-folders of C:\Folder without matching the folder itself.

1 Like

Thanks, DOpus once again won :smiley: And I am somehow not even startled that DOpus is capable of doing this. At least I wrote the possiblility down that I didnt find that way :sweat_smile:

However I'll leave this here for anyone still interested in or as an inspiration.

1 Like

To come back to this topic.
Right now I have to go to Preferences => Folder Formats, add a new path format and configure/create the format there.
My preferred way of creating folder formats is applying settings to the current folder and then via Folder => Folder Options then simply saving the format, because i can see directly how it looks like.
Is there a chance that i can get a wildcard option in this second dialog? Right now the path textfield is read only and I cannot save a "on the go" created folder format over a path format. This would make things a lot easier at least for me.

You can't save a wildcard format directly from the lister, but I think you can save a path format and then, in Preferences, copy & paste it over a new wildcard format to copy its details over.

Well that worked but you might agree that a wildcard option in the folderoptions save dialog would be easier :wink: