Applescript Jekyll assistant (pt 3)
In which we distinguish between availableCategories
and chosenCategories
and provide the user the ability to edit her list of Categories .
This follows on from Part 2
-- these two properties are immutable
property homeFolder : the POSIX path of (path to home folder)
property plistPath : the POSIX path of (homeFolder & ".makepost.plist")
(*
We keep three persistent settings in 'makepost.plist':
'chosenBlogPath' is the path to the folder where Jekyll expects blog posts to be.
This is typically the '_posts' subdirectory in the Jekyll project files.
'availableCategories' is a list of the user's Categories from which the user can choose
and which will appear in the frontmatter of the newly-to-be-created blog post's 'markdown'
'chosenScriptFilePath' is the path to where the user has stored 'makepost.py'
which is written to be used as a shell command for creating new Jekyll blog posts
*)
-- These 5 properties of our Script Object are mutable
-- persistent across runs
property chosenBlogPath : the POSIX path of homeFolder
property availableCategories : {"Blog", "Scripting"}
property chosenScriptFilePath : the POSIX path of (homeFolder & "bin/makepost.py")
-- not persistent across runs
property chosenTitle : "Untitled"
property chosenCategories : availableCategories
(*
Initialisation
-- -- -- -- --
The plist, and thus the three persistent settings above may not yet exist
in which case we have bootstrapped them with some sensible initial values.
Notes:
* AppleScript aliases have to refer to existing files
* POSIX files and paths need not refer to existing files or directories
* The AppleScript path of a POSIX path is "text"
*)
-- overwite our bootstrapped properties if the user already has a .plist
initialisePersistentSettings()
(*
Next, we ask the user
1. What the title of her blog is going to be;
and from this, we will derive the Jekyll-conformant file name for the post
2. Which Folder she uses for posts
in her Jekyll-conformant Folder structure
*)
-- overwite our chosenTitle and chosenBlogPath properties as the user chooses
manageTitleAndBlogpath()
(*
Ask the user to choose which blog categories the post is to be part of.
getCats() will deal with non-existent .blogcats
*)
set chosenCategories to chooseCategories()
-- DEBUG -- DEBUG -- DEBUG -- DEBUG -- DEBUG -- DEBUG -- DEBUG -- DEBUG --
log "chosenTitle: " & chosenTitle
log "chosenBlogPath: " & chosenBlogPath
log "chosenScriptFilePath: " & chosenScriptFilePath
repeat with n from 1 to the length of availableCategories
log "availableCategories (" & n & "): " & item n of availableCategories
end repeat
repeat with n from 1 to the length of chosenCategories
log "chosenCategories (" & n & "): " & item n of chosenCategories
end repeat
-- DEBUG -- DEBUG -- DEBUG -- DEBUG -- DEBUG -- DEBUG -- DEBUG -- DEBUG --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
(*
Handlers / subroutines
*)
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
to chooseCategories()
repeat
choose from list availableCategories with title "Choose Blog Categories" with prompt "Choose one or more Blog Categories" OK button name "Save" cancel button name "Edit" default items {"Blog"} with multiple selections allowed
if the result is not false then
return result
else
set availableCategories to editCats()
end if
end repeat
end chooseCategories
to editCats()
-- Ask the user to edit her blog categories
-- turn the list availableCategories into a comma-separated string for her to edit
set availableCatString to convertListToString(availableCategories, ",")
set {catButton, editedCategories} to {button returned, text returned} of (display dialog "Add and delete comma-separated values. Best not to have too many!" default answer availableCatString buttons {"Save", "Cancel"} default button 1 cancel button 2 with title "Edit your Categories")
-- AppleScript will exit if user presses the "Cancel" button
-- just in case we have a zero length "list"
if editedCategories is "" then set editedCategories to "Blog"
-- sanitise the new category "list" which is a string
-- make it a list
set editedCategoriesList to convertStringToList(editedCategories, ",")
-- remove any leading or trailing spaces of each list item
set trimmedEditedCategoriesList to trimItems(editedCategoriesList)
-- so we can set a default in the choose cats dialogue
if trimmedEditedCategoriesList does not contain "Blog" then
copy "Blog" to end of trimmedEditedCategoriesList
end if
-- write the newly-edited list of categories to the plist
putCats(trimmedEditedCategoriesList)
return trimmedEditedCategoriesList
end editCats
to convertListToString(theList, theDelimiter)
set AppleScript's text item delimiters to theDelimiter
set theString to theList as string
set AppleScript's text item delimiters to ""
return theString
end convertListToString
to convertStringToList(theText, theDelimiter) -- (String) as list
set AppleScript's text item delimiters to theDelimiter
set theListItems to every text item of theText
set AppleScript's text item delimiters to ""
return theListItems
end convertStringToList
to trimItems(inList)
set outList to {}
repeat with i from 1 to (count (items of inList))
copy trimText((item i of inList), " ", "both") to end of outList
log "outList: " & outList
end repeat
return outList
end trimItems
to trimText(theText, theCharactersToTrim, theTrimDirection)
set theTrimLength to length of theCharactersToTrim
if theTrimDirection is in {"beginning", "both"} then
repeat while theText begins with theCharactersToTrim
try
set theText to characters (theTrimLength + 1) thru -1 of theText as string
on error
-- text contains nothing but trim characters
return ""
end try
end repeat
end if
if theTrimDirection is in {"end", "both"} then
repeat while theText ends with theCharactersToTrim
try
set theText to characters 1 thru -(theTrimLength + 1) of theText as string
on error
-- text contains nothing but trim characters
return ""
end try
end repeat
end if
return theText
end trimText
to getCats()
tell application "System Events"
tell property list file plistPath
set availableCategories to value of property list item "catsList"
end tell
end tell
end getCats
to putCats(theCategoriesList)
tell application "System Events"
tell property list file plistPath
set value of property list item "catsList" to theCategoriesList
end tell
end tell
end putCats
to manageTitleAndBlogpath()
-- Reduce the length of the path for displaying as the legend in button 1
set pathClue to crypticPath(chosenBlogPath)
set chosenTitle to "Untitled"
-- We'll cycle the path-choosing, not forgetting the title-choosing each cycle, until user is happy with her choice
repeat
set {OKButton, chosenTitle} to {button returned, text returned} of (display dialog "Choose the Title of your new post" default answer chosenTitle with title "Makepost" buttons {pathClue, "Other"} default button 1)
if OKButton is pathClue then
-- stay with the blogpath that we read from user's settings file
exit repeat
else
chooseBlogPath()
copy crypticPath(chosenBlogPath) to pathClue
end if
end repeat
end manageTitleAndBlogpath
to chooseBlogPath()
-- User chooses her blog posts Folder
set chosenBlogPath to the POSIX path of (choose folder with prompt "Choose the path to your blog posts Folder" default location chosenBlogPath)
-- record chosenBlogPath in makepost's persistent settings
tell application "System Events"
tell property list file plistPath
set value of property list item "blogPath" to chosenBlogPath
end tell
end tell
end chooseBlogPath
on crypticPath(fullPath) -- (String) as String
set splitPath to splitText(fullPath, "/")
set lastBit to {}
copy item ((count of splitPath) - 2) of splitPath to end of lastBit
copy "/" to end of lastBit
copy item ((count of splitPath) - 1) of splitPath to end of lastBit
return ("Place in .../" & lastBit as text) & " ?"
end crypticPath
to splitText(theText, theDelimiter)
set AppleScript's text item delimiters to theDelimiter
set theTextItems to every text item of theText
set AppleScript's text item delimiters to ""
return theTextItems
end splitText
to initialisePersistentSettings()
if not FileExists(plistPath) then
-- create the plist with bootstrap settings now, and for recording the user's choices later
tell application "System Events"
-- Have a look at the 'Mac Automation Scripting Guide' for more on this 'tell' block
-- Create an empty property list dictionary item
set theParentDictionary to make new property list item with properties {kind:record}
-- Create a new property list file using the empty dictionary list item as contents
set thePropertyListFilePath to plistPath
set thePropertyListFile to make new property list file with properties {contents:theParentDictionary, name:thePropertyListFilePath}
tell property list items of thePropertyListFile
-- use bootstrapped settings of these properties
-- Add a list key for accessing the users' blog categories
make new property list item at end with properties {kind:list, name:"catsList", value:availableCategories}
-- Add a string key for accessing the path to the user's blog posts
make new property list item at end with properties {kind:string, name:"blogPath", value:chosenBlogPath}
-- Add a string key for accessing the path to the python script 'makepost.py'
make new property list item at end with properties {kind:string, name:"scriptFilePath", value:chosenScriptFilePath}
end tell
end tell
else
-- overwrite the bootstrapped values of these persistent properties
tell application "System Events"
tell property list file plistPath
set chosenBlogPath to value of property list item "blogPath"
set availableCategories to value of property list item "catsList"
set chosenScriptFilePath to value of property list item "scriptFilePath"
end tell
end tell
end if
end initialisePersistentSettings
on FileExists(theFile) -- (String) as Boolean
-- Convert the file to a string
set theFile to theFile as string
tell application "System Events"
if exists file theFile then
return true
else
return false
end if
end tell
end FileExists