Create a New Note From AppleScript

Partly to build a new TBX for daily use, partly as an exercise to learn how to use Tinderbox, I’ve created a new “daily notes” kind of TBX called Captain’s Log

Working from the structure of my blog test platform, I have as Root, the Captain’s Log, which creates the container for the current year. In turn, the year container creates the current month, and the month container creates a daily note which will be the container for each day’s log entries.

The log is intended to be a kind of journal, though it will also record other events.

Ideally, I should be able to make a log entry without being in Tinderbox, much like I can create a Photo post to my blog from Photos.

For now, I’m modifying the Photos script to create a new note in the current day’s container. I have confidence that the script works up to that point. The note is created in the relevant container, but I can’t add the $Name and $Text attributes, which are created via AppleScript dialogs.

This script looks like this (I’m probably missing the proper formatting):

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

set entryTitle to display dialog "Entry Title?" default answer ""
copy the result to {button returned:buttonPressed, text returned:titleString}
set entryText to display dialog "Entry Text?" default answer ""
copy the result to {button returned:buttonPressed, text returned:entryString}
tell application "Tinderbox 9"
	set this_moment to (the current date)
	set nmMonth to (month of this_moment) as string
	set nmYear to (year of this_moment) as string
	set thePath to "Captain's Log/" & nmYear & "/" & nmMonth & " " & nmYear & "/" & date string of this_moment
	tell document "Captain's Log.tbx" -- suffix .tbx required on my machine
		-- this is how to specify a note down in the hierarchy:
		set theContainer to find note in it with path thePath
		set newNote to make new note at theContainer
		tell newNote
			if entryTitle is not missing value then set value of attribute "Name" to entryTitle
			set value of attribute "Text" to entryText
			set value of attribute "Prototype" to "p_Entry"
		end tell
	end tell
end tell

The error I get is this:

But it does create the new entry, just doesn’t populate the attributes. It looks the same as the code I used in the Photos to TBX script, but it’s not working the same.

Once I get this working, I intend to use Automator to turn it into a Quick Action I can assign a keyboard shortcut to, and run it from whatever application I happen to be in.

Further modifications may include log entries of specific emails, attaching Automator actions to Calendar events to create a log entry of a particular Calendar event, and so on. (I will undoubtedly have to ensure only one of my Macs is awake at a time for the Calendar thing. That may be problematic.)

Here is the previous Topic regarding Photos, which yielded a successful, and ongoing, result.

Any help or insight is much appreciated.

Here’s the TBX if you care to look. It’s pretty simple at the moment.
Captain’s Log.tbx (275.1 KB)

I was going to write “I’m too busy to do a test right now…” but curiosity got the better of me. :rofl:

Not quite true, as it does set the $Prototype for the new note. That gives as a clue. The two non-working calls are dialog-derived values and AppleScript Debugger’s variables/value list shows me entryTitle is not—as you suppose—a string but the value of result of the dialog call, which is a list of two properties.

What you actually want is the value of the ‘text returned’ property of the dialog. So change:

set entryTitle to display dialog "Entry Title?" default answer ""
copy the result to {button returned:buttonPressed, text returned:titleString}
set entryText to display dialog "Entry Text?" default answer ""
copy the result to {button returned:buttonPressed, text returned:entryString}

To

set entryTitle to text returned of (display dialog "Entry Title?" default answer "")
set entryText to text returned of (display dialog "Entry Text?" default answer "")

and it works. Huzzah for AppleScript Debugger’s richer reports on what AppleScript does, as I’m no export. The chink of light here was noting that only the prototypes using dialog-derived values weren’t working. I’ll freely admit chasing several wrong conclusions en route to the right one.

Also ended up fixing a few formatting a typo errors in aTbRef—happily in body text not code samples. Those corrections are now rectified in the live HTML pages (and zipped TBX).

1 Like

Bravo Zulu, shipmate!

Indeed, it does work. Odd that the button returned piece doesn’t bother the Photos to Tinderbox script.

Also, imagine my relief this morning when there was the Wednesday, March 6, 2024 container already there, waiting for me. It worked every time making Tuesday during tests, but there’s always a little uncertainty until the day actually rolls over.

I’ll have to inspect the edict again to make sure it doesn’t go on making April dates in the March container, but I’m kind of looking forward to a good April Fools’ joke.

Thanks, Mark. Much appreciated.

1 Like

Hi Dave,
Do you mind posting the updated file once you finish tweaking. Fascinating stuff!
Tom

1 Like

Ooh, haven’t had one of those in a long time. Thanks.

†. Bravo Zulu

1 Like

You can still use your button returned: text returned record structure, but below in the script you then need to refer to the variable after text returned: e.g. to titleString and entryString not to entryTitle and entryText.

In fact you don’t even need entryTitle and entryText because result refers to the line above.

So something like this will work:

display dialog "Entry Title?" default answer ""
copy the result to {button returned:buttonPressed, text returned:titleString}
display dialog "Entry Text?" default answer ""
copy the result to {button returned:buttonPressed, text returned:entryString}

set this_moment to (the current date)
set nmMonth to (month of this_moment) as string
set nmYear to (year of this_moment) as string
set thePath to "Captain's Log/" & nmYear & "/" & nmMonth & " " & nmYear & "/" & date string of this_moment

tell front document of application "Tinderbox 9"
	set theContainer to find note in it with path thePath
	set newNote to make new note at theContainer
	tell newNote
		if titleString is not missing value then set value of attribute "Name" to titleString
		set value of attribute "Text" to entryString
		set value of attribute "Prototype" to "p_Entry"
	end tell
end tell

Those lines at the top of the script, which Script Debugger inserts by default, are rarely needed for basic scripts, especially the one referring to AppleScript version. When I use Script Debugger (I often don’t because Script Editor is lightweight and capable and also does JavaScript) I remove them because I don’t like clutter.

To be safe you might consider removing the apostrophe in the path though it doesn’t seem to be causing problems in your simple example.

2 Likes

Tom, I don’t know that I’ll ever “finish tweaking,” but I’ll post an updated version soon. FWIW, I checked and the necessary conditionals appear to be in place in the edicts to prevent rampant production of unwanted children.

I created a Quick Action in Automator which simply runs the script as modified above (I haven’t considered Sumner’s suggestions at this moment.). It works just fine.

Which brings me to another question. I have an AS that will copy the URL of an email to the clipboard. For the purpose of this exercise, I merely ran the script from FastScripts menu item, which dutifully copied the URL to the clipboard.

In Mail, I’m viewing the email copy of Mark Anderson’s reply above. I invoke the Mail URL AppleScript from the FastScripts menu, and confirm that the URL is on the clipboard. (Clicking on the URL does indeed open that email.)

I then invoke the QA with the key combination (CTRL)(Shift)L.

The QA runs, I enter the Entry Title, and in the Entry Text I enter “Nice reply on AppleScript query: (insert URL from clipboard - see screenshot below)”

(I can’t seem to upload a screenshot just now. I’ll post and try again in Edit.)
(Update: The upload button isn’t working for me. Perhaps I’ve abused a privilege?)
(Update update: Works now.)

The actual text (rich) that appears in the $Text is:

message://%3cdiscourse/post/41031@forum.eastgate.com%3e

Which is identical to the appearance of the text on the clipboard as viewed from the Clipboard Manager pane of UnClutter.

I have what I think is called an “encoding” problem. The text as rendered in the $Text of the note is not a clickable link. What sorcery is necessary to paste the URL as a clickable link?

I’m feeling almost giddy in that the Automator action ran without a hiccup on the first try. (I did have to give Mail permission to control Tinderbox, but that was accomplished in a dialog directly in Mail and not a trip to the Settings app.)

Thanks for your insights and assistance.

2 Likes

Further to the foregoing…

Likewise with URLs copied from Safari, pasted into the $Text by way of AppleScript they aren’t clickable. I can select the text and then the utility PopClip recognizes it and I can click on the little link icon and go to the page. PopClip does not recognized Mail URIs (URI? Is that right?), so that remains something of an issue.

In a happy coincidence, this blog post appeared in my NetNewsWire feed this morning, and it was delightful!

How about in the $URL attribute instead of $Text?

Also think it should be %3C …%3E.

Didn’t test but Make PopClip open x-devonthink links should work with mail links

1 Like

I like your thinking…

Right now, I’m just exploring the realm of the possible for someone like me with limited skills in AppleScript and Action Code. Having the URL in the $Text is useful for now. It might be neater to have it in the $URL attribute, making that attribute among the $KeyAttributes for the p_Entry prototype.

(Also, the lower case E and C are what appear in the URI as detected by AppleScript, and which do open the email when clicked in the clipboard manager. So I’m not certain that would be an error.)

I’ll have to sit down and think of the steps to get the URL into the AppleScript. Automator has some handy URL actions that I hope to explore, but I would do so cautiously. Alternatively, some $Rule that would scan $Text and auto-populate $URL, but then I’m bumping up against my Action Code ignorance. (At the moment, that feels like a lower barrier to overcome than fancy work with AS and attributes.)

For now, I was wondering if there was something I could invoke like “paste as unstyled text” or something like that from the clipboard that would make the URL clickable in $Text. (Which I just thought of, or I’d have tried it before posting this.)

But thanks for the response, you’ve given me an idea or two. This is such a nice community.

Thanks, I’ll check it out!

I’ve joined the PopClip forum and posed a question there regarding Snippets, which seem to be the relevant approach. That link is from 2019 and the Terminal command doesn’t find the array of URL schemes on my machine.

In other developments… I copied the URI to the clipboard, entered some text into a new log entry (not relying on any automation, just working in the file in Tinderbox).

I selected a portion of the text and used the Make Web Link… menu item to make that text into a link.

It worked. Clicking on the text opens the email in Mail.

Likewise, entering the URI into the SourceURL attribute (added as a $DisplayedAttribute in p_Entry), makes it clickable when I click on the globe icon in the Displayed Attributes.

So I think the URI is correct in all respects. It would just be nice to have that URI, ugly as it may be, be a clickable link in the $Text attribute.

Failing that, or in addition to, having some action code scan the $Text for a URI or URL and having it automatically populate the $SourceURL attribute would be a significant improvement.

Thinking through this some more, the “workflow” for making a log entry referencing an email would rely on the $Name attribute to record whatever comment about the email was relevant for the log. “Nice email from Mark Anderson” or something.

Then the $Text would exclusively be the Mail URI.

I think I should be able to cobble together some Action Code in a $Rule(?) to make $SourceURL=$Text and have a clickable link in the log entry note with no further user intervention.

Maybe I should try that rather than taking up everyone’s time here. But it seems like I “see what I think” here too…

Upload shouldn’t be disabled, but it is limited in the formats it accepts (which are tested via the uploaded file’s extension. There may be limitations on what is allowed in the name of the uploaded file.

Not quite clear is the context. I think your scenario is you are adding text to a note that includes a URI (in this case using message:// protocol). Although web links in pasted-in rich text are adopted from the RTF as a Tinderbox web links, I don’t think URIs in plain text URI are detected in the same way. If you are pasting in plain text into $Text then I doubt there is anything to trigger URI detection.

But, as you’re using AppleScript why not post RTF including a link instead of plain text? (Not that I know how to do that, as I write this)

But, as you’re using AppleScript why not post RTF including a link instead of plain text? (Not that I know how to do that, as I write this)

Precisely. I don’t know how to do it either. It’s kind of a question of how important it is.

The important thing is to have the URI somewhere in the log entry, and it’s a trivial matter to get it into $Text, although it’s not immediately clickable.

Manually, I can copy and paste it into the $SourceURL attribute (displayed in p_Entry in the present version of the file), and it becomes clickable there.

For a hands-off operation, I think a $Rule along the lines of $Text.contains some regex to describe an email URI, followed by some code to set $SourceURL to $Text.contains, though I don’t know how that works either. I think it’ll be easier to figure out than a bunch of AppleScript. I’ve been looking at aTbRef and posts in the forum, but I’m happy to let someone just show me!

Then some code to turn off the Rule after the action is completed. It only has one thing to do, and it’d become part of every log entry as it’s in the prototype.

Maybe it would be better as an $OnAdd action, if $Text.contains an email URI, then set the $SourceURL to the URI. (Through some magic that I think I can get Michael Becker to demonstrate at a meetup. :wink:)

Likewise, if $Text.contains a web URL, do the same thing.

OnAdd is probably better than a Rule in the Entry prototype. Gets processed once and it’s done.

I don’t anticipate having $Text with multiple URLs or URIs, though I know that wants and desires can grow over time. For now, it’s enough to just collect a link to the thing that was logged, assuming it has a URL or URI.

I think that’s what I’m going to pursue for now. There are other things I think I want to try with AppleScript, but I want to pick my battles so I don’t get too discouraged!

I’d welcome a precis by email of the URI questions, once those become clear; I’m beyond swamped.

1 Like

Hi Dave … I really like what you’re doing with this script, and I got it working on my end as well.

Then I played around with AppleScript to extend your script so that it brings in a selected message from Apple Mail:

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

tell application "Mail"
	--	if not it is running then activate
	
	if not (get selection) is {} then
		set theMsg to item 1 of (get selection)
	else
		return
	end if
	
	tell theMsg
		set {msgSubj, msgSender, msgContent, msgID} to {subject, sender, content, message id}
		set theText to content of theMsg
		set theSubj to subject of theMsg
		set theSender to sender of theMsg
		set msgURL to "message://%3C" & msgID & "%3E"
		set dateSentStr to my dateToStr(date sent)
		set existsAttach to exists mail attachments
	end tell
end tell

tell application "Tinderbox 9"
	set this_moment to (the current date)
	set nmMonth to (month of this_moment) as string
	set nmYear to (year of this_moment) as string
	set thePath to "CaptainsLog/" & nmYear & "/" & nmMonth & " " & nmYear & "/" & date string of this_moment
	tell document "CaptainsLog.tbx" -- suffix .tbx required on my machine
		-- this is how to specify a note down in the hierarchy:
		set theContainer to find note in it with path thePath
		set newNote to make new note at theContainer
		tell newNote
			set value of attribute "Prototype" to "pEmail"
			set value of attribute "Name" to theSubj
			set value of attribute "Attachment" to existsAttach
			set value of attribute "URL" to msgURL
			set value of attribute "StartDate" to dateSentStr
			set value of attribute "Sender" to theSender
			set value of attribute "Text" to theText
		end tell
	end tell
end tell

to dateToStr(aDate) --> convert AppleScript date to string in format that Tinderbox recognizes
	tell aDate to return date string & ", " & time string
end dateToStr

Still a work in progress, but it works! Next step is probably to do the same thing with Calendar events.

1 Like

I’ve emailed @eastgate with a summary. Essentially:

Cutting aside all the wider context the question is this:

  • via script we set $Text of a note
  • the new text includes a valid URI as plain text, i.e. there is no Tinderbox web link on the URI text.
    • e.g. This is some message://%3cdiscourse/post/41031@forum.eastgate.com%3e more text.
  • placing the text insertion cursor in $Text after the end of the URI and typing a character triggers auto-recognition/adoption of the URI. But we can’t do that during scripting.
  • how do we, can we, signal to Tinderbox that we want it to scan the note’s text and adopt any valid URI?

Note, I tried running update() on such a note but it had no effect on undetected URI.

TL;DR we are looking for a user-activated call to scan and adopt valid URIs.

1 Like

That’s very cool!

This suggests, to me, to create a separate AppleScript for logging emails to Captain’s Log.

In my conception, I wouldn’t need each of those attributes. Basically just the URL. I don’t need to replicate the contents of the email in the log, just record that I received it (for whatever reason that made it worthwhile to log, maybe my reaction to it or whatever), and a link to the original email.

I see how you’re constructing the URI (msgURL) using

"message://%3C" & msgID & "%3E"

It makes me wonder if the case of C and E is irrelevant?

So I think I’ll take your script, modify it, and then add it to the FastScripts Menu for Mail. I’d keep the same Title and Text dialogs as they, together with $Created, are the essential elements of a “log entry.” Then I wouldn’t need an OnAdd in a day’s container to move the URI from $Text to $URL as it’d be populated that attribute directly from the Mail AppleScript.

Likewise, a similar AS in the FastScripts menu for Safari to Captain’s Log.

I haven’t completely figured out what I want the interaction with Calendar to be.

The log isn’t intended as a planning document. There’s a feature that allows you to attach an Automator action to an Alert for an event (I just looked and it must be “Open File,” I’m not sure. I’m relying on watching old YouTube videos, maybe the functionality has changed), and I thought that I might, for certain events, have an entry automatically created in the log.

Medical or dental appointments, or social events, as those are the kinds of things that you’re AFK, and maybe you remember to log them when you get back or maybe you don’t. But if Calendar does it for you, no worries.

Apart from long-form entries, the log is intended as a memory aid, “When was the last time…?” (I changed the air filter. We had dinner with Faith and Rick. etc.)

I don’t need to replicate the data contained in apps better designed to contain that information, I just want to be able to get to it quickly. Presumably “Search” answers many of those questions, but I think a lot of that can be be more useful in a broader context of a personal timeline, which is what the log is intended to be.

But this has been very helpful, and has given me a new direction for making entries from other apps.

And don’t take my comments to say I think “you’re holding it wrong.” There are many ways to configure such a “log” document to suit each individual’s needs or purposes, and I’m sure they’re all different.

I think it’s remarkable that we have such a facility available to us, which rewards time spent learning Tinderbox.

Thanks again.

Thanks, Mark. I was going to reply that I’m not sure we require any action on his part at this time. I think Paul’s AppleScript answers much of the issue. And I hadn’t noticed that you can force the detection. I just tried it, and wow! Maybe I don’t even need a separate AppleScript for Mail.

So many ways to skin a cat! Which one is “best”? The tyranny of choice!

(Let me add that I am going to implement Paul’s AS solution, if for no other reason than the very worthwhile exercise of using AppleScript and hopefully learning something in the process.)

1 Like