Store group templates in "template" database

I chose to hold of my static DT templates in a “templates” database. I created a single dynamic template for this which creates a dialog with Dialog Toolkit Plus to choose the template.

Why?

  1. I was tired to switch between DT and the filesystem for templating
  2. I want to be able share templates with my wife - via WebDAV and DT sync
  3. I moved a lot static templates recently into DT and was tired to create a lot of static .dtTemplates

Setup

  1. Create the templates database

  2. Create the the “default”-template with AppleScript - see below

  3. Change defaults in the script to match your database

    property globalLettersGroupName : “Meine Vorlagen”

    property globalDatabase : “templates”

    property globalDefaultCategory : “Briefe”

  4. Create categories and templates in categories

The dynamic default template

_Default.templatescriptd.zip (17.9 KB)

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use script "Dialog Toolkit Plus" version "1.1.3"

-- Default non-localized sprint name, also used to identify the resources
property pTemplateName : "Letters"
property pAboutDocument : "Create letters"
property globalLettersGroupName : "Meine Vorlagen"
property globalDatabase : "templates"
property globalDefaultCategory : "Briefe"

property templatesPopup : {}
property categoriesPopup : {}
property lettersGroup : {}

tell application id "DNtp"
	activate
end tell

local selectedGroup, currentDatabase
tell application id "DNtp"
	set selectedGroup to current group
end tell

tell application id "DNtp"
	set lettersGroup to create location globalLettersGroupName in database globalDatabase
end tell

-- search for template categories
local foundCategories
tell application id "DNtp"
	set foundCategories to (search "type:group" in lettersGroup with exclude subgroups)
end tell

if length of foundCategories is 0 then
	error "No template categories defined. Exit"
end if

-- sort categories
local sortedCategories
set sortedCategories to sortRecordNames(foundCategories)

-- get "first" category to be shown by default within dialog
local firstCategory
tell application id "DNtp"
	set firstCategory to item 1 of (search "type:group name:" & globalDefaultCategory in lettersGroup with exclude subgroups)
end tell

local foundTemplates
tell application id "DNtp"
	set foundTemplates to (search "type:group name:!<_" in firstCategory with exclude subgroups)
end tell

if length of foundTemplates is 0 then
	error "No templates defined. Exit"
end if

-- sort templates

local sortedTemplates
set sortedTemplates to sortRecordNames(foundTemplates)

-- create dialog to show dropdowns for template selection
set accViewWidth to 600

-- set buttons
set {theButtons, minWidth} to create buttons {"Create from Template", "Cancel"} default button "Create from Template" without equal widths
if minWidth > accViewWidth then set accViewWidth to minWidth -- make sure buttons fit

-- to make it look better, we can get the length of the longest label we will use, and use that to align the controls
set theLabelStrings to {"Category", "Template"}
set maxLabelWidth to max width for labels theLabelStrings
set controlLeft to maxLabelWidth + 8

-- start from the bottom
set {templatesPopup, templatesLabel, theTop} to create labeled popup sortedTemplates left inset 0 bottom 0 popup width 435 max width accViewWidth label text (item 2 of theLabelStrings) popup left controlLeft
set {categoriesPopup, categoriesLabel, theTop} to create labeled popup sortedCategories left inset 0 bottom (theTop + 14) popup width 435 max width accViewWidth label text (item 1 of theLabelStrings) popup left controlLeft initial choice "Briefe"

-- make it possible that the category dropdown updates the template dropdown
-- https://www.macscripter.net/t/change-elements-dynamically-using-shanes-dialog-toolkit/70409/11
categoriesPopup's setTarget:me
categoriesPopup's setAction:"updateOtherFields:"

-- make list of cotrols and pass to display command
set allControls to {categoriesPopup, categoriesLabel, templatesPopup, templatesLabel}

-- controlResults will in the same order as allControls
local buttonPressed, controlsResults
set {buttonPressed, controlsResults} to display enhanced window "Choose letter template" acc view width accViewWidth acc view height theTop acc view controls allControls buttons theButtons initial position {} giving up after 0 with align

-- return if dialog is canceled
if buttonPressed is "Cancel" then
	return missing value
end if

-- WARN: only required for debugging the interactive dropdowns
-- my updateOtherFields()

-- gather data from result
local categoryName, templateName
set categoryName to (item 1 of controlsResults)
set templateName to (item 3 of controlsResults)

-- search group for chosen category
-- if two groups with the same name exist; only the first one is used
local selectedCategory
tell application id "DNtp"
	set selectedCategory to item 1 of (search "type:group name:" & categoryName in lettersGroup with exclude subgroups)
end tell

-- error handling
if selectedCategory is missing value then
	error "Template category " & categoryName & " was deleted from templates database " & globalDatabase & " while the selector dialog was shown. Exit"
end if

-- select first template by name in selected category
local selectedTemplate
tell application id "DNtp"
	set selectedTemplate to item 1 of (search "type:group name:" & templateName in selectedCategory with exclude subgroups)
end tell

-- error handling
if selectedCategory is missing value then
	error "Template " & templateName & " was deleted from templates database " & globalDatabase & " while the selector dialog was shown. Exit"
end if

-- create new group based on chosen template
tell application id "DNtp"
	local newGroup
	set newGroup to duplicate record selectedTemplate to selectedGroup
	
	local theResult
	set theResult to display dialog ("Location: " & location with name of selectedGroup & return & "Database: " & name of database of selectedGroup) default answer templateName with title "Set name of newly created group"
	
	local buttonPressed
	set buttonPressed to button returned of theResult
end tell

if buttonPressed is not "OK" then
	return missing value
end if

-- set new name
tell application id "DNtp"
	local newNameOfGroup
	set newNameOfGroup to text returned of theResult
	
	set name of newGroup to newNameOfGroup
end tell

on sortRecordNames(theRecords)
	local listOfNames
	set listOfNames to {}
	
	repeat with theRecord in theRecords
		tell application id "DNtp"
			copy name of theRecord to end of listOfNames
		end tell
	end repeat
	
	local namesArray
	set namesArray to current application's NSArray's arrayWithArray:listOfNames
	
	local sortedNames
	set sortedNames to (namesArray's sortedArrayUsingSelector:"localizedStandardCompare:") as list
	
	return sortedNames
end sortRecordNames

--on updateOtherFields()
on updateOtherFields:sender
	try
		-- set index of selected dropdown item
		local selectedCategoryIndex, selectedCategory
		set selectedCategoryIndex to (my categoriesPopup's indexOfSelectedItem() as integer) + 1
		set selectedCategory to categoriesPopup's titleOfSelectedItem() as text
		
		local selectedCategoryGroup
		tell application id "DNtp"
			set selectedCategoryGroup to item 1 of (search "type:group name:" & selectedCategory in lettersGroup with exclude subgroups)
		end tell
		
		local foundTemplates
		tell application id "DNtp"
			set foundTemplates to (search "type:group name:!<_" in selectedCategoryGroup with exclude subgroups)
		end tell
		
		local sortedTemplates
		set sortedTemplates to sortRecordNames(foundTemplates)
		
		templatesPopup's removeAllItems()
		my (templatesPopup's addItemsWithTitles:sortedTemplates)
	end try
end updateOtherFields:


Why do you use so many subsequent tell … "DNtp" blocks? I’m not an Apple script person, but wouldn’t it be simpler to group all these statements related to DT in a single tell block?

Can you clarify what you mean by this?

I had some weird problems with dialog toolkit plus in another script. So I split things up.

Data in DT and Templates in dtTemplate “files”. Now my data and most of my templates are held by Devonthink.

I guess I don’t understand how you’re actually using the templates.
An example of a template generated by your system would be useful.

  1. I use some kind of a “fluid” approach with my templates
    1. Use them
    2. Change them - if required
    3. Back to 1.
  2. Some letters require a signature - I created a png file with my signature and replicate the group to all templates requiring it.

I use the templates with this script: Store, version LaTeX and generate PDF from within DEVONthink . I attached an example for a template in that thread.

Nowadays, I try only to run code which requires DT in tell … “DNtp” blocks after I searched multiple days for a solution for an error with a non foreground thread with DT and Dialog Toolkit Plus.