(*
Date created: 09/01/2019
Date last modified: 03/26/2020
*)
(*
IF YOU ARE NOT AN EXPERIENCED SCRIPTER OR DEVELOPER DO NOT MODIFY THIS SCRIPT!
*)
(*
The script was created in macOS ver. 10.13.6 "High Sierra";
The script has been confirmed to work properly and produce the intended result with the versions of OS X and macOS 10.9.0 and higher right up to the ver. 10.13.6 "High Sierra" included;
The script HAS NOT BEEN TESTED to work properly and produce the intended result with the versions of macOS 10.14.0 and newer;
The script assumes the versions of the application "Numbers" 3.0 and higher are installed on a Mac running OS X or macOS operating system of the version 10.9.0 and higher. It will not work with all the versions of the application "Numbers" prior to the version 3.0 (the application "Numbers" constituting "iWork '09" applications package).
*)
(* Warning: Font names must take the form of
PostScript font names only (refer to FontBook utility) else the script fails*)
(*INSTRUCTIONS FOR USE:
To use the script place it in the folder "~/Library/Scripts" of the library of your home folder. Then, run the utility "Script Editor" located in the folder "Utilities" of the folder "Applications". Open its preferences, go to the pane "General" and select the two checkboxes: "Show the scripts menu in the menu bar" and "Show this computer scripts". The scripts menu icon ("a manuscript scroll") appears in the menu bar. Run this script by clicking the icon and choosing "Sort events by month.scpt" from the dropdown.
*)
(*DESCRIPTION:
The script acquires selected calendar events, counts them based on the recurrence and puts the result in a workbook created with the application "Numbers" in the form of a table. It allows you to decide whether data will be written in the existing workbook or a new workbook will be created, you can also choose another year or calendar in the course of running the script. After looping for 4 unsuccessful attempts the script offers the ability to perform the search anew.
If a new workbook is created then a new sheet containing the table is created as well, otherwise, a new sheet is created only if deemed necessary by the script.
All the created "Numbers" documents are saved to the "Documents" folder.
*)
(*ISSUES:
The script's handling of recurring events is unsatisfactory it returning only an incomplete events cycle originating with the parent event. This is because of the Calendar's AppleScript implementation and to be addressed in the future versions.
*)
property theYear : (the year of (current date)) as text
property theMonth : missing value
set TestDate to (current date)
property Months4Table : {}
property EventMonthsInfo : {}
property DocName : ""
property DocNum : ""
property DocExtension : ""
property CalendarName : ""
property EventName : "Meeting"
property ChosenDocName : ""
property TheFullPath : ""
property FileCount : integer
property SelectedEventsbyName : {}
property CalendarIcon : (path to resource "App.icns" in bundle (((path to applications folder) as text) & "Calendar.app") as alias)
property AttemptsCount : 0
set theYear to ChooseTheDate(theYear)
set (year of TestDate) to theYear
class of TestDate is date --the date entered correctly
tell application "Calendar"
activate
set AllCalendars to get name of every calendar
delay 0.5
repeat
set CalendarName to (choose from list AllCalendars with title "Calendars of all accounts." with prompt "Select a calendar." default items {(item 1 of AllCalendars)} cancel button name "Cancel" without multiple selections allowed) as text
if result is not "false" then
set TheTargetCalendar to (get calendar named CalendarName)
else
error number -128
end if
set EventName to (text returned of (display dialog "Enter a name of the event." default answer EventName buttons {"Cancel", "OK"} default button 2 cancel button 1 with icon CalendarIcon)) --the events in question
set SelectedEventsbyName to get every event of TheTargetCalendar whose summary contains EventName
if SelectedEventsbyName is {} then --failed to find in the calendar. Prompt to pick any other legit calendar
set AttemptsCount to AttemptsCount + 1 #Failed attempt 1
set DialogMessage to display dialog "No events with the name " & quote & EventName & quote & " found in the calendar " & quote & CalendarName & quote & " for " & theYear & return & "Would you like to try with another calendar? The year is unchanged." buttons {"Cancel", "Another calendar"} with title "Choose another calendar" default button 2 cancel button 1 with icon CalendarIcon
if button returned of DialogMessage is "Another calendar" then set SelectedEventsbyName to my SelectAndFindAgain(CalendarName, AllCalendars) #Failed attempt 2 inside the handler
if SelectedEventsbyName is theYear then
set SelectedEventsbyName to ChooseEvent(AllCalendars, EventName) of me
end if
end if
set SelectedEventsbyYear to IdentifyEvents(SelectedEventsbyName, theYear) of me
if SelectedEventsbyYear is {} then --found in the calendar but not in the year
set AttemptsCount to AttemptsCount + 1 #Failed attempt 3
set PromptA to display dialog "No events with the name " & quote & EventName & quote & " found in " & theYear & " for the calendar " & quote & CalendarName & quote & "." & return & "Would you like to choose another year?" & return & "The calendar remains the one you have selected." buttons {"Cancel", "Another year"} with title "Choose another year" default button 2 cancel button 1 with icon CalendarIcon
if button returned of PromptA is "Another year" then
set theYear to my ChooseTheDate(theYear)
set SelectedEventsbyYear to IdentifyEvents(SelectedEventsbyName, theYear) of me
end if
end if
# Need to loop anew from the beginning, starting all over again.
if SelectedEventsbyYear is {} then
set AttemptsCount to AttemptsCount + 1 #Failed attempt 4
display dialog ((AttemptsCount as string) & " failed attempts. No events with the name " & quote & EventName & quote & " found in the calendar " & quote & CalendarName & quote & " for " & theYear & return & "Would you like to perform another search?") buttons {"Cancel", "Another search"} with title "Search again" default button 2 cancel button 1 with icon CalendarIcon
else
exit repeat
end if
set AttemptsCount to 1
end repeat
set EventMonths to {}
repeat with anEvent in SelectedEventsbyYear
set theStartDate to (start date of contents of anEvent)
set Month2Get to month of theStartDate
set end of EventMonths to (Month2Get as text)
end repeat
set EventMonthsInfo to {} --list of records
set MonthRecord to missing value --this is a initial value because the very 1st processed object will be unique.
repeat with aMonth in EventMonths
set CurrentMonth to contents of aMonth
set MonthRecord to missing value --else it will persistently retain the last value
repeat with aRec in EventMonthsInfo
if CurrentMonth = theMonth of contents of aRec then
set MonthRecord to contents of aRec
exit repeat
end if
end repeat
if MonthRecord is missing value then
set MonthRecord to {theMonth:CurrentMonth, MonthCount:1}
set end of EventMonthsInfo to MonthRecord
else
set MonthCount of MonthRecord to (MonthCount of MonthRecord) + 1
end if
end repeat
quit
end tell
display dialog (((count SelectedEventsbyYear) as text) & " events in " & theYear & " were found. ") buttons {"OK"} default button 1 giving up after 4 with icon CalendarIcon
set Months4Table to {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
tell application "Finder"
set NumbersIcon to (path to resource "AppIcon.icns" in bundle (((path to applications folder) as text) & "Numbers.app") as alias)
set DocName to "Events-Record"
set DocNum to ""
set DocExtension to ".numbers"
set TheFullPath to ((path to documents folder from user domain) as text) & (DocName & DocNum & DocExtension)
set TargetFiles to (every document file of folder "Documents" of home whose name begins with DocName)
set FileCount to (count TargetFiles)
if FileCount = 0 then
tell application "Finder" to make new document file with properties {name:DocName & DocExtension} at folder "Documents" of home
tell application "Numbers"
activate
delay 0.5
tell (make new document with properties {name:DocName & DocExtension})
tell (make new sheet with properties {name:"Selected Events" & "–1"})
tell (make new table with properties {name:(EventName & space & "❨" & theYear & "❩"), column count:2, row count:12, header row count:0})
set format of every cell to text
set {every column's width, every row's height} to {110, 36, 8.949198753E+9}
repeat with i from 1 to (count Months4Table)
tell row i
set value of cell 1 to item i of Months4Table
set {alignment of cell 1, vertical alignment of cell 1} to {center, center}
set background color of cell 1 to {65535, 42148, 23130}
set font name of cell 1 to "Futura-Bold"
set font size of cell 1 to 16
set text color of cell 1 to {65535, 65535, 65535}
set CellValue to formatted value of cell 1
repeat with aRec in EventMonthsInfo
if CellValue is theMonth of contents of aRec then set value of cell 2 to MonthCount of contents of aRec
end repeat
if value of cell 2 is in {"", missing value} then set value of cell 2 to "–"
set {alignment of cell 2, vertical alignment of cell 2} to {center, center}
set background color of cell 2 to {32639, 49344, 64250}
set font name of cell 2 to "Futura-MediumItalic"
set font size of cell 2 to 16
set text color of cell 2 to {65535, 65535, 65535}
end tell
end repeat
end tell
delete (every table whose name does not start with EventName)
end tell
delete (every sheet whose name does not start with "Selected Events") --deletes the default sheet usually named as "Sheet 1".
close saving in file TheFullPath
end tell
end tell
else
set TargetFilesNames to name of every document file of folder "Documents" of home whose name begins with DocName
set FileCount to (my OrderbyIndex(TargetFilesNames)) + 1
set Ref2Alises to TargetFiles as alias list
set DocNum to FileCount as text --for creating new documents only!
display dialog "Similar documents were found." & return & "Would you like to create a new document or add a table to a sheet in the existing document?" with title "Choose between document or sheet" with icon NumbersIcon buttons {"Cancel", "New document", "Add to the existing"} default button 3 cancel button 1
if button returned of result is "Add to the existing" then
set ChosenDocName to (choose from list TargetFilesNames with title "Select a file" with prompt "Select a workbook from the following workbooks" cancel button name "Cancel") as text
if result is not "false" then
repeat with anAlias in Ref2Alises
if ((contents of anAlias) as text) ends with ChosenDocName then
set TheFullPath to (contents of anAlias) as text
tell application "Numbers"
open file TheFullPath
tell document named ChosenDocName
set N to (count (every sheet))
repeat with i from 1 to N
if N = 1 then
set j to i
else
set j to N
end if
tell sheet j
set M to count (every table) --the tables that already present on opening the document
set IdenticalTableNames to (every table whose name begins with EventName and name ends with ("❨" & theYear & "❩"))
if IdenticalTableNames is not {} then set EventName to EventName & "-" & ((count IdenticalTableNames) + 1)
if M < 4 then
tell (make new table with properties {name:EventName & space & "❨" & theYear & "❩", column count:2, row count:12, header row count:0})
set format of every cell to text
set {every column's width, every row's height} to {110, 36, 8.949198753E+9}
repeat with i from 1 to (count Months4Table)
tell row i
set value of cell 1 to item i of Months4Table
set {alignment of cell 1, vertical alignment of cell 1} to {center, center}
set background color of cell 1 to {65535, 42148, 23130}
set font name of cell 1 to "Futura-Bold"
set font size of cell 1 to 16
set text color of cell 1 to {65535, 65535, 65535}
set CellValue to formatted value of cell 1
repeat with aRec in EventMonthsInfo
if CellValue is theMonth of contents of aRec then set value of cell 2 to MonthCount of contents of aRec
end repeat
if value of cell 2 is in {"", missing value} then set value of cell 2 to "–"
set {alignment of cell 2, vertical alignment of cell 2} to {center, center}
set background color of cell 2 to {32639, 49344, 64250}
set font name of cell 2 to "Futura-MediumItalic"
set font size of cell 2 to 16
set text color of cell 2 to {65535, 65535, 65535}
end tell
end repeat
end tell
exit repeat
else if M = 4 then -- if 4 tables in the sheet then a new sheet is created. The new table goes to the population of this sheet as the first resident.
tell me to MakeNewSheet()
exit repeat
end if
end tell
end repeat
close saving yes
end tell
end tell
exit repeat --no need to loop for the rest of the list
end if
end repeat
else
error number -128
end if
else
if button returned of result is not "Cancel" then
my MakeNewWorkbook()
end if
end if
end if
end tell
set theYear to "2019" -- at the end of the script
set AttemptsCount to 0
on SelectAndFindAgain(CalendarName, AllCalendars) --just events of the calendar in question regardless of a year.
set CalendarName to ""
tell application "Calendar"
set CalendarName to (choose from list AllCalendars with title "Calendars of all accounts." with prompt "Select a calendar to look the event " & quote & EventName & quote & " up." default items {(item 1 of AllCalendars)} cancel button name "Cancel" without multiple selections allowed) as text
if result is not "false" then
set TheTargetCalendar to (get calendar named CalendarName)
set SelectedEventsbyName to get every event of TheTargetCalendar whose summary contains EventName
if result is {} then
set AttemptsCount to AttemptsCount + 1
set PromptA to display dialog ("No events with the name " & quote & EventName & quote & " found in the calendar " & quote & CalendarName & quote & " for " & theYear & return & "Would you like to try with another calendar or year?") buttons {"Cancel", "Another year", "Another calendar"} with title "Another calendar or year" default button 3 cancel button 1 with icon CalendarIcon
if button returned of PromptA is not "Cancel" then
if button returned of PromptA is "Another calendar" then
set SelectedEventsbyName to ChooseEvent(AllCalendars, EventName) of me
else
set theYear to ChooseTheDate(theYear) of me
return theYear
end if
end if
end if
return SelectedEventsbyName
else
error number -128
end if
end tell
end SelectAndFindAgain
on ChooseTheDate(theYear)
repeat
set Prompt to display dialog "Enter the year as a YYYY digits format" buttons {"Cancel", "OK"} default button 2 cancel button 1 default answer theYear
if button returned of Prompt is not "Cancel" then set theYear to text returned of Prompt
if (count (characters of theYear)) = 4 then
try
repeat with anItem in (characters of theYear)
anItem as number
end repeat
exit repeat
on error
display alert "Invalid value. Try again." message "Only numbers are acceptable." buttons {"Cancel", "OK"} default button 2
if button returned of result is "Cancel" then return
end try
else
display alert "Invalid value." message "A year must contain 4 digits."
end if
end repeat
return theYear
end ChooseTheDate
on ChooseEvent(AllCalendars, EventName)
set SelectedEventsbyName to {}
tell application "Calendar"
set CalendarName to (choose from list AllCalendars with title "Calendars of all accounts." with prompt "Select a calendar to look the event " & quote & EventName & quote & " up for " & theYear & "." default items {(item 1 of AllCalendars)} cancel button name "Cancel" without multiple selections allowed) as text --perhaps, could be re-written into a separate handler
if result is not "false" then
set TheTargetCalendar to (get calendar named CalendarName)
set SelectedEventsbyName to get every event of TheTargetCalendar whose summary contains EventName
else
error number -128
end if
end tell
return SelectedEventsbyName
end ChooseEvent
on IdentifyEvents(SelectedEventsbyName, theYear)
set SelectedEventsbyYear to {}
tell application "Calendar"
repeat with anEvent in SelectedEventsbyName
set theStartDate to (start date of contents of anEvent)
set Year2Get to year of theStartDate
if Year2Get is (theYear as number) then set end of SelectedEventsbyYear to contents of anEvent
end repeat
end tell
return SelectedEventsbyYear
end IdentifyEvents
on MakeNewSheet()
tell application "Numbers"
tell document named ChosenDocName
set ExistingSheetCount to (count (every sheet)) --Existing sheets are being checked.
set NewSheetIndex to ExistingSheetCount + 1
tell (make new sheet with properties {name:"Selected Events" & "–" & (NewSheetIndex as text)})
delete (every table whose name does not start with EventName)
tell (make new table with properties {name:EventName & space & "❨" & theYear & "❩", column count:2, row count:12, header row count:0})
set format of every cell to text
set {every column's width, every row's height} to {110, 36, 8.949198753E+9}
repeat with i from 1 to (count Months4Table)
tell row i
set value of cell 1 to item i of Months4Table
set {alignment of cell 1, vertical alignment of cell 1} to {center, center}
set background color of cell 1 to {65535, 42148, 23130}
set font name of cell 1 to "Futura-Bold"
set font size of cell 1 to 16
set text color of cell 1 to {65535, 65535, 65535}
set CellValue to formatted value of cell 1
repeat with aRec in EventMonthsInfo
if CellValue is theMonth of contents of aRec then set value of cell 2 to MonthCount of contents of aRec
end repeat
if value of cell 2 is in {"", missing value} then set value of cell 2 to "–"
set {alignment of cell 2, vertical alignment of cell 2} to {center, center}
set background color of cell 2 to {32639, 49344, 64250}
set font name of cell 2 to "Futura-MediumItalic"
set font size of cell 2 to 16
set text color of cell 2 to {65535, 65535, 65535}
end tell
end repeat
end tell
end tell
end tell
end tell
end MakeNewSheet
on MakeNewWorkbook()
set DocNum to "–" & (FileCount as text)
set TheFullPath to (((path to documents folder) as text) & (DocName & DocNum & DocExtension))
tell application "Finder" to make new document file with properties {name:DocName & DocNum & DocExtension} at folder "Documents" of home
tell application "Numbers"
activate
delay 0.5
tell (make new document with properties {name:DocName & DocNum & DocExtension})
tell (make new sheet with properties {name:"Selected Events" & "–1"})
delete (every table whose name does not start with EventName)
tell (make new table with properties {name:EventName & space & "❨" & theYear & "❩", column count:2, row count:12, header row count:0})
set format of every cell to text
set {every column's width, every row's height} to {110, 36, 8.949198753E+9}
repeat with i from 1 to (count Months4Table)
tell row i
set value of cell 1 to item i of Months4Table
set {alignment of cell 1, vertical alignment of cell 1} to {center, center}
set background color of cell 1 to {65535, 42148, 23130}
set font name of cell 1 to "Futura-Bold"
set font size of cell 1 to 16
set text color of cell 1 to {65535, 65535, 65535}
set CellValue to formatted value of cell 1
repeat with aRec in EventMonthsInfo
if CellValue is theMonth of contents of aRec then set value of cell 2 to MonthCount of contents of aRec
end repeat
if value of cell 2 is in {"", missing value} then set value of cell 2 to "–"
set {alignment of cell 2, vertical alignment of cell 2} to {center, center}
set background color of cell 2 to {32639, 49344, 64250}
set font name of cell 2 to "Futura-MediumItalic"
set font size of cell 2 to 16
set text color of cell 2 to {65535, 65535, 65535}
end tell
end repeat
end tell
end tell
delete (every sheet whose name does not start with "Selected Events") --deletes the default sheet usually named as "Sheet 1"
close saving in file TheFullPath
end tell
end tell
end MakeNewWorkbook
on OrderbyIndex(TheNames)
set CheckPointList to {}
repeat with aName in TheNames
set aName to get contents of aName
set AppleScript's text item delimiters to ".numbers"
set TempItems to text items of aName
set AppleScript's text item delimiters to ""
set TempWord to TempItems as text
get the last character of TempWord
try
result as integer
set end of CheckPointList to the result
on error
set end of CheckPointList to missing value
end try
end repeat
set OnlyNum to every number of CheckPointList
(GetHighest out of OnlyNum) of me
end SortFileNames
to GetHighest out of OnlyNum
set TheCandidate to the first item of OnlyNum
repeat with aNum in the rest of OnlyNum
if TheCandidate < contents of aNum then set TheCandidate to contents of aNum
end repeat
return TheCandidate
end GetHighest
Model: MacBook Pro
AppleScript: 2.7
Browser: Safari 605.1.15
Operating System: macOS 10.13