Advanced delete button for image viewer

This is a delete menu button for the image viewer.

image

The main functionality is a dialog where you can choose to delete files with the same name but different extension (eg you view the jpg and want to delete the raw and xmp sidecar file at once). You can also set if you want do confirm deletions and if to send them to the recycle bin. These settings are saved in global variables and are accessible for the two other buttons (delete raw, delete both which do not offer a dialog).
image

<?xml version="1.0"?>
<button backcol="none" display="both" label_pos="right" separate="yes" textcol="none" type="menu_button">
	<label>Delete</label>
	<hotkeys>
		<key>delete</key>
		<key>shift+delete</key>
	</hotkeys>
	<icon1>#delete</icon1>
	<function type="normal">
		<instruction>Show VIEWERCMD=delete</instruction>
	</function>
	<button backcol="none" display="both" hotkey="alt+delete" label_pos="right" textcol="none">
		<label>Delete Raw\tAlt + Entf</label>
		<icon1>#deletefilter</icon1>
		<function type="script">
			<instruction>@script JScript</instruction>
			<instruction>// (c) Felix Frömel 2022</instruction>
			<instruction>// v1.1 (2022-03-20)</instruction>
			<instruction>function OnClick(clickData)</instruction>
			<instruction>{</instruction>
			<instruction>	var viewer = clickData.func.viewer;</instruction>
			<instruction>	var current = viewer.current;</instruction>
			<instruction>	var tab = viewer.parenttab;</instruction>
			<instruction>	var cmd = clickData.func.command;</instruction>
			<instruction />
			<instruction>	var raw = GetRaw(current);</instruction>
			<instruction>	if(raw)</instruction>
			<instruction>	{	</instruction>
			<instruction>		var cmdLine = &quot;Delete &quot; + (GetConfirmDelete() ? &quot;&quot; : &quot;Quiet &quot;) + (GetSendToRecycleBin() ? &quot;&quot; : &quot;NORECYCLE&quot;);</instruction>
			<instruction>		cmd.AddLine(cmdLine);</instruction>
			<instruction>		cmd.AddFile(raw);</instruction>
			<instruction>		cmd.AddLine(&quot;Show VIEWERCMD=refresh&quot;);</instruction>
			<instruction>		Log(cmdLine);</instruction>
			<instruction>		viewer.Command(cmd); //show the confirmation dialog on top of the viewer instead of the lister</instruction>
			<instruction>	}</instruction>
			<instruction>	else</instruction>
			<instruction>		Log(&quot;No raw image found for deletion&quot;);</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function GetRaw(item)</instruction>
			<instruction>{</instruction>
			<instruction>	return GetFile(item, [&quot;.nef&quot;, &quot;.dng&quot;, &quot;.cr2&quot;, &quot;.cr3&quot;]);</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function GetFile(item, extensions)</instruction>
			<instruction>{</instruction>
			<instruction>	var basePath = item.realpath.pathpart + &quot;\\&quot; + item.realpath.stem;</instruction>
			<instruction>	for(var i = 0; i &lt; extensions.length; i++)</instruction>
			<instruction>	{</instruction>
			<instruction>		var path = basePath + extensions[i];</instruction>
			<instruction>		if(DOpus.FSUtil.Exists(path))</instruction>
			<instruction>		{</instruction>
			<instruction>			return DOpus.FSUtil.GetItem(path);</instruction>
			<instruction>		}</instruction>
			<instruction>	}</instruction>
			<instruction>	return null;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction />
			<instruction>var ConfirmationDialogKey = &quot;DeleteOptions.ConfirmDelete&quot;;</instruction>
			<instruction />
			<instruction>function GetConfirmDelete()</instruction>
			<instruction>{</instruction>
			<instruction>	var vars = DOpus.vars;</instruction>
			<instruction>	if(vars.Exists(ConfirmationDialogKey))</instruction>
			<instruction>		return vars.Get(ConfirmationDialogKey);</instruction>
			<instruction>		</instruction>
			<instruction>	return true;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>var SendToRecycleBinKey = &quot;DeleteOptions.SendToRecycleBin&quot;;</instruction>
			<instruction />
			<instruction>function GetSendToRecycleBin()</instruction>
			<instruction>{</instruction>
			<instruction>	var vars = DOpus.vars;</instruction>
			<instruction>	if(vars.Exists(SendToRecycleBinKey))</instruction>
			<instruction>		return vars.Get(SendToRecycleBinKey);</instruction>
			<instruction>		</instruction>
			<instruction>	return true;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function Log(msg){DOpus.Output(String(msg));}</instruction>
		</function>
	</button>
	<button backcol="none" display="both" hotkey="ctrl+shift+delete" label_pos="right" textcol="none">
		<label>Delete Both\tShift + Entf</label>
		<icon1>#deletesecure</icon1>
		<function type="script">
			<instruction>@script JScript</instruction>
			<instruction>// (c) Felix Frömel 2022</instruction>
			<instruction>// v1.1 (2022-03-20)</instruction>
			<instruction />
			<instruction>function OnClick(clickData)</instruction>
			<instruction>{</instruction>
			<instruction>	var viewer = clickData.func.viewer;</instruction>
			<instruction>	var current = viewer.current;</instruction>
			<instruction>	var tab = viewer.parenttab;</instruction>
			<instruction>	var cmd = clickData.func.command;</instruction>
			<instruction />
			<instruction>	var img = GetImage(current);</instruction>
			<instruction>	var raw = GetRaw(current);</instruction>
			<instruction>	if(img || raw)</instruction>
			<instruction>	{	</instruction>
			<instruction>		if(! img &amp;&amp; raw)</instruction>
			<instruction>			Log(&quot;Just one image type found for deletion&quot;);</instruction>
			<instruction>			</instruction>
			<instruction>		var cmdLine = &quot;Delete &quot; + (GetConfirmDelete() ? &quot;&quot; : &quot;Quiet &quot;) + (GetSendToRecycleBin() ? &quot;&quot; : &quot;NORECYCLE&quot;);</instruction>
			<instruction>		cmd.AddLine(cmdLine);</instruction>
			<instruction>		if(img)</instruction>
			<instruction>			cmd.AddFile(img);</instruction>
			<instruction>		if(raw)</instruction>
			<instruction>			cmd.AddFile(raw);</instruction>
			<instruction>		cmd.AddLine(&quot;Show VIEWERCMD=refresh&quot;);</instruction>
			<instruction>		Log(cmdLine);</instruction>
			<instruction>		viewer.Command(cmd); //show the confirmation dialog on top of the viewer instead of the lister</instruction>
			<instruction>	}</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function GetImage(item)</instruction>
			<instruction>{</instruction>
			<instruction>	return GetFile(item, [&quot;.bmp&quot;, &quot;.gif&quot;, &quot;.heic&quot;, &quot;.jpe&quot;, &quot;.jpg&quot;, &quot;.jpeg&quot;, &quot;.png&quot;]);</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function GetRaw(item)</instruction>
			<instruction>{</instruction>
			<instruction>	return GetFile(item, [&quot;.nef&quot;, &quot;.dng&quot;, &quot;.cr2&quot;, &quot;.cr3&quot;]);</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function GetFile(item, extensions)</instruction>
			<instruction>{</instruction>
			<instruction>	var basePath = item.realpath.pathpart + &quot;\\&quot; + item.realpath.stem;</instruction>
			<instruction>	for(var i = 0; i &lt; extensions.length; i++)</instruction>
			<instruction>	{</instruction>
			<instruction>		var path = basePath + extensions[i];</instruction>
			<instruction>		if(DOpus.FSUtil.Exists(path))</instruction>
			<instruction>		{</instruction>
			<instruction>			return DOpus.FSUtil.GetItem(path);</instruction>
			<instruction>		}</instruction>
			<instruction>	}</instruction>
			<instruction>	return null;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction />
			<instruction>var ConfirmationDialogKey = &quot;DeleteOptions.ConfirmDelete&quot;;</instruction>
			<instruction />
			<instruction>function GetConfirmDelete()</instruction>
			<instruction>{</instruction>
			<instruction>	var vars = DOpus.vars;</instruction>
			<instruction>	if(vars.Exists(ConfirmationDialogKey))</instruction>
			<instruction>		return vars.Get(ConfirmationDialogKey);</instruction>
			<instruction>		</instruction>
			<instruction>	return true;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>var SendToRecycleBinKey = &quot;DeleteOptions.SendToRecycleBin&quot;;</instruction>
			<instruction />
			<instruction>function GetSendToRecycleBin()</instruction>
			<instruction>{</instruction>
			<instruction>	var vars = DOpus.vars;</instruction>
			<instruction>	if(vars.Exists(SendToRecycleBinKey))</instruction>
			<instruction>		return vars.Get(SendToRecycleBinKey);</instruction>
			<instruction>		</instruction>
			<instruction>	return true;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function Log(msg){DOpus.Output(String(msg));}</instruction>
		</function>
	</button>
	<button backcol="none" display="both" hotkey="ctrl+delete" label_pos="right" textcol="none">
		<label>Delete Options\tCtrl + Del</label>
		<icon1>#deletecollection</icon1>
		<function type="script">
			<instruction>@script JScript</instruction>
			<instruction>// (c) Felix Frömel 2022</instruction>
			<instruction>// v1.1 (2022-03-20)</instruction>
			<instruction />
			<instruction>function OnClick(clickData)</instruction>
			<instruction>{</instruction>
			<instruction>	var viewer = clickData.func.viewer;</instruction>
			<instruction>	var current = viewer.current;</instruction>
			<instruction>	var tab = viewer.parenttab;</instruction>
			<instruction>	var cmd = clickData.func.command;</instruction>
			<instruction />
			<instruction>	var imgType = GetImageType(current.ext);</instruction>
			<instruction />
			<instruction>	var img = GetImage(current);</instruction>
			<instruction>	var raw = GetRaw(current);</instruction>
			<instruction>	var xmp = GetXMP(current);</instruction>
			<instruction>	</instruction>
			<instruction>	var buttons = &quot;&quot;;</instruction>
			<instruction>	var deleteFunctions = [];</instruction>
			<instruction>	var foundTypes = 0;</instruction>
			<instruction>	</instruction>
			<instruction>	var dlg = clickData.func.Dlg;</instruction>
			<instruction>	dlg.icon = &quot;warning&quot;;</instruction>
			<instruction>	dlg.message = &quot;Current image &apos;&quot; + current.name + &quot;&apos;\nFolder &apos;&quot; + current.realpath.pathpart + &quot;&apos;\n\nDelete ...&quot;;</instruction>
			<instruction>	dlg.title = &quot;Delete matching&quot;;</instruction>
			<instruction>	dlg.options(0).label = &quot;Confirm deletion&quot;;</instruction>
			<instruction>	dlg.options(0).state = GetConfirmDelete();</instruction>
			<instruction>	dlg.options(1).label = &quot;Send to recycle bin&quot;;</instruction>
			<instruction>	dlg.options(1).state = GetSendToRecycleBin();</instruction>
			<instruction>	</instruction>
			<instruction>	if(img)</instruction>
			<instruction>	{</instruction>
			<instruction>		buttons += &quot;Image (&quot; + img.ext + &quot;)|&quot;;</instruction>
			<instruction>		deleteFunctions.push(function () { Log(&quot;img&quot;); Delete(tab, cmd, viewer, img); });</instruction>
			<instruction>		foundTypes++;</instruction>
			<instruction>		if(raw &amp;&amp; imgType == &quot;image&quot;)</instruction>
			<instruction>			dlg.defid = 2;</instruction>
			<instruction>	}	</instruction>
			<instruction>	if(raw)</instruction>
			<instruction>	{</instruction>
			<instruction>		buttons += &quot;Raw (&quot; + raw.ext + &quot;)|&quot;;</instruction>
			<instruction>		deleteFunctions.push(function () { Log(&quot;raw&quot;); Delete(tab, cmd, viewer, raw); });</instruction>
			<instruction>		foundTypes++;</instruction>
			<instruction>		if(img &amp;&amp; imgType == &quot;raw&quot;)</instruction>
			<instruction>			dlg.defid = 1;</instruction>
			<instruction>	}</instruction>
			<instruction>	if(xmp)</instruction>
			<instruction>	{</instruction>
			<instruction>		buttons += &quot;XMP (&quot; + xmp.ext + &quot;)|&quot;;</instruction>
			<instruction>		deleteFunctions.push(function () { Log(&quot;xmp&quot;); Delete(tab, cmd, viewer, xmp); });</instruction>
			<instruction>		foundTypes++;</instruction>
			<instruction>	}</instruction>
			<instruction>	if(raw &amp;&amp; xmp)</instruction>
			<instruction>	{</instruction>
			<instruction>		buttons += &quot;Raw and XMP|&quot;;</instruction>
			<instruction>		deleteFunctions.push(function () { Log(&quot;raw+xmp&quot;); Delete(tab, cmd, viewer, raw, xmp); });</instruction>
			<instruction>	}</instruction>
			<instruction>	if(foundTypes &gt; 1)</instruction>
			<instruction>	{</instruction>
			<instruction>		buttons += &quot;All (&quot; + foundTypes + &quot;)|&quot;;</instruction>
			<instruction>		if(img)</instruction>
			<instruction>		{</instruction>
			<instruction>			if(raw)</instruction>
			<instruction>			{</instruction>
			<instruction>				if(xmp)</instruction>
			<instruction>					deleteFunctions.push(function () { Log(&quot;All&quot;); Delete(tab, cmd, viewer, img, raw, xmp); });</instruction>
			<instruction>				else</instruction>
			<instruction>					deleteFunctions.push(function () { Log(&quot;All&quot;); Delete(tab, cmd, viewer, img, raw); });</instruction>
			<instruction>			}</instruction>
			<instruction>			else if(xmp)</instruction>
			<instruction>				deleteFunctions.push(function () { Log(&quot;All&quot;); Delete(tab, cmd, viewer, img, xmp); });</instruction>
			<instruction>		}</instruction>
			<instruction>		else if(raw)</instruction>
			<instruction>		{</instruction>
			<instruction>			if(xmp)</instruction>
			<instruction>				deleteFunctions.push(function () { Log(&quot;All&quot;); Delete(tab, cmd, viewer, raw, xmp); });</instruction>
			<instruction>		}</instruction>
			<instruction>	}</instruction>
			<instruction />
			<instruction>	buttons += &quot;Cancel&quot;;</instruction>
			<instruction>	deleteFunctions.splice(0, 0, function () { Log(&quot;cancel&quot;); return; }); //cancel button retuns 0</instruction>
			<instruction>	//https://stackoverflow.com/questions/586182/how-to-insert-an-item-into-an-array-at-a-specific-index-javascript</instruction>
			<instruction />
			<instruction>	dlg.buttons = buttons;</instruction>
			<instruction>	var result = dlg.Show();</instruction>
			<instruction />
			<instruction>	if(result &gt; 0)</instruction>
			<instruction>	{</instruction>
			<instruction>		SetConfirmDelete(dlg.options(0).state);</instruction>
			<instruction>		SetSendToRecycleBin(dlg.options(1).state);</instruction>
			<instruction>	}</instruction>
			<instruction>	</instruction>
			<instruction>	deleteFunctions[result]();</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function Delete()</instruction>
			<instruction>{</instruction>
			<instruction>	var tab = arguments[0];</instruction>
			<instruction>	var cmd = arguments[1];</instruction>
			<instruction>	var viewer = arguments[2];</instruction>
			<instruction />
			<instruction>	Log(&quot;Found &quot; + (arguments.length - 3) + &quot; images for deletion&quot;);</instruction>
			<instruction />
			<instruction>	for(var i=3;i&lt;arguments.length;i++)</instruction>
			<instruction>		cmd.AddFile(arguments[i]);</instruction>
			<instruction />
			<instruction>	var cmdLine = &quot;Delete &quot; + (GetConfirmDelete() ? &quot;&quot; : &quot;Quiet &quot;) + (GetSendToRecycleBin() ? &quot;&quot; : &quot;NORECYCLE&quot;);</instruction>
			<instruction>	cmd.AddLine(cmdLine);</instruction>
			<instruction>	cmd.AddLine(&quot;Show VIEWERCMD=refresh&quot;);</instruction>
			<instruction>	Log(cmdLine);</instruction>
			<instruction>	viewer.Command(cmd); //show the confirmation dialog on top of the viewer instead of the lister</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>var ConfirmationDialogKey = &quot;DeleteOptions.ConfirmDelete&quot;;</instruction>
			<instruction />
			<instruction>function GetConfirmDelete()</instruction>
			<instruction>{</instruction>
			<instruction>	var vars = DOpus.vars;</instruction>
			<instruction>	if(vars.Exists(ConfirmationDialogKey))</instruction>
			<instruction>		return vars.Get(ConfirmationDialogKey);</instruction>
			<instruction>		</instruction>
			<instruction>	return true;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function SetConfirmDelete(enabled)</instruction>
			<instruction>{</instruction>
			<instruction>	DOpus.vars.Set(ConfirmationDialogKey, enabled);</instruction>
			<instruction>	DOpus.vars(ConfirmationDialogKey).persist = true;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction />
			<instruction>var SendToRecycleBinKey = &quot;DeleteOptions.SendToRecycleBin&quot;;</instruction>
			<instruction />
			<instruction>function GetSendToRecycleBin()</instruction>
			<instruction>{</instruction>
			<instruction>	var vars = DOpus.vars;</instruction>
			<instruction>	if(vars.Exists(SendToRecycleBinKey))</instruction>
			<instruction>		return vars.Get(SendToRecycleBinKey);</instruction>
			<instruction>		</instruction>
			<instruction>	return true;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function SetSendToRecycleBin(enabled)</instruction>
			<instruction>{</instruction>
			<instruction>	DOpus.vars.Set(SendToRecycleBinKey, enabled);</instruction>
			<instruction>	DOpus.vars(SendToRecycleBinKey).persist = true;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function GetImageType(extension)</instruction>
			<instruction>{</instruction>
			<instruction>	extension = extension.toLowerCase();</instruction>
			<instruction>	switch(extension)</instruction>
			<instruction>	{</instruction>
			<instruction>		case &quot;.bmp&quot;:</instruction>
			<instruction>		case &quot;.gif&quot;:</instruction>
			<instruction>		case &quot;.heic&quot;:</instruction>
			<instruction>		case &quot;.jpe&quot;:</instruction>
			<instruction>		case &quot;.jpg&quot;:</instruction>
			<instruction>		case &quot;.jpeg&quot;:</instruction>
			<instruction>		case &quot;.png&quot;:</instruction>
			<instruction>			return &quot;image&quot;;</instruction>
			<instruction>		case &quot;.nef&quot;:</instruction>
			<instruction>		case &quot;.dng&quot;:</instruction>
			<instruction>		case &quot;.cr2&quot;:</instruction>
			<instruction>		case &quot;.cr3&quot;:</instruction>
			<instruction>			return &quot;raw&quot;;</instruction>
			<instruction>	}</instruction>
			<instruction />
			<instruction>	return &quot;unknown&quot;;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function GetXMP(item)</instruction>
			<instruction>{</instruction>
			<instruction>	var basePath = item.realpath.pathpart + &quot;\\&quot; + item.realpath.stem;</instruction>
			<instruction>	var path = basePath + &quot;.xmp&quot;;</instruction>
			<instruction>	if(DOpus.FSUtil.Exists(path))</instruction>
			<instruction>		return DOpus.FSUtil.GetItem(path);</instruction>
			<instruction />
			<instruction>	return null;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function GetImage(item)</instruction>
			<instruction>{</instruction>
			<instruction>	return GetFile(item, [&quot;.bmp&quot;, &quot;.gif&quot;, &quot;.heic&quot;, &quot;.jpe&quot;, &quot;.jpg&quot;, &quot;.jpeg&quot;, &quot;.png&quot;]);</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function GetRaw(item)</instruction>
			<instruction>{</instruction>
			<instruction>	return GetFile(item, [&quot;.nef&quot;, &quot;.dng&quot;, &quot;.cr2&quot;, &quot;.cr3&quot;]);</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function GetFile(item, extensions)</instruction>
			<instruction>{</instruction>
			<instruction>	var basePath = item.realpath.pathpart + &quot;\\&quot; + item.realpath.stem;</instruction>
			<instruction>	for(var i = 0; i &lt; extensions.length; i++)</instruction>
			<instruction>	{</instruction>
			<instruction>		var path = basePath + extensions[i];</instruction>
			<instruction>		if(DOpus.FSUtil.Exists(path))</instruction>
			<instruction>		{</instruction>
			<instruction>			return DOpus.FSUtil.GetItem(path);</instruction>
			<instruction>		}</instruction>
			<instruction>	}</instruction>
			<instruction>	return null;</instruction>
			<instruction>}</instruction>
			<instruction />
			<instruction>function Log(msg){DOpus.Output(String(msg));}</instruction>
		</function>
	</button>
</button>

Download

v1.1 (2022-03-20) Delete.dcf (20.0 KB) had a wrong call in the "delete options" button so that it didnt delete the image as requested. please update

v1.0 (2022-03-17) Delete.dcf (20.0 KB)

Installation
Edit your viewer toolbar via context menu and either drag and drop the dcf file where you want the menu button or copy the code above and paste it via contextmenu to the toolbar.

4 Likes

I would like a modification of this button according to this:

  • I have .HEIC images from iPhone
  • These heic images come with 3 files more: .mov .AAE and sometimes _edited.HEIC
  • I would like to preserve sometimes the .mov and the _edited.heic, sometimes only the _editec.heic
  • If a file doesn't end with _edited.HEIC check if there's another file with the same name but with _edited before extension, if it exists delete the file without the _edited. If there's no same filename with _edited then don't delete, as there's the only version of the file.
    Example:
    imagen
    Images 9244 and 9245 should preserve only the files with _edited on their name. Images 9256 and 9265 should be preserved as there's no edited version.