Devonthink for lawyers redux - or how to create chronologies

I was revisiting how to use Devonthink to speed up making chronologies and came across @stephenjw 's post in this thread on August 2021.

I am wondering how you got Devonthink to sort in date order with the dates in the traditional format - dd/mm/yyyy - rather than ISO format - yyyy/mm/dd ?

Also, I am wondering what solution(s) people have for creating a timeline from a chronology created in Devonthink?

When clicking on a date heading in a list of documents DT sorts by that date. Regardless of its format.

But I’m not sure where you are seeing that „traditional“ (rather: local, other regions have other traditions) format and where you want to sort the documents.

I had understood - or perhaps misunderstood - from @stephenjw 's post in the linked thread that he creates a series of individual markdown notes with titles such as 10-03-2023 - The victim met the defendant behind the football ground.

The only way I have been able to sort notes like that chronologically is to write the date in ISO format : 2023-03-10 etc.

That is fine for me but often just confuses people I need to share the chronological list with

Obviously I can’t speak for @stephenjw, but looking at the linked post’s capture he probably sorted by creation date or used Custom Meta Data and sorted by that.

1 Like

Hi @wrothnie - @pete31 is right. I set & sort by creation date (because you can then sort chronologically in DTTG easily).

Here’s the script if you would like it (disclaimer: I’m not a scripter and most of what I have has been cobbled together from scripts which Christian, Jim, pete31 and others have been kind enough to share, but it works for me. Any suggested improvements would be gratefully received. :sweat_smile: )

-- Creates note with date, event and link in inbox and sets creation date to date of source document

use AppleScript version "2.4"
use framework "AppKit"
use scripting additions

property theDelimiter : return & return -- or e.g. linefeed & linefeed
property theSeparator : "---" & return

tell application id "DNtp"
	
	try
		if not (exists think window 1) then
			error "Please open a window"
		else
			set theWindow to think window 1
		end if
		
		set thisRecord to content record of theWindow
		
		if thisRecord ≠ missing value then
			set theType to (type of thisRecord) as string
			
			try
				set theSelectedText to selected text of theWindow & "" as string
			on error
				display notification "No text selected"
				set theSelectedText to ""
			end try
			
			if theType is in {"PDF document", "«constant ****pdf »"} then
				set thePage to current page of theWindow
				set theRefURL to reference URL of thisRecord & "?page=" & thePage
			end if
		end if
		
		set theDatabase to current database
		
		set defaultDate to creation date of thisRecord
		
		-- get creation date of thisRecord 
		
		set theYear to the ((year in defaultDate) as integer) as string
		if (month in defaultDate) as integer is less than 10 then
			set theMonth to "0" & ((month in defaultDate) as integer) as string
		else
			set theMonth to ((month in defaultDate) as integer) as string
		end if
		if (day in defaultDate) as integer is less than 10 then
			set theDay to "0" & the ((day in defaultDate) as integer) as string
		else
			set theDay to the ((day in defaultDate) as integer) as string
		end if
		if (hours in defaultDate) as integer is less than 10 then
			set theHour to "0" & ((hours in defaultDate) as integer) as string
		else
			set theHour to ((hours in defaultDate) as integer) as string
		end if
		if (minutes in defaultDate) as integer is less than 10 then
			set theMinutes to "0" & ((minutes in defaultDate) as integer) as string
		else
			set theMinutes to ((minutes in defaultDate) as integer) as string
		end if
		
		set displayDate to theDay & theMonth & theYear & " " & theHour & theMinutes as string
		
		-- get doc link
		
		set theInbox to (incoming group of the current database)
		set theName to name of thisRecord
		
		-- determines whether to include selected text or not
		
		if theSelectedText is not "" then
			set theContent to theDelimiter & theSelectedText & theDelimiter
			
		else
			set theContent to "" & theDelimiter
			
		end if
		
		-- prompt for date and event
		
		set userDate to display name editor "Date (DDMMYYYY HHMM)" info "Enter date of the event (default is date of record)." default answer displayDate
		
		set chronoCreationDate to creation date of thisRecord
		
		set displayMinutes to "00"
		
		try
			
			set displayDay to (characters 1 thru 2 in userDate) as string
			
			set displayMonth to (characters 3 thru 4 in userDate) as string
			
			set displayYear to (characters 5 thru 8 in userDate) as string
			
		end try
		
		try
			
			set displayHours to (characters 10 thru 11 in userDate) as string
			
			set displayMinutes to (characters 12 thru 13 in userDate) as string
			
		end try
		
		if displayMinutes is not "00" then
			
			set displayDate to displayDay & "." & displayMonth & "." & displayYear & " " & displayHours & ":" & displayMinutes
			
			set year of chronoCreationDate to displayYear as integer
			set month of chronoCreationDate to displayMonth as integer
			set day of chronoCreationDate to displayDay as integer
			set hours of chronoCreationDate to displayHours as integer
			set minutes of chronoCreationDate to displayMinutes as integer
			set seconds of chronoCreationDate to 0
			
			
		else
			
			set displayDate to displayDay & "." & displayMonth & "." & displayYear
			
			set year of chronoCreationDate to displayYear as integer
			set month of chronoCreationDate to displayMonth as integer
			set day of chronoCreationDate to displayDay as integer
			set hours of chronoCreationDate to 0
			set minutes of chronoCreationDate to 0
			set seconds of chronoCreationDate to 0
			
		end if
		
		set theEvent to display name editor "Event" info "Enter the event this record relates to."
		
		if displayDay is "01" then
			
			set altDate to display name editor "Do you want to assign a different display date?" info "Example display date, eg Sep YYYY?" default answer (displayDay & "." & displayMonth & "." & displayYear)
			
		else
			
			set altDate to displayDate
			
		end if
		
		set theLocation to display group selector "Destination" buttons {"Cancel", "OK"}
		
		
		create record with {name:(altDate & " - " & theEvent), type:markdown, creation date:(chronoCreationDate), content:("# " & altDate & " - " & theEvent & theDelimiter & return & "[" & theName & "](" & theRefURL & ")") & theContent} in theLocation
		
		
	on error error_message number error_number
		hide progress indicator
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
	end try
end tell

It’s quite quick to create as you go through documents in a new brief. The idea is you can copy key (ie highlighted) text about the event from the document you are looking at into the note (but you don’t have to copy anything) with a link back to the document. I go back and manually add links in individual notes to additional evidence later (eg another witness’ conflicting testimony about a key event).

This is what the process looks like (I’ve taken it from a random court case for the purposes of this example):

(1) Trigger script using whatever keystroke you assing:

(It’s showing a default date and time which is the creation date of the particular document I’m using here.)

(2) Type in the date of the event you want to capture:

I’ve tweaked to allow you to put in a “display date” such as a month or a year where you don’t have enough information to input a date in DDMMYYYY format or want to put in a date range (eg “Apr to June 2009”). An additional input box for the display date comes up whenever the date is “01”.

You can put in a time as well, but don’t have to.

(3) Type in a description of the event

(4) The script will pull up the sorter:

I use a subdirectory (“@ chronology”) in each project/ matter database (the reason for the “@” is so it appears near the top and stands out from other subdirectories).

(5) This is how it looks as you build it up:

2 Likes

Wow! Thank you!

Your scripting abilities are way beyond mine.

I have tried it and it creates exactly the right kind of note for selected text and I do like your point about linking in links to additional evidence.

I didn’t understand your comment about DTTG, however, I didn’t think scripts could run in DTTG. Certainly, I agree that if it weren’t for that it is usually more convenient to be reviewing documents on the iPad.

Thank you once again for your generosity!

1 Like

Glad it worked for you - hope it is useful.

You’re right - AFAIK they don’t. What I meant to say was that by setting the creation date of the note to the date of the event (which the script does), you can sort by Date Created in DTTG so that the notes appear in chronological order.

Another option if you need a working chronology on your iPad is to merge the notes into a single markdown document, which I sometimes do for when I’m on my feet in court.

Ah. Thanks!

Just another frustration of the limitations built into the ipad.

I use an Applescript that creates a Table-of-Contents note for the note collection
. html format (formatted note)
. entries are sectioned and sorted as required
. entries are linked to the original notes
The ToC document functions in both DevonThink and DTTG

sort in date order with the dates in the traditional format - dd/mm/yyyy - rather than ISO format - yyyy/mm/dd

The script uses it’s own hidden sort fields for the ToC entries

I hear you. So much potential, so let down by the operating system. :neutral_face:

1 Like

Not sure what you’re referring to here. If this is about the lack of a scripting language on i*OS: Apple is simply not interested in supporting scripting anywhere. They don’t do any work on AppleScript on the Mac, nor on the abandoned JXA, and they’ve deprecated Perl (not sure about Python). For i*OS, the argument (if there even is one) is probably “security”. Though we know that there are apps supporting scripting (in JavaScript or Python) on i*OS, e.g. Drafts, Pythonista and Scriptable (apparently abandoned, also).

And Apple is apparently going for crippled approaches like Shortcuts (and the now all but dead Automator): Shortcuts does allow for scripts, but only on macOS. For not technical reason at all, at least for JavaScript code.

App developers who want to provide scripting on all Apple platforms could go for JavaScript since support for that is built into the OS anyway (because of Safari). That’s what Drafts does. But this is an entirely different approach from Apple’s OSA, so everybody would be reinventing wheels.

1 Like

Hi @chrillek

That’s interesting about JavaScript (something I know nothing about).

The iPad is potentially brilliant for work from a business user’s point of view. For taking handwritten notes in a meeting, for reading and referring to documents it’s unobtrusive and user-friendly. Scrawling a note on a document feels more easy and intuitive than messing round typing text boxes on a Mac. When I am on my feet in front of a judge, an iPad lies flat on the lectern and I can look the judge in the eye while swiping from one document to the next. There’s something a bit anti-social about clacking away behind a laptop screen in many professional settings.

But then you bump up against iOS’ limitations. Apple seems to have improved file management but it’s still too fiddly having to share documents between apps. DTTG takes quite a bit of the pain out of the process (and it’s frankly easier to do all my noting up in DTTG knowing that markups will be saved in place). But there’s just so many things that you just can’t do in iOS.

I am really just repeating grizzles other people have been making for many years and have strayed from the original post.

I take your point about the limitations of scripting support and the impact on app developers. (Did you put the asterisk in “i*OS” to signify that it’s not a “real” operating system? :slightly_smiling_face:) I didn’t mean in any way to suggest that the problem lay with the app developers. It’s impressive how much functionality DTTG has wrung out of the system.

No - there’s iOS and iPadOS. The asterisk is short for „both“.

1 Like

Warwick,

Good to see that the discussion in the other place has spilled over to here. I will come back to this thread next week - busily prepping for a 2 day hearing next week where I would love to be across all this now although I have built the chronology for the matter in Filemaker. Also, need to get across incorporating annotations in Devonthink into Chronologies and submissions.

I use Text Expander for dates. Simply create the format you want and a trigger abbreviation. Works in all apps.

Sorting YYYY-MM-DD I find easier because at a glance is the year which for the law is generally more useful to begin with than the actual date.

If you’re not applying styling to the date…
Depending on your settings in System Settings > Language & Region > Date Format, you could also just use our WordService > Insert Short Date service. :wink:

Could you provide a copy of the AppleScript you are using?

Click to see script
tell application id "DNtp"
	
	set theTagList to {} ------------------------------------------------------------------------------- Retrieve the list of project tags and process each project
	set theTagGroup to item 1 of (every record of database "FilingCabinet" whose name is "Tags")
	set theProjectTags to every child of theTagGroup whose name starts with "vProject:"
	repeat with theProjectTag in theProjectTags
		
		set projectName to texts 10 thru -1 of (name of (theProjectTag) as string)
		
		if character 1 of projectName is not "x" then
			
			set project to {}
			set projectNotes to {}
			set projectReceipts to {}
			set tasksActive to {}
			set tasksNextAction to {}
			set tasksPending to {}
			set tasksWaiting to {}
			set tasksCompleted to {}
			set theChildren to (every child of theProjectTag)
			
			repeat with theNote in theChildren ------------------------------------------------------------- Retrieve the Project data
				
				set theName to my ExtractName(name of theNote)
				set theLabel to label of theNote
				set theTags to tags of theNote
				set theLink to the reference URL of theNote
				set theTaskDate to get custom meta data for "taskduedate" from theNote default value "-"
				if theTaskDate is not "-" then set theName to theName & " (" & theTaskDate & ")"
				
				if "cType-ProjectToC" is in theTags then --------------------------------------Split into sections
					delete record theNote
				else if "vAction-Project" is in theTags then
					set projectName to texts 12 thru -1 of theName
					set end of project to {theName, theLink}
				else if "cType-Receipt" is in theTags then
					set end of projectReceipts to {theName, theLink}
				else if "vAction-Task" is in theTags or theTaskDate is not "-" then
					if theLabel is 0 or theLabel is 1 then
						set the end of tasksPending to {theName, theLink}
					else if theLabel is 2 then
						set end of tasksActive to {theName, theLink}
					else if theLabel is 3 then
						set the end of tasksNextAction to {theName, theLink}
					else if theLabel is 4 then
						set the end of tasksCompleted to {theName, theLink}
					else if theLabel is 5 then
						set the end of tasksWaiting to {theName, theLink}
					else
						set the end of projectNotes to {theName, theLink} -- default tasks	
					end if
				else
					set the end of projectNotes to {theName, theLink}
				end if
			end repeat
			
			set theNoteName to "0000-00-00 ProjectToC [" & projectName & "]" --------------------------------Format the ToC mote
			set theSource to "<html>
	<head>
	<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>
	<meta name=\"DT:isEditableNote\" content=\"Yes\"/>
	<style>
	</style>
	</head>
	<body style=\"background-color:ivory; margin:1.5em; font-family:'Times-Roman','Times'; font-size:14px\">
		<table style=\"border: 1px solid black;\">"
			
			set theSource to theSource & my FormatSection("Project", project)
			set theSource to theSource & my FormatSection("Notes", projectNotes)
			set theSource to theSource & my FormatSection("Receipts", projectReceipts)
			set theSource to theSource & my FormatSection("Tasks - Active", tasksActive)
			set theSource to theSource & my FormatSection("Tasks - Next Action", tasksNextAction)
			set theSource to theSource & my FormatSection("Tasks - Waiting", tasksWaiting)
			set theSource to theSource & my FormatSection("Tasks - Pending", tasksPending)
			set theSource to theSource & my FormatSection("Tasks - Completed", tasksCompleted)
			
			set theSource to theSource & "</tr></table></body></html>"
			
			set theFilingGroup to get record with uuid "AA28F696-D9F9-4FC3-9089-B1EDBC96011E" in database "FilingCabinet" ------ Create Note
			set newRecord to create record with {name:theNoteName, type:formatted note} in theFilingGroup
			set source of newRecord to theSource
			set tags of newRecord to {"cType-ProjectToC", theProjectTag}
			--set theWindow to open window for record (newRecord)
		end if
	end repeat
end tell


on ExtractName(theName) ----------------------------------------------- Precise name is specified within []
	set extractedName to text 1 thru 10 of theName & " "
	set extractSW to false
	repeat with theChar in characters of theName
		if theChar as string is "[" then
			set extractSW to true
		else if theChar as string is "]" then
			set extractSW to false
			set extractedName to extractedName & " "
		else
			if theChar as string is "$" then set extractSW to true
			if extractSW is true then set extractedName to extractedName & theChar
		end if
	end repeat
	return extractedName
end ExtractName


on FormatSection(theHeading, theNotes)
	set theSource to ""
	set theNotes to my SortNotes(theNotes)
	set theSource to theSource & "<h3>" & theHeading & "</h3>"
	repeat with theNote in theNotes
		set theSource to theSource & "<a href=" & (item 2 of theNote) & ">" & (item 1 of theNote) & "</a><br>"
	end repeat
	return theSource
end FormatSection


on SortNotes(theNoteList) ----------------------------------------------- Generic Sort
	set the index_list to {}
	set the sortedNoteList to {}
	repeat (the number of items in theNoteList) times
		set the lowSort to ""
		repeat with i from 1 to (number of items in theNoteList)
			if i is not in the index_list then
				set thisNote to item i of theNoteList
				set thisName to item 1 of thisNote
				--set thisDate to item 2 of thisNote
				set thisLink to item 2 of thisNote
				set thisSort to thisName
				if the lowSort is "" then
					set lowSort to thisSort
					set low_item_index to i
				else if thisSort comes before lowSort then
					set the lowSort to thisSort
					set the low_item_index to i
				end if
			end if
		end repeat
		set the end of sortedNoteList to item low_item_index of theNoteList
		set the end of the index_list to the low_item_index
	end repeat
	return sortedNoteList
end SortNotes

This script generates Table of Contents notes for my active projects
Projects are identified with a tag (*Project-aaaaa") assigned to every note associated with the project
The script extracts the notes, organizes them into sections
then sorts, and inserts into the ToC note as hyperlinks
Here’s a sample ToC note

Many thanks - more food for thought when compiling a chronology.