Action

Recon

Posted by sylumer, Last update 3 months ago

This action has been created to help get information about a user’s set-up in Drafts when they are having issues, but can be used by anyone who is simply curious about their set-up.

The action queries the Drafts app for information. You select what sets of information to query for, and the output can be previewed as well as copied to the clipboard in various formats.

Please note file access for Drafts can be very slow. If you have a complex file structure within any of your Drafts folders, please be aware that it can take quite a while to run on iOS and iPadOS. A mitigation utilising shell scripting and the system clipboard has been used to improve the performance of these listings on macOS.

Steps

  • script

    const RVER = `RECON-06`;
    
    let g_strHTMLCSS = `  <style>
    @charset "UTF-8";
    
    :root {
    	--main-bg-color: white;
    	--main-color: black;
    	--alternate-bg-color: #efefef;
    	--alternate-color: #222222;
    	--main-border-color: #BBBBBB;
    	  --link-color: #627EC9;
      }
    
      @media (prefers-color-scheme: dark) {
    	:root {
    	  --main-bg-color: #222222;
    	  --main-color: #53C8D6;
    	  --alternate-bg-color: #444444;
    	  --alternate-color: #cccccc;
    	  --main-border-color: #AAAAAA;
    		--link-color: #627EC9;
    	}
      }
    
    html {
      font-size: 100%;
      font-family: -apple-system, BlinkMacSystemFont, "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", "helvetica neue", helvetica, roboto, noto, "segoe ui", arial, sans-serif;
      line-height: 1.4;
    }
    
    body {
      margin: 0;
      padding: 1em;
      background-color: var(--main-bg-color);
      color: var(--main-color);
    }
    
    @media (max-device-width: 700px) {}
    
    @media (min-device-width: 701px) {
      body {
    	margin: auto;
    	max-width: 600px;
      }
    }
    
    blockquote {
      font-style: italic;
      margin: 1.5em 2em;
      padding: 1em;
      background-color: var(--alternate-bg-color);
      color: var(--alternate-color);
    }
    
    a {
      color: var(--link-color);
    }
    pre {
      width: 100%;
      background-color: var(--alternate-bg-color);
      margin: 1em 0;
      white-space: pre-wrap;
    }
    
    code {
      background-color: var(--alternate-bg-color);
      color: var(--alternate-color);
      font-family: Menlo, Courier, sans-serif;
      padding: 2px 3px;
      white-space: pre-wrap;
    }
    
    strong {
    	color: white;
      }
    
      h1 {
    	color: orange;
      }
    
    table {
      margin: 1.5em 0;
      border: 1px solid var(--main-border-color);
      border-collapse: collapse;
    }
    
    th {
      padding: .25em .5em;
      background: var(--alternate-bg-color);
      border: 1px solid var(--main-border-color);
    }
    
    td {
      padding: .25em .5em;
      border: 1px solid var(--main-border-color);
    }
    
    img {
      max-width: 90%;
    }
    
    form {
       padding: 1em;
    }
    
    .verticalLine {
    	border-left: 2px solid orange;
    	padding-left: 5px;
    	margin-bottom: 5px;
    	font-style: italic;
      }
    </style>
    `
    
    let  g_strSelectHTML = `<!DOCTYPE html>
    <html dir="auto">
    
    <head>
      <title>Recon Select Options</title>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
    ${g_strHTMLCSS}
    </head>
    <body>
    	<form id="frmSelection" autocomplete="off" autocorrect="off">
    	
    	<strong>Drafts Set-up</strong><br>
    	<input type="checkbox" id="cbDrafts"> Drafts Info<br>
    	<input type="checkbox" id="cbEditor"> Editor Info<br>
    	<input type="checkbox" id="cbWorkspaces"> Workspace Info<br>
    	<input type="checkbox" id="cbCurrentWorkspace"> Current Workspace<br>
    
    	<br><strong>Device</strong><br>
    	<input type="checkbox" id="cbDevice"> Device Info<br>
    
    	<br><strong>File System</strong><br>
    	<div class="verticalLine">Please note that file system queries on the Mac make use of the clipboard to speed up retrieval of directory listings for large and complex folder structures.</div>
    	<input type="checkbox" id="cbPreviewListing"> Directory Listing for Previews<br>
    	<input type="checkbox" id="cbScriptsListing"> Directory Listing for Scripts<br>
    	<input type="checkbox" id="cbTemplatesListing"> Directory Listing for Templates<br>
    	---	<br>
    	<input type="checkbox" id="cbListingIncludeDotted"> <span style="color:lightgray; font-style: italic;">Include Files Beginning with a Period in Directory Listings?</span><br>
    
    	<br><strong>Actions</strong><br>
    	<input type="checkbox" id="cbActionGroupListing"> Action Group Listing<br>
    	<input type="checkbox" id="cbActionListing"> Action Listing<br>
    	<input type="checkbox" id="cbActionKeyboardShortcutsListing"> Action Keyboard Shortcuts Listing<br>
    
    	<br><strong>Current Draft</strong><br>
    	<input type="checkbox" id="cbCurrentInfo"> Current Draft Info<br>
    	<input type="checkbox" id="cbCurrentVersions"> Current Draft's Versions<br>
    	<input type="checkbox" id="cbCurrentExample"> Current Draft Content<br>
    
    	<hr>
    
    	<input type="checkbox" id="cbPreview" checked> Preview Results<br>
    
    	<p>Copy Results?
    	<select id="selClipboard">
    		<option value="no" selected="selected">No</option>
    		<option value="mmd">As MultiMarkdown</option>
    		<option value="hidden">As MultiMarkdown in a Hidden Details Section</option>
    		<option value="html">As HTML</option>
    		<option value="rich">As Rich Text</option>
    	</select>
    	</p>
    
    
    		<div style="margin: 1em 0 3em 0;">
    			<button id="sub" onclick="submitFormById('frmSelection'); return false;">Submit</button>
    			<button id ="cancel" onclick="Drafts.cancel(); return false;">Cancel</button>
    		</div>
    	</form>
    </body>
    <script>
    function serialiseForm(p_objForm)
    {
    	//Initialise
    	let objData = {};
    
    	//Add returnable items to the data object
    	for(let element of p_objForm.elements)
    	{
    		if (element.type && element.type === 'checkbox')
    		{
    			objData[element.id] = element.checked;
    		}
    		else if (element.type == 'submit')
    		{
    			//Ignore
    		}
    		else
    		{
    			objData[element.id] = element.value;
    		}
    	}
    
    	//Return the data object
    	return objData;
    };
    
    function submitFormById(p_strFormID)
    {
    	//Get the form
    	let objForm = document.getElementById(p_strFormID);
    
    	//Transform all of the returnable form elements into an object
    	let objData = serialiseForm(objForm);
    
    	//Send the object to Drafts and return a continue code
    	Drafts.send("formValues", objData);
    	Drafts.continue();
    	return;
    }
    
    
    function checkKeyPress(p_objKey)
    {
    	if (p_objKey.keyCode == '13') submitFormById('frmSelection');
    	return false;
    }
    
    </script>
    
    </html>`
    
    function b2s(p_bBoolean)
    {
    	if (p_bBoolean) return "true";
    	else return "false";
    }
    
    //Show the HTML prompt to select what to output
    function selectOptions(p_strHTML)
    {
    	let hp = new HTMLPreview;
    	hp.hideInterface = true;
    	if (hp.show(p_strHTML)) return context.previewValues["formValues"];
    	else return false;
    }
    
    function detailsDevice()
    {
    	return `# Device Information
    - **Model:** ${device.model}
    - **OS Version:** ${device.systemVersion}
    - **System Name:** ${device.systemName}
    - **Battery Level:** ${device.batteryLevel}
    `
    }
    
    function detailsDrafts()
    {
    	return `# Drafts Information
    - **Version:** ${app.version}
    - **Pro Subscription Enabled:** ${b2s(app.isPro)}
    - **Idle Disabled:** ${b2s(app.isIdleDisabled)}
    - **Draft List Visible:** ${b2s(app.isDraftListVisible)}
    - **Action List Visible:** ${b2s(app.isActionListVisible)}
    - **Theme:** ${app.currentThemeMode}
    - **Drafts in Inbox:** ${Draft.query("", "inbox", [], [], "created").length}
    - **Drafts in Archive:** ${Draft.query("", "archive", [], [], "created").length}
    - **Drafts in Flagged:** ${Draft.query("", "flagged", [], [], "created").length}
    - **Drafts in Trash:** ${Draft.query("", "trash", [], [], "created").length}
    `
    }
    
    function detailsCurrentWorkspace()
    {
    	return  `# Current Workspace\n` + detailsWorkspace(app.currentWorkspace, true);
    }
    
    function detailsWorkspaces()
    {
    	strOutput = "# Workspaces\n";
    	Workspace.getAll().forEach(function(wsCurrent)
    	{
    		strOutput += "\n## " + wsCurrent.name;
    		strOutput += detailsWorkspace(wsCurrent, false) + "\n";
    	});
    	return strOutput;
    }
    
    function detailsWorkspace(p_wsToCheck, p_bIncludeName)
    {
    	let strWorkspace = "";
    	if (p_bIncludeName) if (p_wsToCheck.name != undefined) strWorkspace += `\n- **Name:** ${p_wsToCheck.name}`
    	if(p_wsToCheck.queryString != undefined) strWorkspace += `\n- **Query String:** ${p_wsToCheck.queryString}`
    	if(p_wsToCheck.tagFilter != undefined) strWorkspace += `\n- **Tag Filter:** ${p_wsToCheck.tagFilter}`
    	if(p_wsToCheck.tagFilterRequireAll != undefined) strWorkspace += `\n- **Require All Tags:** ${b2s(p_wsToCheck.tagFilterRequireAll)}`
    	if(p_wsToCheck.startDate != undefined)
    	{
    		strWorkspace += `\n- **Start Date Field:** ${p_wsToCheck.startDate.field}`
    		strWorkspace += `\n- **Start Date Type:** ${p_wsToCheck.startDate.type}`
    		strWorkspace += `\n- **Start Date Date (>=):** ${p_wsToCheck.startDate.date}`
    		strWorkspace += `\n- **Start Date Days (>=):** ${p_wsToCheck.startDate.days}`
    	}
    	if(p_wsToCheck.endDate != undefined)
    	{
    		strWorkspace += `\n- **End Date Field:** ${p_wsToCheck.endDate.field}`
    		strWorkspace += `\n- **End Date Type:** ${p_wsToCheck.endDate.type}`
    		strWorkspace += `\n- **End Date Date (<=):** ${p_wsToCheck.endDate.date}`
    		strWorkspace += `\n- **End Date Days (<=):** ${p_wsToCheck.endDate.days}`
    	}
    	if(p_wsToCheck.inboxIncludesFlagged != undefined) strWorkspace += `\n- **Inbox Includes Flagged:** ${b2s(p_wsToCheck.inboxIncludesFlagged)}`
    	if(p_wsToCheck.archiveIncludesFlagged != undefined) strWorkspace += `\n- **Archive Includes Flagged:** ${b2s(p_wsToCheck.archiveIncludesFlagged)}`
    	if(p_wsToCheck.loadFolder != undefined) strWorkspace += `\n- **Load Folder:** ${p_wsToCheck.loadFolder}`
    	if(p_wsToCheck.loadActionBarGroup != undefined) strWorkspace += `\n- **Load Action Bar Group:** ${p_wsToCheck.loadActionBarGroup.name} (${p_wsToCheck.loadActionBarGroup.uuid})`
    	if(p_wsToCheck.loadActionListGroup != undefined) strWorkspace += `\n- **Load Action List Group:** ${p_wsToCheck.loadActionListGroup.name}  (${p_wsToCheck.loadActionListGroup.uuid})`
    	if(p_wsToCheck.showLastAction != undefined) strWorkspace += `\n- **Show Last Action for Draft in List:** ${b2s(p_wsToCheck.showLastAction)}`
    	if(p_wsToCheck.showPreview != undefined) strWorkspace += `\n- **Show Body Prfeview for Draft in List:** ${b2s(p_wsToCheck.showPreview)}`
    	if(p_wsToCheck.showTags != undefined) strWorkspace += `\n- **Show Tags for Draft in List:** ${b2s(p_wsToCheck.showTags)}`
    	return strWorkspace;
    }
    
    // Get all actions.
    ActionGroup.getAllActions = function()
    {
    	let aactAll = [];
    	ActionGroup.getAll().forEach(function(actgrpCurrent){aactAll = aactAll.concat(actgrpCurrent.actions);});
    	return aactAll;
    }
    
    // Populate an action object with a keyboard shortcut property
    Action.prototype.populateKeyboardShortcut = function()
    {
    	//Get the installation data for an action from its install URL
        let jsonActionData = JSON.parse(decodeURIComponent(this.installURL.replace("drafts5://action?data=","")));
    
        //Keyboard shortcut
        if (jsonActionData.hasOwnProperty("keyCommand"))
        {
            this._keyShift = jsonActionData.keyCommand.shiftKey;
            this._keyControl = jsonActionData.keyCommand.controlKey;
            this._keyOption = jsonActionData.keyCommand.optionKey;
            this._keyCommand = jsonActionData.keyCommand.commandKey;
            if(jsonActionData.keyCommand.input.length > 0)
            {
                //Deal with the encoding for the special keys that are available
                switch (jsonActionData.keyCommand.input)
                {
                    case "#LEFT":
                        this._keyInput = "&leftarrow; ";
                        break;
                    case "#RIGHT":
                        this._keyInput = "&rightarrow; ";
                        break;
                    case "#UP":
                        this._keyInput = "&uparrow; ";
                        break;
                    case "#DOWN":
                        this._keyInput = "&downarrow; ";
                        break;
                    case "#TAB":
                        this._keyInput = "&#11134;";
                        break;
                    default:
                        this._keyInput = jsonActionData.keyCommand.input;
                }
                this._keyHas = true;
            }
            else
            {
                this._keyInput = "";
                this._keyHas = false;
            }
    
            //Build the shortcuts key
            let astrKeyShortcut = [];
            if (this._keyShift) astrKeyShortcut.push("&#8679;");
            if (this._keyControl) astrKeyShortcut.push("^");
            if (this._keyOption) astrKeyShortcut.push("&#8997;");
            if (this._keyCommand) astrKeyShortcut.push("&#8984;");
            if (this._keyInput.length > 0) astrKeyShortcut.push(this._keyInput);
            this._keyShortcut = astrKeyShortcut.join("");
        }
        else
        {
            this._keyShortcut = "";
            this._keyShift = false;
            this._keyControl = false;
            this._keyOption = false;
            this._keyCommand = false;
            this._keyInput = "";
        }
        return;
    }
    
    function detailsActionShortcuts()
    {
    	let astrOutput = [];
    	ActionGroup.getAllActions().forEach(function(acCurrent)
    	{
    		acCurrent.populateKeyboardShortcut();
    		if (acCurrent._keyShortcut != "")
    		{
    			let strKeys = acCurrent._keyShortcut;
    			let intLen = 1;
    			if (acCurrent._keyShift) intLen++;
    			if (acCurrent._keyControl) intLen++;
    			if (acCurrent._keyOption) intLen++;
    			if (acCurrent._keyCommand) intLen++;
    			let intSpaces = 6 - intLen;
    			for (let intCounter = 0; intCounter < intSpaces; intCounter++)
    			{
    				strKeys = strKeys + "&nbsp;";
    			}
    			strKeys = strKeys.replaceAll("§", "&sect;")
    			astrOutput.push(`${strKeys}${acCurrent.name}`);
    		}
    	});
    	return "# Actions with Keyboard Shortcuts\n<pre>" + astrOutput.join("\n") + "</pre>";
    }
    
    function checkFolder(p_strFolder, p_bIncludeDotted = false)
    {
    	let astrOutput = [];
    	app.displayWarningMessage(`Checking content of "${p_strFolder}...`)
    	let fmCloud = FileManager.createCloud();
    	let astrListing = fmCloud.listContents(p_strFolder)
    	astrListing.forEach(function (strItemPath)
    	{
    		if (!p_bIncludeDotted && !strItemPath.includes("/."))
    		{
    			astrOutput.push(strItemPath);
    			if (strItemPath.endsWith("/")) astrOutput = astrOutput.concat(checkFolder(strItemPath));
    		}
    	});
    	return astrOutput;
    }
    
    function checkFolderMac(p_strFolder, p_bIncludeDotted = false)
    {
    	let strLSparams = "-R1 ";
    	if (p_bIncludeDotted) strLSparams = "-Ra1 ";
    	let strScript = `#!/bin/zsh
    echo $HOME/Library/Mobile Documents/iCloud~com~agiletortoise~Drafts5/Documents${p_strFolder}
    ls ${strLSparams}"$HOME/Library/Mobile Documents/iCloud~com~agiletortoise~Drafts5/Documents${p_strFolder}" | pbcopy
    `;
    	let shMain = ShellScript.create(strScript);
    
    	if (shMain.execute()) return app.getClipboard();
    	else return shMain.standardError;
    }
    
    function detailsPreviewsListing(p_bListingIncludeDotted)
    {
    	
    	if(device.systemName == 'macOS')
    	{
    		return "# Previews Listing\n<pre>" + checkFolderMac("/Library/Previews", p_bListingIncludeDotted) + "</pre>";
    	}
    	else
    	{
    		let astrListing = checkFolder("/Library/Previews", p_bListingIncludeDotted);
    		return "# Previews Listing\n<pre>" + astrListing.join("\n") + "</pre>";
    	}
    }
    
    function detailsScriptsListing(p_bListingIncludeDotted)
    {
    	if(device.systemName == 'macOS')
    	{
    		return "# Scripts Listing\n<pre>" + checkFolderMac("/Library/Scripts", p_bListingIncludeDotted) + "</pre>";
    	}
    	else
    	{
    		let astrListing = checkFolder("/Library/Scripts", p_bListingIncludeDotted);
    		return "# Scripts Listing\n<pre>" + astrListing.join("\n") + "</pre>";
    	}
    }
    
    function detailsTemplatesListing(p_bListingIncludeDotted)
    {
    	if(device.systemName == 'macOS')
    	{
    		return "# Templates Listing\n<pre>" + checkFolderMac("/Library/Templates", p_bListingIncludeDotted) + "</pre>";
    	}
    	else
    	{
    		let astrListing = checkFolder("/Library/Templates", p_bListingIncludeDotted);
    		return "# Templates Listing\n<pre>" + astrListing.join("\n") + "</pre>";
    	}
    }
    
    String.prototype.deMarkdown = function()
    {
    	let strTemp = this;
    	strTemp = strTemp.replaceAll("\\", "\\\\`");
    	strTemp = strTemp.replaceAll("-", "\\-");
    	strTemp = strTemp.replaceAll("_", "\\_");
    	strTemp = strTemp.replaceAll("*", "\\*");
    	strTemp = strTemp.replaceAll("`", "&#96;");
    
    	return strTemp;
    }
    
    function detailsActionListing()
    {
    	let strOutput = [];
    	ActionGroup.getAll().forEach(function(agCurrent)
    	{
    		strOutput.push("\n## " + agCurrent.name.deMarkdown());
    		agCurrent.actions.forEach(function (acCurrent)
    		{
    			if (acCurrent.isSeparator) strOutput.push("- **" + acCurrent.name.deMarkdown() + ":**");
    			else strOutput.push("- " + acCurrent.name.deMarkdown());
    		});
    	});
    	return "# Actions\n" + strOutput.join("\n");
    }
    
    function detailsActionGroupListing()
    {
    	let strOutput = [];
    	let intAGCounter = 0;
    	let intACCounter = 0;
    	ActionGroup.getAll().forEach(function(agCurrent)
    	{
    		let intCounter = 0;
    		agCurrent.actions.forEach(function (acCurrent)
    		{
    			if (!acCurrent.isSeparator) intCounter++;
    		});
    		intAGCounter++;
    		intACCounter = intACCounter + intCounter;
    		strOutput.push(`- ${agCurrent.name.deMarkdown()} (${intCounter} actions)`);
    	});
    	strOutput.push(`\n\n${intAGCounter} Action Groups Containing ${intACCounter} Actions.`)
    
    	return "# Action Groups\n" + strOutput.join("\n");
    }
    
    function detailsEditor()
    {
    	strOutput = "# Editor\n";
    	strOutput += `- **Focus Mode Enabled:** ${b2s(editor.focusModeEnabled)}\n`;
    	strOutput += `- **Link Mode Enabled:** ${b2s(editor.linkModeEnabled)}\n`;
    	strOutput += `- **Typewriter Scrolling Enabled:** ${b2s(editor.typewriterScrollingEnabled)}\n`;
    	strOutput += "- **Editor Preferred Tab String (Text):** `\"" + editor.preferredTabString + "\"`\n";
    	strOutput += "- **Editor Preferred Tab String (URL Encoded):** " + encodeURIComponent(editor.preferredTabString) + "\n";
    	return strOutput;
    }
    
    function detailsCurrentInfo()
    {
    
    	let astrMarkers = [];
    	if (editor.navigationMarkers.length > 0)
    	{
    		editor.navigationMarkers.forEach(function(nmMain)
    		{
    			astrMarkers.push(`	- [${nmMain.level}] ${nmMain.prefix} : ${nmMain.label}`);
    		})
    	}
    
    	return `# Current Draft Information
    - **UUID:** ${draft.uuid}
    - **Title:** ${draft.title}
    - **Syntax:** ${draft.languageGrammar}
    - **Flagged:** ${b2s(draft.isFlagged)}
    - **Archived:** ${b2s(draft.isArchived)}
    - **Trashed:** ${b2s(draft.isTrashed)}
    - **Line Count:** ${draft.lines.length}
    - **Character Count:** ${draft.content.length}
    - **Created:** ${draft.createdAt}
    - **Modified:** ${draft.modifiedAt}
    - **Versions:** ${draft.versions.length}
    - **Tags:** ${draft.tags.join(" | ")}
    - **Navigation Markers:**\n${astrMarkers.join("\n")}
    `;
    }
    
    function detailsCurrentVersions()
    {
    	let strOutput = [`# Current Draft's Versions\n`];
    	draft.versions.forEach(function (verDraft)
    	{
    		strOutput.push(`- **${verDraft.createdAt}:** ${verDraft.content.length} characters in ${verDraft.content.split('\n').length} lines - (${verDraft.uuid})`);
    	});
    	return strOutput.join("\n");
    }
    
    function detailsCurrentExample()
    {
    	//We'll use lots of backticks to mark our code block in case the content of the draft contains a code block defined by backticks
    	return `# Current Draft Content
    \`\`\`\`\`\`\`\`\`plaintext
    ${draft.content}
    \`\`\`\`\`\`\`\`\`
    `;
    }
    
    //Display Results
    function displayResults(p_strHTML)
    {
    	let hp = new HTMLPreview;
    	hp.hideInterface = false;
    	hp.show(p_strHTML);
    	return;
    }
    
    function recon()
    {
    	//Choose what to output
    	let astrSelection = selectOptions(g_strSelectHTML);
    	//alert(JSON.stringify(astrSelection));
    
    	if (astrSelection != false)
    	{
    		//Build the output as MMD
    		let astrOutput = [];
    		//Drafts
    		if (astrSelection.cbDrafts) astrOutput.push(detailsDrafts());
    		if (astrSelection.cbEditor) astrOutput.push(detailsEditor());
    		if (astrSelection.cbWorkspaces) astrOutput.push(detailsWorkspaces());
    		if (astrSelection.cbCurrentWorkspace) astrOutput.push(detailsCurrentWorkspace());
    		//Device
    		if (astrSelection.cbDevice) astrOutput.push(detailsDevice());
    		//File System
    		if (astrSelection.cbPreviewListing) astrOutput.push(detailsPreviewsListing(astrSelection.cbListingIncludeDotted));
    		if (astrSelection.cbScriptsListing) astrOutput.push(detailsScriptsListing(astrSelection.cbListingIncludeDotted));
    		if (astrSelection.cbTemplatesListing) astrOutput.push(detailsTemplatesListing(astrSelection.cbListingIncludeDotted));
    		//Actions
    		if (astrSelection.cbActionGroupListing) astrOutput.push(detailsActionGroupListing());
    		if (astrSelection.cbActionListing) astrOutput.push(detailsActionListing());
    		if (astrSelection.cbActionKeyboardShortcutsListing) astrOutput.push(detailsActionShortcuts());
    		//Current Draft
    		if (astrSelection.cbCurrentInfo) astrOutput.push(detailsCurrentInfo());
    		if (astrSelection.cbCurrentVersions) astrOutput.push(detailsCurrentVersions());
    		if (astrSelection.cbCurrentExample) astrOutput.push(detailsCurrentExample());
    
    		//Add a generation footer
    		astrOutput.push(`<strong>Generated at:</strong> <span style="font-family:courier">${new Date()}</span><br>
    		<strong>Generated by:</strong> <span style="font-family:courier">${RVER}</span>`);
    
    		//Combine the MMD for output
    		let strMMD = astrOutput.join("\n\n---\n\n")
    
    		//Convert MMD output to HTML for display and copying
    		let mmd = MultiMarkdown.create();
    		mmd.format = "html";
    		mmd.completeDocument = "false";
    		let strHTML = `<html><head>\n<meta charset="UTF-8">\n${g_strHTMLCSS}\n</head><body>` + mmd.render(strMMD) + `\n</body></html>`;
    
    		//If the option to preview was set, display it
    		if (astrSelection.cbPreview) displayResults(strHTML);
    
    		//Populate the clipboard if necessary
    		switch(astrSelection.selClipboard) {
    			case "mmd":
    				app.setClipboard(strMMD);
    				break;
    			
    			case "hidden":
    				app.setClipboard(`[details="Recon Results"]\n${strMMD}\n[/details]`);
    				break;
    			
    			case "html":
    				app.setClipboard(strHTML);
    				break;
    
    			case "rich":
    				app.htmlToClipboard(strHTML);
    				break;
    			
    			default:
    			// Default is to leave the clipboard untouched
    		}
    	}
    
    	return;
    }
    
    recon();
  • script

    /*
    VERSION INFO
    ============
    RECON-06:
    - Added inbox/archive/flagged/trash counts to the Drafts information section.
    
    RECON-05:
    - Added current draft information, including content dump and version information.
    - De-Markdown action/separator and action group names so they are not interpreted on output.
    - Added wrapping to code sections.
    
    RECON-04: 
    - Added higher performance file/directory listings for macOS (only).
    - Removed unnecessary element spacing in action group listing.
    
    RECON-03:
    - Fixed an action name containing emoji display bug on macOS.
    
    RECON-02:
    - Added several additional data gathering sections for app and action information.
    
    RECON-01:
    - Initial release.
    */

Options

  • After Success Default
    Notification Error
    Log Level Error
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.