Experimental: qNote applet to take DT note anywhere in macOS

Purpose: To take a simple note in macOS while using other apps and save the note under DT3.

Why using a script instead of using Sorter or services menu:
(1) Those who use multiple 32" displays in full resolution will probably know why. Sorter’s window is not floating when using “Show as Menu Extra” (typing while looking up at the top-right corner of the screen is not comfortable for my neck), and is placed on the farthest edge or corner of all displays when using “Show as Dock Tab”.
(2) I usually save notes in only two groups but need to clip other info to quite a few different groups. With sorter, I need to keep switching the destination. If I use the services menu, there is only one choice (the root of the global inbox) and the default name of the note is the entire selected text.
(3) Perhaps the most important reason is that I am testing to use “Dialog Toolkit Plus.scptd” to create customised dialogue box. The script addition is developed by Shane Stanley. Shane and Mark are the developers of Script Debugger.

Note 20190420: you can now download Dialog Toolkit Plus here in Late Night Software website.

How to use the script:

  • Download “Dialog Toolkit Plus.scptd” and save it under “/Library/Script Libraries”
  • Save the script as the format of “Application” and not “Script”. It will be a lot more convenient if you have BTT or KM or any similar app for assigning a shortcut key to the application. P.S. I think saving as script will work, too but I’m not sure.

Demo:

  • Call the script applet anywhere in macOS. (1) The first line is automatically used as the note’s name and a date string will be added as a prefix. (2) I can choose from three main groups for saving the notes. (3) Note can be saved in markdown or rich text format.

  • A note is created in DT3. The first line will be bolded if “Markdown” format is used.

The configuration of the script before it is saved as a script application.

property qNoteGps : {{"NoteGp1", "XXXXX-4BE3F9516720"}, {"NoteGp2", "XXXXX-0766195DC024"}, {"NoteGp3", "XXXXX-6B5D1048D710"}}
property openNoteAfterCreation : false
  • I create a group in the inbox of my most frequently used databases. I specify the name and uuid of those groups in qNoteGps. I use three groups, but there is no limitation in the number of groups that can be shown in the dropdown list.
  • If property openNoteAfterCreation is true, the note will be opened. Else the script will just saved the note to DT3.

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


property qNoteGps : {{"NoteGp1", "XXXXX-4BE3F9516720"}, {"NoteGp2", "XXXXX-0766195DC024"}, {"NoteGp3", "XXXXX-6B5D1048D710"}}
property openNoteAfterCreation : false

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 200 label text "Note:" with accepts linebreak and tab
set {theRule, theTop} to create rule (theTop + 12) rule width accViewWidth
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 "Markdown" 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 1

set allControls to {noteField, noteLabel, theRule, 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


tell application id "DNtp"
	
	if buttonName is "OK" then
		set theDate to my getDateString(current date, "ymdhn", ".")
		
		-- get the location to save the note
		set qNoteGpUUID to my vLookup(controlsResults's item 6, 1, 2, qNoteGps)
		set qNoteGp to (get record with uuid qNoteGpUUID)
		--get the format of the note to be saved
		set fileFormatPopup to controlsResults's item 4
		--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
		
		if fileFormatPopup 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 fileFormatPopup is "Rich Text" then
			set theNote to create record with {name:theName, source:theContent, type:rtfd} in qNoteGp
		end if
		
		if openNoteAfterCreation then
			activate
			open tab for record theNote
		end if
	end if
end tell


on getDateString(theDate, theFormat, 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 theFormat to (every character of theFormat)
	repeat with each in theFormat
		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

4 Likes

A minor feature update: “save only” or “save+open” for the newly created note can now be set in the dialog box directly. This comes handy when I want to paste image to the note right after it is created.

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 application
-- 2. Download Dialog Toolkit Plus.scptd and save it under "/Library/Script Libraries"

-- by ngan 2020.04.18
--v3b2
-- add "save-only" and "save+open" option


property qNoteGps : {{"NoteGp1", "XXXXX-4BE3F9516720"}, {"NoteGp2", "XXXXX-0766195DC024"}, {"NoteGp3", "XXXXX-6B5D1048D710"}}


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 200 label text "Note:" with accepts linebreak and tab
set {theRule, 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 "Save Only" 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 "Markdown" 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 1

set allControls to {noteField, noteLabel, theRule, 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


tell application id "DNtp"
	
	if buttonName is "OK" then
		set theDate to my getDateString(current date, "ymdhn", ".")
		
		-- get the location to save the note
		set qNoteGpUUID to my vLookup(controlsResults's item 8, 1, 2, qNoteGps)
		set qNoteGp to (get record with uuid qNoteGpUUID)
		-- get the action for save only or save + open
		set openNoteAfterCreation to controlsResults's item 4
		--get the format of the note to be saved
		set fileFormatPopup to controlsResults's item 6
		--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
		
		if fileFormatPopup 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 fileFormatPopup is "Rich Text" then
			set theNote to create record with {name:theName, source:theContent, type:rtfd} in qNoteGp
		end if
		
		if openNoteAfterCreation is "Save+Open" then
			activate
			open tab for record theNote
		end if
	end if
end tell


on getDateString(theDate, theFormat, 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 theFormat to (every character of theFormat)
	repeat with each in theFormat
		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



1 Like

A complimentary script for jumping to different groups of notes. This script should be saved under the DT3’s script menu folder and run within DT3.

The script:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

property qNoteGps : {{"NoteGp1", "XXXXX-4BE3F9516720"}, {"NoteGp2", "XXXXX-0766195DC024"}, {"NoteGp3", "XXXXX-6B5D1048D710"}}

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

tell application id "DNtp"
	set theName to (choose from list qNoteGpsName with prompt "Choose qNote in Database" default items (item 1 of (qNoteGps's item 1))) as string
	
	set qNoteGpUUID to my vLookup(theName, 1, 2, qNoteGps)
	set qNoteGp to (get record with uuid qNoteGpUUID)
	
	set root of viewer window 1 to qNoteGp
	
	
end tell


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

Thank you! As you noted, Sorter can be not very usable and this is a nice alternative. I look forward to trying it!

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

An updated version is post here:
qNote2: take and save note in DT from anywhere, capture web URL, append selected text and fenced code block, capture screen, set reminder and calendar event