"Soft"linking collections into normal folders (also outside of DOpus)

This code can be used to "softlink" collections into normal folders (existing on the real storage) which then are also available outside of DOpus. It actually just creates a shortcut file to open a tab with this collection in DOpus, so editing/copy/paste is just available inside of DOpus.

Icons of collections are supported such that the shortcut will have the same icon as the collection.
If used in dual mode and destination tab is a non-collection folder, the shortcut will be created in the destination folder, is in non-dual mode, a dialog will pop up and ask for a path where to save the link.

You can either use the button
Link Collection.dcf (9.3 KB) or the code below as a Collection Context Menu (make sure to set contextMenuMode variable to true).

// Softlink Collection Button
// (c) 2022 Felix.Froemel
// v1.0 (2022-10-11)

////// Settings /////
var linkPrefix = ""; //or "Coll "; //How should the default linkname start?
var openInNewTab = false; //If link is clicked inside of dopus this provides a seamless transistion 
var useCollectionIcon = true; //try to read icon for link from collection. Fallback or if false icon is collection icon from dopus
var contextMenuMode = false; //if true, this script can be placed in the collection context menu so that the collection you're currently vieweing is softlinked, else it is a button and you softlink the first selected collection
/////////////////////


function OnClick(clickData)
{
	var source = clickData.func.sourcetab;
	var dest = clickData.func.desttab;
	var dlg = clickData.func.Dlg;
	
	var selectedFolder = contextMenuMode ? (DOpus.FSUtil.GetItem(source.path)) : (source.selected_dirs.count > 0 ? source.selected_dirs(0) : null);
	if(!selectedFolder)
	{
		ShowDialog(dlg, "No folder selected to link", "No collection folder selected to link.", "OK", "error"); 
		return;
	}
	if(String(selectedFolder).indexOf("coll://") == -1)
	{
		ShowDialog(dlg, "Folder is no collection", selectedFolder + " is no collection.", "OK", "error"); 
		return;
	}
	
	if(selectedFolder)
	{
		var lnkPath;
		if(source.lister.dual > 0 || String(dest.path).indexOf("coll://") == -1)
			lnkPath = String(dest.path) + "\\" + linkPrefix + selectedFolder.name + ".lnk";
		else
		{
			var defaultName = linkPrefix + selectedFolder.name;
			var resultPath = dlg.Save("Save link to collection '" + defaultName + "' at",  selectedFolder.name, tab, "#Link file!*.lnk");
			if(resultPath.result)
				lnkPath = String(resultPath);
			else
				return;
		}
		if(String(lnkPath).indexOf("coll://") != -1)
		{
			ShowDialog(dlg, "Cannot create a link inside a collection", selectedFolder + " is a collection. Cannot create a link here.", "OK", "error"); 
			return;
		}
			
		CreateShortcut(lnkPath, selectedFolder);
	}
}

//Create a shortcut (lnk file) pointing to dopusrt calling GO command for selected collection
//https://stackoverflow.com/questions/48375073/how-to-create-link-for-executable-file-and-indicate-work-folder-in-batch-or-vbs
function CreateShortcut(lnkPath, targetPath)
{
	var dopusDir = DOpus.FSUtil.Resolve("/home");
	var dopusPath = dopusDir + "\\dopus.exe";
	var dopusRtPath = dopusDir + "\\dopusrt.exe";

	var lnk = new ActiveXObject("WScript.Shell").CreateShortcut(lnkPath);
	lnk.WorkingDirectory = dopusPath;
	lnk.TargetPath = dopusRtPath;
	lnk.Arguments = openInNewTab ? "/cmd Go NEWTAB PATH=\"" + targetPath + "\"" : "/cmd Go PATH=\"" + targetPath + "\"";
	lnk.Description = "Open '" + targetPath + "' in DOpus";

	var icon = useCollectionIcon ? GetIconFromCollection(targetPath) : null;
	lnk.IconLocation = icon ? icon : dopusPath + ",6";

	lnk.Save();
}

//Read icon path from collection file
//if not exists return null, use icon from dopus
function GetIconFromCollection(collection)
{
	var collectionFilePath = String(collection.path).replace("coll://", DOpus.FSUtil.Resolve("/dopusdata") + "\\Collections\\").replace("/", "\\") + "\\" + collection.name + ".col";
	var collectionText = ReadTextFile(collectionFilePath);
	var iconRegex = /icon="(.+?)"/;
	var matches = collectionText.match(iconRegex);
	if(matches)
	{
		var iconPath = matches[1];
		if(iconPath.charAt(0) == "/")//alias, resolve path
		{
			var aliasRegex = /(\/.+?)\//;
			var matches = iconPath.match(aliasRegex);
			if(matches)
			{
				var resolved = DOpus.FSUtil.Resolve(matches[1]);
				if(resolved == matches[1])//alias does not exist
					return null;
					
				var fullIconPath = iconPath.replace(matches[1] + "/", resolved + "\\");
				return fullIconPath;
			}
			return null;
		}
		else
			return iconPath;
	}
	else
		return null;
}

//Read collection file
function ReadTextFile(filePath)
{
	var fso = new ActiveXObject("Scripting.FileSystemObject");
   	var file = fso.OpenTextFile(filePath, 1);
   	var text = file.ReadAll();
   	file.Close();
	return text;
}

//show a dialog
function ShowDialog(dlg, title, msg, buttons, icon, choices) {
    dlg = dlg || DOpus.Dlg;
    dlg.title = title || "";
    dlg.message = msg || "";
    dlg.buttons = buttons || "OK";
    dlg.icon = icon || "";
    if (choices) {
        dlg.selection = 0;
        dlg.choices = choices;
    }
    
    var result = dlg.Show();
    var buttonValues = buttons.split('|');
    if (buttonValues.length > 1)
        return buttonValues[(result - 1) % buttonValues.length];

    return result;
}

function Log(msg, e)
{
	DOpus.Output(String(msg), e || false);
}
2 Likes