Experimental: qNote applet to take DT note anywhere in macOS

Another minor feature update: add a number of basic remainder functions.

:

  • The field next to the dropdown is for setting the time for alert/action. The default is always the current time for the convenience of editing. The format must be followed strictly and according to macOS system (UK) of DD.MM.YYYY HH:MM (24 hr). I have added some flexibility in setting the date format option for different system date format but haven’t tested it (see below).
property alarmDateTimeFormat : "dmy" -- macOS system date format for UK, day followed by month by year
  • The field below the time field is a text field and its input is dependent on the reminder type.

  • In theory, the type of reminders can be customised in the script. However, I haven’t included some reminder types either because they don’t work (reading list), I don’t use them, or they complicate the script for a quick note-taking script. In fact, I use echo device for reminder most of the time.

property reminderTypeList : {"No Reminder", "Alert", "Notification", "Speak Text", "Send mail", "Launch URL"}

The script:

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

-- Important Notes:
-- 1. save the script as an application
-- 2. Download Dialog Toolkit Plus.scptd and save it under "/Library/Script Libraries"

-- by ngan 2020.04.18
-- v3b2 add save or save+open note
--v3b3 add basic remainder function
--v3b4 add a number of reminder functions

property qNoteGps : {{"NoteGp1", "XXXXX-4BE3F9516720"}, {"NoteGp2", "XXXXX-0766195DC024"}, {"NoteGp3", "XXXXX-6B5D1048D710"}}
property reminderTypeList : {"No Reminder", "Alert", "Notification", "Speak Text", "Send mail", "Launch URL"}
property alarmDateTimeFormat : "dmy" -- macOS system date format for UK, day followed by month by year

global theDate, theName, theContent, openNoteAfterCreation, fileFormat
global qNoteGp, qNoteGpUUID
global alarmDateTime, addReminder, reminderMessage


set qNoteGpsName to {}
repeat with eachGp in qNoteGps
	set end of qNoteGpsName to item 1 of eachGp
end repeat

-- "Dialog Toolkit Plus" coding
set accViewWidth to 600
set {theButtons, minWidth} to create buttons {"Cancel", "OK"} default button 2 given «class btns»:2
if minWidth > accViewWidth then set accViewWidth to minWidth -- make sure buttons fit
set {noteField, noteLabel, theTop} to create top labeled field "" placeholder text "" bottom 0 field width accViewWidth extra height 400 label text "Note:" with accepts linebreak and tab
set {theRule2, theTop} to create rule (theTop + 12) rule width accViewWidth

set {alarmTextField, alarmTextLabel, theTop, fieldLeft} to create side labeled field "" placeholder text "Type message/email address/url here" bottom (theTop + 8) total width accViewWidth label text "Reminder message:    " field left 0

set {addReminderPopup, theTop} to create popup reminderTypeList left inset 0 bottom (theTop + 8) popup width 160 initial choice 1

set {alarmDateTimeField, theTop} to create field (my getDateString(current date, alarmDateTimeFormat, ".") & " " & my getDateString(current date, "hn", ":")) left inset 170 bottom (theTop - 22) field width accViewWidth - 170

set {theRule1, theTop} to create rule (theTop + 12) rule width accViewWidth

set {openNotePopup, openNoteLabel, theTop} to create labeled matrix {"Save Only", "Save+Open"} bottom (theTop + 8) max width accViewWidth - 300 matrix left 0 label text "Action: " initial choice 1 without arranged vertically

set {fileFormatPopup, fileFormatLabel, theTop} to create labeled matrix {"Markdown", "Rich Text"} bottom (theTop + 8) max width accViewWidth - 300 matrix left 0 label text "Format:" initial choice 1 without arranged vertically

set {locPopup, locLabel, theTop} to create labeled popup qNoteGpsName bottom (theTop + 8) popup width 250 max width accViewWidth label text "Inbox:  " popup left 0 initial choice 3

set allControls to {noteField, noteLabel, theRule2, alarmTextField, alarmTextLabel, addReminderPopup, alarmDateTimeField, theRule1, openNotePopup, openNoteLabel, fileFormatPopup, fileFormatLabel, locPopup, locLabel}

set {buttonName, controlsResults} to display enhanced window "Quick Note" acc view width accViewWidth acc view height theTop acc view controls allControls buttons theButtons active field noteField with align cancel button
--  end of "Dialog Toolkit Plus" coding

-- credit @Bluefrog's snippet
--get parameters of reminder
set reminderDateTime to (date (controlsResults's item 7 as string))
set addReminder to controlsResults's item 6
set reminderMessage to controlsResults's item 4


tell application id "DNtp"
	
	if buttonName is "OK" then
		set theDate to my getDateString(current date, "ymdhn", ".")
		
		--use 1st line of note as filename
		set theName to first paragraph of controlsResults's item 1
		-- Add creation date as prefix, if first line is blank, set default name to date & "Note"
		if theName is "" then
			set theName to theDate & " - Note"
		else
			set theName to theDate & " - " & theName
		end if
		--get content of the note
		set theContent to controlsResults's item 1
		-- get the action for save only or save + open
		set openNoteAfterCreation to controlsResults's item 9
		--get the format of the note to be saved
		set fileFormat to controlsResults's item 11
		-- get the location to save the note
		set qNoteGpUUID to my vLookup(controlsResults's item 13, 1, 2, qNoteGps)
		set qNoteGp to (get record with uuid qNoteGpUUID)
		
		
		if fileFormat is "Markdown" then
			-- bold first line (the name)
			set theContent to every paragraph of theContent
			set theContent's item 1 to "**" & theContent's item 1 & "**"
			-- there is an invisible line return "\n" in this line
			set theContent to my listToStr(theContent, "
")
			set theNote to create record with {name:theName, source:theContent, type:markdown} in qNoteGp
		else if fileFormat is "Rich Text" then
			set theNote to create record with {name:theName, source:theContent, type:rtfd} in qNoteGp
		end if
		
		set unread of theNote to true
		
		-- set reminder
		if addReminder is "Alert" then
			tell theNote to make new reminder with properties {schedule:once, alarm:alert, alarm string:reminderMessage, due date:reminderDateTime}
		else if addReminder is "Notification" then
			tell theNote to make new reminder with properties {schedule:once, alarm:notification, alarm string:reminderMessage, due date:reminderDateTime}
		else if addReminder is "Speak Text" then
			tell theNote to make new reminder with properties {schedule:once, alarm:speak, alarm string:reminderMessage, due date:reminderDateTime}
		else if addReminder is "Send mail" then
			tell theNote to make new reminder with properties {schedule:once, alarm:mail, alarm string:reminderMessage, due date:reminderDateTime}
		else if addReminder is "Launch URL" then
			set the URL of theNote to reminderMessage
			tell theNote to make new reminder with properties {schedule:once, alarm:launch, due date:reminderDateTime}
		end if
		
		if openNoteAfterCreation is "Save+Open" then
			activate
			open tab for record theNote
		end if
	end if
end tell


on getDateString(theDate, theDateFormat, theSeperator)
	tell application id "DNtp"
		local y, m, d, h, n, s, T
		local lol, ds
		set lol to {{"y", ""}, {"m", ""}, {"d", ""}, {"h", ""}, {"n", ""}, {"s", ""}}
		
		set (lol's item 1)'s item 2 to get year of theDate
		set (lol's item 2)'s item 2 to my padNum((get month of theDate as integer) as string, 2)
		set (lol's item 3)'s item 2 to my padNum((get day of theDate) as string, 2)
		set T to every word of (get time string of theDate)
		set (lol's item 4)'s item 2 to T's item 1
		set (lol's item 5)'s item 2 to T's item 2
		set (lol's item 6)'s item 2 to T's item 3
	end tell
	
	set ds to {}
	set theDateFormat to (every character of theDateFormat)
	repeat with each in theDateFormat
		set ds to ds & (my lolLookup(each as string, 1, 2, lol))'s item 2
	end repeat
	
	return my listToStr(ds, theSeperator)
	
end getDateString

on padNum(lngNum, lngDigits)
	-- Credit houthakker
	set strNum to lngNum as string
	set lngGap to (lngDigits - (length of strNum))
	repeat while lngGap > 0
		set strNum to "0" & strNum
		set lngGap to lngGap - 1
	end repeat
	strNum
end padNum

on lolLookup(lookupVal, lookUpPos, getValPos, theList)
	--only for list of list with more than 1 items
	local i, j, k
	set j to lookUpPos
	set k to getValPos
	repeat with i from 1 to length of theList
		if (item j of item i of theList) is equal to lookupVal then return {i, item k of item i of theList, item i of theList}
	end repeat
	return {0, {}, {}}
end lolLookup

on vLookup(lookupVal, lookUpPos, getValPos, theList)
	--only for list of list with more than 1 items
	local i, j, k
	set j to lookUpPos
	set k to getValPos
	repeat with i from 1 to length of theList
		if (item j of item i of theList) is equal to lookupVal then return item k of item i of theList
	end repeat
	return {}
end vLookup

on listToStr(theList, d)
	local thestr
	set {tid, text item delimiters} to {text item delimiters, d}
	set thestr to theList as text
	set text item delimiters to tid
	return thestr
end listToStr