I am hoping to create a single BTT button to insert a hyperlink into selected text within an MS Outlook email. The base URL used as part of the inserted hyperlink will be different depending on the first two letters of the user's selected text.
Has anyone done this or can point me in the right direction? I did spend some time trying to hunt down examples using AppleScript, but, I'm quite new to it and am struggling to find anything similar.
Examples below of how selected text will influence the base URL of the hyperlink on press of BTT button:
selected text = "AA111" inserts hyperlink for "search engine 1" into the original display text "AA111"
selected text = "BB222" inserts hyperlink for "search engine 2" into the original display text "BB222"
selected text = "CC333" inserts hyperlink for "search engine 3" into the original display text "CC333"
Surely you can manipulate an Outlook email directly via AppleScript - but I don't have it installed. But what always works is to change the selected text of the current application via the clipboard.
Here is a script that converts the selected text to a hyperlink and then replaces it with CMD + V.
Add the Action "Save selected text in "selected_text" variable" and than run this script:
tell application "BetterTouchTool"
set theText to get_string_variable "selected_text"
end tell
set theUrl to ""
if theText begins with "AA" then
set theUrl to "https://www.google.com/search?q=" & theText
else if theText begins with "BB" then
set theUrl to "https://www.bing.com/search?q=" & theText
else if theText begins with "CC" then
set theUrl to "https://duckduckgo.com/?q=" & theText
end if
if theText ≠ "" and theUrl ≠ "" then
set the clipboard to "<a href=\"" & theUrl & "\" target=\"_blank\">" & theText & "</a>"
set theHEX to do shell script "pbpaste | hexdump -ve '1/1 \"%.2x\"'"
if theHEX ≠ "" then
run script "set the clipboard to «data HTML" & theHEX & "»"
tell application "System Events" to keystroke "v" using command down
end if
end if
Once again, this is such a great help, thanks @Dirk. This approach is even better than I was hoping for as it works across applications (tested in Outlook, Word, PowerPoint).
Would you have any tips on how to approach this with text in an Excel cell and/or a Slack message? Those apps both accept paste of rich text with hyperlink, however, currently they don't seem to accept the script actions.
The problem with Excel is not RTF. Excel does not accept markdown or HTML as input for links in cells. In addition, some functions are blocked if you have selected some text.
Here is a script which sends the links in markdown or HTML syntax as text and also as RTF.
Maybe this helps with Slack or other applications.
tell application "BetterTouchTool"
set theText to get_string_variable "selected_text"
end tell
set theUrl to ""
if theText begins with "AA" then
set theUrl to "https://www.google.com/search?q=" & theText
else if theText begins with "BB" then
set theUrl to "https://www.bing.com/search?q=" & theText
else if theText begins with "CC" then
set theUrl to "https://duckduckgo.com/?q=" & theText
end if
if theText ≠ "" and theUrl ≠ "" then
-- copy as Markdown-Link
Pasteboard's copyMarkdownLinktoClipboard(theText, theUrl)
-- or copy as HTML-Link
--Pasteboard's copyHTMLtoClipboard("<a href=\"" & theUrl & "\" target=\"_blank\">" & theText & "</a>")
-- paste to current application
tell application "System Events" to keystroke "v" using command down
end if
script Pasteboard
use framework "Foundation"
use framework "AppKit"
property NSUTF8StringEncoding : a reference to 4
property NSString : a reference to current application's NSString
property NSRTFTextDocumentType : a reference to current application's NSRTFTextDocumentType
property NSPasteboardTypeRTF : a reference to current application's NSPasteboardTypeRTF
property NSPasteboardTypeString : a reference to current application's NSPasteboardTypeString
property NSDictionary : a reference to current application's NSDictionary
property NSAttributedString : a reference to current application's NSAttributedString
property NSLinkAttributeName : a reference to current application's NSLinkAttributeName
property NSSingleUnderlineStyle : a reference to 1
property NSColor : a reference to current application's NSColor
property NSUnderlineStyleAttributeName : a reference to current application's NSUnderlineStyleAttributeName
property NSForegroundColorAttributeName : a reference to current application's NSForegroundColorAttributeName
property NSMutableAttributedString : a reference to current application's NSMutableAttributedString
property |NSURL| : a reference to current application's |NSURL|
on copyMarkdownLinktoClipboard(linkTextStr, urlStr)
set mdLinkStr to "[" & linkTextStr & "](" & urlStr & ")"
set linkURL to |NSURL|'s URLWithString:urlStr
-- define attributes to apply
set theAtts to NSDictionary's dictionaryWithObjects:{linkURL, NSColor's blueColor(), NSSingleUnderlineStyle} forKeys:{NSLinkAttributeName, NSForegroundColorAttributeName, NSUnderlineStyleAttributeName}
-- make attributed string
set attString to NSMutableAttributedString's alloc()'s initWithString:linkTextStr attributes:theAtts
-- need it in RTF data form for clipboard
set rtfData to attString's RTFFromRange:{0, attString's |length|()} documentAttributes:{DocumentType:NSRTFTextDocumentType}
set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
pb's clearContents()
-- set both types for the first object on the clipboard
pb's setData:rtfData forType:NSPasteboardTypeRTF
pb's setString:mdLinkStr forType:NSPasteboardTypeString
end copyMarkdownLinktoClipboard
on copyHTMLtoClipboard(someHTML)
-- convert to data
set htmlString to NSString's stringWithString:someHTML
set htmlData to htmlString's dataUsingEncoding:NSUTF8StringEncoding
-- make attributed string
set attString to NSAttributedString's alloc()'s initWithHTML:htmlData documentAttributes:(missing value)
-- need it in RTF data form for clipboard
set rtfData to attString's RTFFromRange:{0, attString's |length|()} documentAttributes:{DocumentType:NSRTFTextDocumentType}
set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
pb's clearContents()
-- set both types for the first object on the clipboard
pb's setData:rtfData forType:NSPasteboardTypeRTF
pb's setString:someHTML forType:NSPasteboardTypeString
end copyHTMLtoClipboard
end script
@Dirk, you are amazing! Thanks so much for your help. It will take me some time to digest and try and more deeply understand the script, but it works in both Excel and Slack, as well as Outlook now.
I would love to be able to add two elements to this:
Have method to add the link in BB code type format for a web form
Add an additional "else if" line to account for scenario where the selected text begins with "Word AA111" would translate to a separate URL and remove the "Word " from "theText" (e.g. the resulting URL for this scenario should be "https://www.example.com/search?q=AA111")
I'm starting to feel I'm asking a bit too much from community post and wonder if I could hire services from someone in the BTT community, like yourself, to help with some additions to the functions and possibly some more scripts for use as BTT buttons! I hope it's not against the community rules to suggest this!
In any case, thanks so much for your help, I already have the BTT buttons set-up with the two scripts and they are already so useful!
I don't know the "BB code type format" and can't help you with that, but with the last one you can push any HTML into the clipboard.
Regarding splitting and composing text, there are many AppleScript examples. Here you would have to try to find out the correct display text and the URL yourself. Then you can either pass these to the first function (as theText and theUrl) or the second one as theHTMLText.
Finally you have to send the clipboard to the current application:
tell application "System Events" to keystroke "v" using command down
With regard to the splitting of text, essentially I would like to add the option to find the below scenarios:
A. "Word AA111" identifies with "wordexample.com/search?q=AA111", so that the URL association with "Word AA" is a different web domain, however, everything from start of the text string, up to and including the space are removed from the resulting URL.
B. "Check BB222" identifies with "checkexample.com(forward slash)search?q=BB222", so that the URL association with "Check BB" is again a different web domain with everything from the start of the start of the text string, up to and including the space are removed from the resulting URL.
I'm really out of my depth here as I'm not quite sure how/where to add the above scenarios to the existing script and/or if it would be more wise to create separate scripts/buttons for these.
tell application "BetterTouchTool"
set theText to get_string_variable "selected_text"
end tell
set theUrl to ""
if theText begins with "AA" then
set theUrl to "https://www.google.com/search?q=" & Pasteboard's urlEncode(theText)
else if theText begins with "BB" then
set theUrl to "https://www.bing.com/search?q=" & Pasteboard's urlEncode(theText)
else if theText begins with "CC" then
set theUrl to "https://duckduckgo.com/?q=" & Pasteboard's urlEncode(theText)
else if theText begins with "Word AA" then
set theUrl to "https://wordexample.com/list/browse?q=" & Pasteboard's urlEncode(Pasteboard's getSubstringFromCharacter(theText, " "))
else if theText begins with "Check BB" then
set theUrl to "https://checkexample.com/search?q=" & Pasteboard's urlEncode(Pasteboard's getSubstringFromCharacter(theText, " "))
end if
if theText ≠ "" and theUrl ≠ "" then
-- copy as Markdown-Link
Pasteboard's copyMarkdownLinktoClipboard(theText, theUrl)
-- or copy as HTML-Link
--Pasteboard's copyHTMLtoClipboard("<a href=\"" & theUrl & "\" target=\"_blank\">" & theText & "</a>")
-- paste to current application
tell application "System Events" to keystroke "v" using command down
end if
script Pasteboard
use framework "Foundation"
use framework "AppKit"
property NSUTF8StringEncoding : a reference to 4
property NSString : a reference to current application's NSString
property NSRTFTextDocumentType : a reference to current application's NSRTFTextDocumentType
property NSPasteboardTypeRTF : a reference to current application's NSPasteboardTypeRTF
property NSPasteboardTypeString : a reference to current application's NSPasteboardTypeString
property NSDictionary : a reference to current application's NSDictionary
property NSAttributedString : a reference to current application's NSAttributedString
property NSLinkAttributeName : a reference to current application's NSLinkAttributeName
property NSSingleUnderlineStyle : a reference to 1
property NSColor : a reference to current application's NSColor
property NSUnderlineStyleAttributeName : a reference to current application's NSUnderlineStyleAttributeName
property NSForegroundColorAttributeName : a reference to current application's NSForegroundColorAttributeName
property NSMutableAttributedString : a reference to current application's NSMutableAttributedString
property |NSURL| : a reference to current application's |NSURL|
on copyMarkdownLinktoClipboard(linkTextStr, urlStr)
set mdLinkStr to "[" & linkTextStr & "](" & urlStr & ")"
set linkURL to |NSURL|'s URLWithString:urlStr
-- define attributes to apply
set theAtts to NSDictionary's dictionaryWithObjects:{linkURL, NSColor's blueColor(), NSSingleUnderlineStyle} forKeys:{NSLinkAttributeName, NSForegroundColorAttributeName, NSUnderlineStyleAttributeName}
-- make attributed string
set attString to NSMutableAttributedString's alloc()'s initWithString:linkTextStr attributes:theAtts
-- need it in RTF data form for clipboard
set rtfData to attString's RTFFromRange:{0, attString's |length|()} documentAttributes:{DocumentType:NSRTFTextDocumentType}
set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
pb's clearContents()
-- set both types for the first object on the clipboard
pb's setData:rtfData forType:NSPasteboardTypeRTF
pb's setString:mdLinkStr forType:NSPasteboardTypeString
end copyMarkdownLinktoClipboard
on copyHTMLtoClipboard(someHTML)
-- convert to data
set htmlString to NSString's stringWithString:someHTML
set htmlData to htmlString's dataUsingEncoding:NSUTF8StringEncoding
-- make attributed string
set attString to NSAttributedString's alloc()'s initWithHTML:htmlData documentAttributes:(missing value)
-- need it in RTF data form for clipboard
set rtfData to attString's RTFFromRange:{0, attString's |length|()} documentAttributes:{DocumentType:NSRTFTextDocumentType}
set pb to current application's NSPasteboard's generalPasteboard() -- get pasteboard
pb's clearContents()
-- set both types for the first object on the clipboard
pb's setData:rtfData forType:NSPasteboardTypeRTF
pb's setString:someHTML forType:NSPasteboardTypeString
end copyHTMLtoClipboard
-- Helper
on urlEncode(input)
set rawUrl to NSString's stringWithString:input
set theEncodedURL to rawUrl's stringByAddingPercentEscapesUsingEncoding:(NSUTF8StringEncoding)
return theEncodedURL as Unicode text
end urlEncode
on getSubstringFromCharacter(sourceStr, char)
set sString to NSString's stringWithString:sourceStr
set rangeOf to sString's rangeOfString:char
return (sString's substringFromIndex:((rangeOf's location) + 1)) as text
end getSubstringFromCharacter
end script
You’re probably already aware, but in case you’re not, stringByAddingPercentEscapesUsingEncoding: has been deprecated for some time, so may not continue beyond the current version of MacOS.
This should be as text instead of as Unicode text.
I found that changing "Pasteboard's copyHTMLtoClipboard" still presented the output in webforms as:
[AA111](https://www.google.com/search?q=AA111)
Instead if I changed copyMarkdownLinktoClipboard mdLinkStr as mentioned above, I was able to configure the below desired format for the web forms I am working with, and hyperlinks still continue to work in outlook, slack & excel [code]<a href="https://www.google.com/search?q=AA111">AA111</a>[/code]
stringByAddingPercentEscapesUsingEncoding I tried a simple replace of this with stringByAddingPercentEncodingWithAllowedCharacters as apple developer site suggests this is now to be used, however, I couldn't get this to work.
I changed the return theEncodedURL as Unicode text to return theEncodedURL as text and all appears to be functioning.
It’s because you asked @Dirk in the earlier part of this thread for a markdown link. Markdown links have this form:
[%description%](%url%)
which will display the literal text given by %description% as a hyperlink pointing to the address given by %url%, when rendered by a Markdown-enabled editor, such as the one used in this forum.
Microsoft Outlook isn’t Markdown-aware. It only knows HTML and RTF.
However, this:
[code]%text%[/code]
is called BBCode, and is used by forums stuck in the late 1990s. This specific example tells the rendering software to display the literal text given by %text%, preserving whitespace, using a monospaced font. This is used most often for those wishing to display source code snippets, hence the BB tag code.
A BBCode-formatted URL is described like this, as far as I recall:
[url=%href%]%description%[/url]
that will display the literal text of %description% when rendered, and hyperlink it to the supplied ‘%href%` URL.
You have an amalgamation of HTML syntax inside BBCode syntax, which I’ll let you decide what the purpose of that is, but I’m pretty sure one of those isn’t doing anything useful.
Then you probably didn’t do it correctly. If I recall (I don’t have a computer, so I’m currently having to recall rather than test), this method requires that a valid NSCharacterSet class object be passed as the parameter. You can either declare a new instance of an NSCharacterSet class object, should you wish to have control over customising what the set contains, or, more easily and more wisely in this situation, use the predefined character set object that the Apple Developer website contains a list of named keys that refer to commonly used sets for purpose. It includes a load pertaining to encoding URL strings, which is a complicated situation we’re stuck with just because of how URLs evolved over time, and it’s not actually possible to encode an entire URL using a single homogeneous mapping function, so each component of a URL is usually encoded separately, and pieced together. You can safely encode everything from the start of the URL to the end of a named file including its extension with one character set, but query strings (everything from a question mark up to the first occurrence of a hash symbol if there is one) must be encoded with a different character set, because they, for instance, don’t need to encode a slash, whereas a URL path interprets a slash that separates domains from sub-domains and file names, etc. Likewise, paths can contain ampersands without encoding them, but query strings interpret ampersands as a delimiter for each parameter in the query string. There’s a ton of other differences, but you get the idea. The character sets will be named in obvious ways, like NSURLComponentQueryStringEncodedAllowedCharacterSet or something massively long and vaguely similar-ish.
It’s usually already accessible to any AppleScript that imports the Foundation or AppKit frameworks, by simply referencing current application’s NSStupidlyLongIdentifierForNamedConstant, which you can assign directly to a variable if you don’t want to type it more than once, or just insert that reference as and when you need it, which is fine to do because it’s a constant.