I’ve been tooling around with SD Notary, Myriad Tables Lib, Dialog Toolkit Plus, accessory views and PrefsStorageLib lately. Today I decided to combine them all in one app, a modification of one I’ve been using for a while now.
This app will use the text in the clipboard in Safari to search one or more appleScript related pages (ASLG, SD Forums, MacScripter). The results appear in new tabs.
The app below is notarized.
The script below will run, but the icon that identifies it as a Safari search won’t show (it’s looking for it in an app or bundle’s resources).
AppleScript Safari Search.app.zip (2.1 MB)
use AppleScript version "2.4"
use scripting additions
use framework "Carbon"
use script "Myriad Tables Lib" version "1.0.12"
use script "Dialog Toolkit Plus" version "1.1.2"
use script "PrefsStorageLib" version "1.1.0"
property theAccessoryView : missing value
property theField : missing value
property lastpaletteTablePosition : {}
property initialSelection : {}
property lastSearch : "AppleScript Language Guide"
property firstRun : true
PersistentVariables()
if lastpaletteTablePosition is {} then
set {paletteTableX, paletteTableY} to {0, 0}
else
set {paletteTableX, paletteTableY} to lastpaletteTablePosition
end if
set tableDisplayData to {"AppleScript Language Guide", "ScriptDebugger Forums", "MacScripter", "Google", "ScriptDebugger Forums (Google)", "MacScripter (Google)"}
set tableTitle to "Safari Search"
set okName to "Search"
set cancelName to "Close"
set extraName to "Refresh"
set paletteTablePosition to {paletteTableX, paletteTableY}
set tableSettings to {tableDisplayData, tableTitle, okName, cancelName, extraName, paletteTablePosition}
repeat
set searchString to GetClipboard()
my BuildAccessoryView(searchString)
set {scriptList, searchString} to my DisplaySearchTable(tableSettings, searchString)
RunTheScript(scriptList, searchString)
end repeat
on DisplaySearchTable(tableSettings, searchString)
set {tableDisplayData, tableTitle, okName, cancelName, extraName, paletteTablePosition} to tableSettings
set tablePrompt to "Safari: Searching for “" & searchString & "”"
set myTable to make new table with data tableDisplayData ¬
with prompt tablePrompt ¬
with title tableTitle ¬
empty selection allowed true ¬
initially selected rows initialSelection ¬
multiple selections allowed true ¬
row template {"", missing value} ¬
with double click means OK
modify table myTable initial position paletteTablePosition ¬
OK button name okName ¬
accessory view theAccessoryView ¬
cancel button name cancelName ¬
extra button name extraName
tell me to activate
set tableResult to display table myTable ¬
with extended results
set whichButton to button number of tableResult
set userSelection to values selected of tableResult
set initialSelection to rows selected of tableResult
set lastpaletteTablePosition to final position of tableResult
set searchString to (theField's stringValue()) as text
set {paletteTableX, paletteTableY, paletteTableW, paletteTableH} to lastpaletteTablePosition
if paletteTableX < 1 then set paletteTableX to 0
if paletteTableY < 1 then set paletteTableY to 0
set lastpaletteTablePosition to {paletteTableX, paletteTableY}
set paletteTablePosition to lastpaletteTablePosition
set userSelection to values selected of tableResult
if userSelection is not {} and whichButton is not 2 then
StorePersistentValues()
return {the reverse of userSelection, searchString}
else
return {{}, searchString}
end if
end DisplaySearchTable
on RunTheScript(scriptList, searchString)
local scriptName
set searchStringPlus to words of searchString
set AppleScript's text item delimiters to {"+"}
set searchStringPlus to searchStringPlus as text
repeat with scriptName in scriptList
set scriptName to scriptName as text
set AppleScript's text item delimiters to {"\" \"", "\"", ", ", " "}
set quotedSearchString to text items of searchString
set quotedSearchString to {quote & quotedSearchString & quote} as text
set AppleScript's text item delimiters to {"\" \"\""}
set quotedSearchString to text items of quotedSearchString
set AppleScript's text item delimiters to {"\""}
set quotedSearchString to quotedSearchString as text
--{"ParseIMDBCast", "Search Google IMDB", "Search Google", "Search LATimes", ¬
--"Search Netflix", "Search Wiki"}
--https://www.google.com/search?client=safari&rls=en&q=Handler+site%3Adeveloper.apple.com%2Flibrary%2Farchive%2Fdocumentation%2FAppleScript%2FConceptual%2FAppleScriptLangGuide%2F&ie=UTF-8&oe=UTF-8
if scriptName is "Google" then
set searchPreString to "google.com/search?q="
set searchPostString to ""
set searchURL to searchPreString & quotedSearchString & searchPostString
tell application "Safari" to open location searchURL
else if scriptName is "AppleScript Language Guide" then
--
set searchPreString to "http://www.google.com/search?q="
set searchPostString to "+site:developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/"
set searchURL to searchPreString & quotedSearchString & searchPostString
tell application "Safari" to open location searchURL
else if scriptName is "MacScripter" then
--https://macscripter.net/search.php?action=search&keywords=text+item+delimiters
set searchPreString to "https://macscripter.net/search.php?action=search&keywords="
set searchPostString to "&author=&forum=-1&sort_by=5&sort_dir=DESC&show_as=topics&search=Submit:"
set searchURL to searchPreString & searchStringPlus & searchPostString
tell application "Safari" to open location searchURL
else if scriptName is "MacScripter (Google)" then
set searchPreString to "http://www.google.com/search?q="
set searchPostString to "+site:macscripter.net"
set searchURL to searchPreString & quotedSearchString & searchPostString
tell application "Safari" to open location searchURL
else if scriptName is "ScriptDebugger Forums" then
set AppleScript's text item delimiters to {"%20"}
set SDsearchString to words of searchString as text
-- text%20item%20delimiters
-- https://forum.latenightsw.com/search?expanded=true&q=text%20item%20delimiters
set searchPreString to "https://forum.latenightsw.com/search?expanded=false&q="
set searchPostString to ""
set searchURL to searchPreString & SDsearchString & searchPostString
tell application "Safari" to open location searchURL
else if scriptName is "ScriptDebugger Forums (Google)" then
set searchPreString to "http://www.google.com/search?q="
set searchPostString to "+site:forum.latenightsw.com"
set searchURL to searchPreString & quotedSearchString & searchPostString
tell application "Safari" to open location searchURL
end if
end repeat
tell application "Safari" to activate
tell me to activate
end RunTheScript
on PersistentVariables()
prepare storage for (path to me) default values {lastpaletteTablePosition:{}, initialSelection:{}, lastSearch:{}, firstRun:{}}
set my lastpaletteTablePosition to value for key "lastpaletteTablePosition"
set my initialSelection to value for key "initialSelection"
set my lastSearch to value for key "lastSearch"
set my firstRun to value for key "firstRun"
if firstRun = {} then set firstRun to false
end PersistentVariables
on StorePersistentValues()
assign value lastpaletteTablePosition to key "lastpaletteTablePosition"
assign value initialSelection to key "initialSelection"
assign value lastSearch to key "lastSearch"
assign value firstRun to key "firstRun"
end StorePersistentValues
on RetreiveStoredValues()
set my lastpaletteTablePosition to value for key "lastpaletteTablePosition"
set my initialSelection to value for key "initialSelection"
set my lastSearch to value for key "lastSearch"
set my firstRun to value for key "firstRun"
end RetreiveStoredValues
on GetClipboard()
try
set clipboardString to paragraph 1 of (the clipboard)
set clipboardString to trimText(clipboardString)
on error
set clipboardString to lastSearch
return clipboardString
end try
return clipboardString
end GetClipboard
on trimText(theString)
set thePattern to "(?m)^[ \\t]+|[ \\t]+$"
set theString to current application's NSString's stringWithString:theString
set theString to (theString's stringByReplacingOccurrencesOfString:thePattern withString:"" options:(current application's NSRegularExpressionSearch) range:{0, theString's |length|()})
return theString as text
end trimText
on BuildAccessoryView(displayString)
set accViewControls to {}
set AccViewLeft to 0
set AccViewBottom to 0
set AccViewWidth to 280
set AccViewTop to 250
set theBottom to AccViewBottom
set theLeft to AccViewLeft
set spacer to 20
--Label variables
set maxWidth to 280
set alignment to left aligned
-- alignments: left aligned, right aligned or center aligned
set wrapsBool to false
set controlSize to regular size
--control sizes:regular size, mini size, small size,large size
set boldType to true
set labelString to "Safari search:"
set LabelLeft to 0
--Field variables
set enteredText to displayString
set defaultText to displayString
set theWidth to maxWidth - 10
set extraHeight to spacer
set acceptsTabs to true
set fieldLeft to 45
--View variables
set myPath to POSIX path of (path to me)
set iconPath to myPath & "Contents/Resources/seachSafariIcon.jpg"
set posixPath to POSIX path of iconPath
set viewWidth to 40
set viewHeight to 40
set imageScale to scale to fit
--{scale down proportionally, scale to fit, scale none, scale proportionally}
set imageAlignment to bottom left aligned
--imageAlignments:center aligned, top aligned, top left aligned, top right aligned
----left aligned, bottom left aligned, bottom right aligned, right aligned, bottom aligned
set {theField, theTop} to create field enteredText ¬
placeholder text defaultText ¬
left inset fieldLeft ¬
bottom theBottom ¬
field width theWidth ¬
extra height extraHeight ¬
with accepts linebreak and tab
set the end of accViewControls to theField
set {theImage, viewTop} to create image view posixPath ¬
left inset theLeft ¬
bottom theBottom ¬
view width viewWidth ¬
view height viewHeight ¬
scale image imageScale ¬
align image imageAlignment
set theBottom to theTop
set {theLabel, theTop} to create label labelString ¬
left inset LabelLeft ¬
bottom theBottom ¬
max width maxWidth ¬
aligns alignment ¬
multiline wrapsBool ¬
control size controlSize ¬
bold type boldType
set the end of accViewControls to theLabel
set theBottom to theTop + spacer
set the end of accViewControls to theImage
set theTop to theTop - AccViewBottom
if theTop < AccViewTop then set AccViewTop to theTop
my buildAccessoryViewMainThread:{accViewControls, AccViewLeft, AccViewBottom, AccViewWidth, AccViewTop}
end BuildAccessoryView
on create label labelString left inset theLeft : 0 bottom theBottom max width maxWidth aligns alignment : left aligned multiline wrapsBool : true control size controlSize : regular size bold type boldType : false
if NSThread's isMainThread() as boolean then
my createLabelMainThread:{labelString, theLeft, theBottom, maxWidth, alignment, wrapsBool, controlSize, boldType}
else
my performSelectorOnMainThread:"createLabelMainThread:" withObject:{labelString, theLeft, theBottom, maxWidth, alignment, wrapsBool, controlSize, boldType} waitUntilDone:true
end if
return handlerResult
end create label
on create field enteredText placeholder text placeholder left inset theLeft : 0 bottom theBottom field width theWidth extra height extraHeight : 0 accepts linebreak and tab acceptsTabs : false
if NSThread's isMainThread() as boolean then
my createFieldMainThread:{enteredText, placeholder, theLeft, theBottom, theWidth, extraHeight, acceptsTabs}
else
my performSelectorOnMainThread:"createFieldMainThread:" withObject:{enteredText, placeholder, theLeft, theBottom, theWidth, extraHeight, acceptsTabs} waitUntilDone:true
end if
return handlerResult
end create field
on create image view posixPath left inset theLeft bottom theBottom view width viewWidth view height viewHeight scale image imageScale : scale down proportionally align image imageAlignment : center aligned
if NSThread's isMainThread() as boolean then
my createImageViewMainThread:{posixPath, theLeft, theBottom, viewWidth, viewHeight, imageScale, imageAlignment}
else
my performSelectorOnMainThread:"createImageViewMainThread:" withObject:{posixPath, theLeft, theBottom, viewWidth, viewHeight, imageScale, imageAlignment} waitUntilDone:true
end if
return handlerResult
end create image view
on buildAccessoryViewMainThread:theArg
set {accViewControls, theLeft, theBottom, theWidth, theTop} to theArg
set my theAccessoryView to current application's NSView's alloc()'s initWithFrame:{{theLeft, theBottom}, {theWidth, theTop - theBottom}}
repeat with aControl in accViewControls
(theAccessoryView's addSubview:aControl)
end repeat
end buildAccessoryViewMainThread: