For those of you who want to get the JXCirrusDiary entries to do more than just their basic functions, or want to save time adding a few new functions to the user interface, there is a scripting language. Scripting is usually used to do two things:
JXCirrusDiary does not have its own special scripting language... It uses JavaScript (which may cause any web programmers reading this to breathe a sight of relief).
JavaScript is the programming language used in vast numbers of websites around the world to do lots of the more funky complex sort of things, like display maps that you can zoom in on. JXCirrusDiary uses the WebKit JavaScript engine - WebKit is the same engine that is used in the Chrome and Safari browsers.
There are 3 ways to specify scripts that can be run. You can:
Here are a couple of examples...
This script, called "MoreImportant" bumps up the priority for a task.
priority = JXGet("Priority");
priority++;
JXSet("Priority",priority);
The JXGet function gets the priority value from the task. The "priority++" line adds one to the priority. The JXSet function pushes the priority value back into the task. For more on modifying entries, see Modifying Entries.
This script, called "StartFirst" gives the user another user interface function - It lets them complete the current task, go to the most important task, and start work on that (all in a single mouse click).
JXGuiCall( "Complete");
JXGuiCall( "GoFirstTask");
JXGuiCall( "StartSession");
This script uses the JXGuiCall function, which sends commands back to the user interface. For more, see Controlling the User Interface.
To add a a script to an entry, select Entry -> Edit. Once the Entry dialog appears, select the Scripts tab.
This page is split into 2 parts: The top part lists the scripts that you have added to this entry. The bottom part lists scripts that have been added to the Object Spec that this entry uses.
This list shows the name of the script, and the shortcut you can use to run each script.
- Lets you
add a new script. It will open the Script Edit Dialog, which lets
you type in the script.
-
Lets you edit a script that you have already created. It also
opens the Script Edit Dialog
also.
- Lets you delete a script that you no longer want.
Double-clicking on a script in the list also edits the script.
This list shows you the scripts that have been defined in the object spec that this object uses. If you were to change the spec, this list may change to show a different list of scripts.
You can double-click the entries in the list to show what the script contains - It will open the Script Edit Dialog. These scripts are defined in the Object Spec, so you will need to go to the DB Schema dialog/Object Spec dialog to edit them.
This dialog allows you to edit the actual script.
Name - Contains the name of the script. The names have a couple of restrictions:
Shortcut - Shortcuts are typically 1 or 2 keystrokes that you can use to run a script using the keyboard only. To run the script, you would press Shift-M, then the keys that you define here.
Some examples:
Script Text - This is where you type in the actual script details.
-
You can use this to check for
basic errors in your JavaScript. If you press it, and nothing
happens, then your script looks OK. If there is an error, the
error message will appear below the script text in a separate
field (which goes away when there are no errors in the
script).
OK - Finishes editing the script and saves the changes.
Cancel - Closes the window and discards any changes to the script.
Scripts can be added to the Object Specs for a whole class of objects in the database.
The script itself is just added as extra text at the bottom of the spec. For example:
$<Priority> = init("5");
@Script MoreUrgent @Shortcut U
>"
JXSet("Priority",Number(JXGet("Priority")+1));
"<;
The script is started after the "@Script
" keyword.
The name must appear next. If you want to use a shortcut for the
script, add "@Shortcut
" and then the shortcut
keystroke. @Shortcut
(and the key combination
afterwards) are optional. See shortcut in the Script
Edit Dialog section.
The script body appears between the >"
and the "<
;
When you add a script to an object spec, it will be available for any objects that use that spec. It will also be available for any object specs that inherit this one. One thing to note about inheritance: Lets say spec A defines a Blah script, and spec B inherits A. If B wants Blah to behave differently, then B can define its own Blah script. That will override the Blah script from spec A. This is very useful for triggers...
As well as having scripts that are attached to a JXCirrusDiary
entry, you can also have global scripts. These can be run from any
entry in the diary. To create or edit global scripts, use button then
Global Scripts. This will bring up a dialog that is identical to
the Scripts tab in the Script
Edit Dialog.
Any scripts that you add in there will be available from all records in the database.
The Pre-Defined Scripts section here list global scripts that have been defined in the Database Schema. To add scripts in there, go to the schema, and add the scripts to the TopLevel object spec. Any scripts added to that will be global.
There are 3 ways to run scripts:
If there is an error in a script, a notification message will appear at the top right telling you "Script errors in...". To go to the error, double click this message - It will take you to the script that has the error:
One of the main reasons for using scripts is to modify the values in an entry. To do this you will use:
JXGet("VARIABLE");
to get a value from an entry. For example:
score = JXGet("Score");
This will create a local script variable called "score" which contans the value from the Score field in the entry.
To get the values back into the entry, use
JXSet("VARIABLE",value);
For example:
JXSet("Priority",10);
will set the entry priority to 10.
Any variables that you define in the object spec for the entry will be able to be modified using JXGet and JXSet. The VARIABLE value will be the name of the value you have defined in the object spec (case sensitive).
The following table, list the standard system-defined variables for an entry.
Value | Meaning | Contents |
Id |
The ID number for the entry. |
|
Title | The title of the entry. | |
EntryType | What type of entry this is. | ToDo, Appointment, Journal, Object, Person, Household |
Start_Time | Start time for appointments and journals. | Date in text form (see Dates). |
End_Time | End time for appointments and journals. | Date in text form. |
Start_After | The start-after time for tasks. | Date in text form. |
Due_Date | The due date for tasks. | Date in text form. |
Repeating | Is this a repeating task. | 0 (if No), 1 (if Yes) |
Repeat_Start | The start-after date to repeat from. | Date in text form. |
Repeat_Due | The due date to repeat from. | Date in text form. |
Begin_Repeating | The date to begin the task repeating from. | Date in text form. |
Finish_Repeating | The date after which the task stops repeating. | Date in text form. |
Exclude_Repeating | A set of dates where the task will not repeat. | Date in text form. |
Duration | The expected duration of a task. | In the form HH:MM:SS. |
Remaining |
The remaining duration of a task (calculated
using duration and percentage complete). Read
only value. |
In the form HH:MM:SS |
Spent |
The total time spent on a task.
Read only value. |
In the form HH:MM:SS |
Complete | The completion percentage of a task. | 0-100. |
Priority | The priority of the task. | 0-300. |
Depend_Title | The title of another entry this depends on. | |
Prevent_Other_Depend | Prevent other tasks from depending on this | 0 (if No), 1 (if Yes). |
Prevent_Depend | Prevent this from depending on others. | 0 (if No), 1 (if Yes). |
Resource | The name of the resource assigned to this task. | |
TimeType | The time type we are using for this task. | |
Baseline_Duration | The baseline set for the task duration. | In the form HH:MM:SS. |
Baseline_Start | The baseline start time. | Date in text form. |
Baseline_End | The baseline end time. | Date in text form. |
Baseline_Progress | Are we tracking progressive baselines. | 0 (if No), 1 (if Yes). |
Auto_Baseline | Should we adjust the baseline automatically. | 0 (if No), 1 (if Yes). |
Command | Any commands to be executed. |
Whether these can all be set will depend on whether the variable is set to eval in the object spec. If it is set to eval, then there is no sense in trying to set it from a script, because it will just get overridden.
In addition to changing the variables, you can also change the object spec for an entry. Use:
JXSetSpec("SPEC");
SPEC is the new spec that you will use.
NOTE: You can only set the spec to something else that inherits off the same base object spec. If you don't understand what this is talking about, best avoid JXSetSpec for now.
The other big helpful thing that scripts can do is to send commands back to the user interface. This is done using:
JXGuiCall("FUNCTION");
FUNCTION is the function on the GUI that you want to call.
For example, you could go to the first task:
JXGuiCall("GoFirstTask");
Some GUI calls can take parameters.
JXGuiCall("Query","MyQuery");
IMPORTANT: When you call a GUI function, that function works on the diary entry that is selected in the GUI. For example, you could have a script that automatically starts the highest priority task.
JXGuiCall("GoFirstTask");
JXGuiCall("StartSession");
In this case, it wouldn't matter what entry you had selected - It
would always start the highest priority task. That is
because "GoFirstTask" changes the selected entry on the GUI.
This behaviour is different to JXGet and JXSet - They always
work with the entry that the macro is part of.
Here is a full list of the GUI functions you can access:
Function | Menu Equivalent | Meaning |
Edit | Entry -> Edit | Edit the selected item. |
EditEntry |
Entry -> EditEntry |
Edit the entry (even if a a time slot is
selected). |
EditID |
(no equivalent menu item) |
Edits an entry with a given ID. Should use ID
as a parameter 1 i.e: JXGuiCall("EditID",12345); |
Copy | Edit -> Copy | Copies the entry to the clipboard. |
CopyID |
(no equivalent menu item) |
Copies an entry with a given ID. Should use
ID as parameter 1 i.e. :JXGuiCall("CopyID",12345); |
Cut | Edit -> Cut | Cuts the entry and stores on the clipboard. |
CutID |
(no equivalent menu item) |
Cuts an entry with a given ID.
Should use ID as parameter 1 i.e. :JXGuiCall("CutID",12345); |
Paste | Edit -> Paste | Pastes the entry from the clipboard in the selection location. |
Paste-As | Edit -> Paste As | Pastes the entry from the clipboard and changes to a different type. |
Delete | Edit -> Delete | Deletes the selected entry. |
Complete | Entry -> Complete | Marks the task or appointment as complete. |
Compact |
Entry -> Compact |
Compacts the
entries from this one down the tree. |
Link |
Entry -> Link |
Links the entries so they depend on each other. |
Postpone | Entry -> Postpone | Pops up the dialog to allow the entry to be postponed. |
PostponeDay | Entry -> Postpone Day | Postpones the entry by one day. |
AdjComplete | Entry -> % Complete | Pops up the dialog to adjust the % completion for a task. |
BaselineHours | Entry -> Baseline Hours | Saves the baseline hours for a task. |
BaselineDate | Entry -> Baseline Hours Date | Saves the baseline hours, start and end date. |
AddEntry |
Edit -> Add |
Adds a new top level entry. |
AddTask |
Add -> Add Task |
Adds a new task. |
AddJournal |
Add -> Add Journal |
Adds a new journal entry. |
AddAppointment |
Add -> Add Event |
Adds a new event. |
AddPerson |
Add -> Add Person |
Adds a new person. |
AddAddress |
Add -> Add Address |
Adds a new address. |
AddPlace |
Add -> Add Place |
Adds a new place. |
Note |
Add -> Add Note |
Adds a new quick note. Parameter 1 - The text of the note. |
CreateChild | Entry -> Create Child | Creates a child of the current entry. |
CreateSibling | Entry -> Create Sibling | Creates a sibling of the current entry. |
StartSession | Entry -> Start Session | Starts a session for the selected entry. |
StopSession | Entry -> Stop Session | Stops the running session. |
CompleteSession | Entry -> Complete Session | Mark the running session task/appointment as complete. |
AddSession |
Similar to timesheet function |
Adds an entry to the time spent for a task
for that person. Parameter 1 - The day of the session (i.e. "Today", "Yesterday", "1-Mar-2013" ). If you specify a time, then the session will be recorded for exactly that time (i.e. "Yesterday 1:00PM"). Parameter 2 - The duration of the session (i.e. "1:00", "0:30" ). Parameter 3 - The name of the resource doing the work. |
ClearSession |
Similar to timesheet function. | Clears all time spent entries for a task for
a day. Parameter 1 - The day of the session (i.e. "Today", "Yesterday", "1-Mar-2013" ). Parameter 2 - The name of the resource doing the work. |
RepeatInstance |
Entry -> Repeat to Instance |
Converts a single instance of a repeating
task or event to an actual task/event. |
Plan | Planning -> Plan Time | Starts the dialog to plan time for an entry. |
MovePlanUp | Planning -> Move Plan Up | Moves the selected plan earlier in the day. |
MovePlanDown | Planning -> Move Plan Down | Moves the selected plan later in the day. |
LockSession | Planning -> Lock Session | Turns a selected session into a plan. |
LockTaskDay | Planning -> Lock Task For Day | Turns all sessions for a task into plans just for the current day. |
LockTaskAll | Planning -> Lock Task All | Turns all sessions for a task into plans. |
LockDay | Planning -> Lock Everything for Day | Locks all sessions as plans for today (for all tasks). |
LockAll | Planning -> Lock Everything | Locks all sessions in the diary. |
UnlockTaskDay | Planning -> Unlock Task For Day | Removes all plans for a task for today only. |
UnlockTaskAll | Planning -> Unlock Task All | Removes all plans for a task. |
UnlockDay | Planning -> Unlock Everything for Day | Removes all plans for today. |
UnlockAll | Planning -> Unlock Everything | Removes all plans. |
CommandRun | Entry -> Command Run | Runs the selected command. |
CommandRunAll | Entry -> Command Run All | Runs all commands for the entry. |
CommandSkip | Entry -> Command Skip | Skips the selected command. |
CommandClear | Entry -> Command Clear | Marks the selected command as not run. |
CalNextDay | Calendar -> Next Day | Moves the calendar to the next day. |
CalLastDay | Calendar -> Previous Day | Moves the calendar to the previous day. |
CalNextWeek | Calendar -> Next Week | Moves the calendar to the next week. |
CalLastWeek | Calendar -> Previous Week | Moves the calendar to the previous week. |
CalNextMonth | Calendar -> Next Month | Moves the calendar to the next month. |
CalLastMonth | Calendar -> Previous Month | Moves the calendar to the previous month. |
CalNextYear | Calendar -> Next Year | Moves the calendar to the next year. |
CalLastYear | Calendar -> Previous Year | Moves the calendar to the previous year. |
CalToday | Calendar -> Today | Moves the calendar to today. |
CalGoDate | Calendar -> Go To Date | Pops up a dialog to prompt to go to a specific date. |
GoSession | Go -> Current Session | Goes to the task that has a session. |
GoFirstTask | Go -> First Task | Goes to the highest priority task. |
GoNextTask | Go -> Next Task | Goes to the next task (in priority order). |
GoLastTask | Go -> Previous Task | Goes to the previous task (in priority order). |
GoFirstPlan | Go -> First Plan | Goes to the earliest planned session. |
GoNextPlan | Go -> Next Plan | Goes to the next plan (in chronological order). |
GoLastPlan | Go -> Previous Plan | Goes to the previous plan. |
GoID |
(no equivalent menu item) |
Select an entry with a given ID.
Should use ID as parameter 1 i.e. :JXGuiCall("GoID",12345) |
Refresh | View -> Refresh | Refreshes the current display. |
Find | Edit -> Find | Finds a given piece of text. You can supply the text to search for as parameter 1. |
Recalculate | View -> Recalculate | Performs a full recalculate, including all sessions. |
CloseTab | View -> Close Tab | Closes the current tab (if it is a query or timesheet). |
Collapse | View -> Collapse Tree | Collapses the entire tree. |
Expand |
View -> Expand Tree |
Expands the full tree below the selected
item. |
TreeView | View -> Tree | Switch to the tree view. |
PlanView |
View -> Plan |
Switch to the plan view. |
DayView | View -> Day | Switch to the day view. |
WeekView | View -> Week | Switch to the week view. |
MonthView | View -> Month | Switch to the month view. |
SummaryView | View -> Summary | Switch to the summary view. |
PlanningView |
View -> Planning |
Switch to the planning view. |
ProjectView |
View -> Project |
Switch to the project view. |
FocusView |
View -> Focus |
Switch to the focus view. |
TimesheetView |
Tools -> Timesheet |
Open the Timesheet view (or switch to it if
it is already open). |
Query | Query | Run a query and display the results. Should use query name as parameter 1, ("Query", "QueryName"). If there are extra values, supply them as parameters 2, 3 and 4. |
ExportTree |
File -> Export -> Tree |
Exports the tree view to a CSV
file. Parameter 1 is the name of the file to
export to. Parameter 2 is the maximum depth in the
tree to export (0 = All levels). |
ExportQuery |
File -> Export -> Query |
Exports the current query to a CSV
file. Parameter 1 is the name of the file export
to. |
Import |
File -> Import -> Tasks |
Imports CSV
data from a named template. The template name should
be the same as a saved import template. If no
name is specified, then it will just open the Import Tasks
dialog. |
JXCirrus' scripting provides a several ways to prompt the user to
enter values:
The following example prompts the user to update their name.
var name = JXGet("Name");
name = JXPromptText("Enter your name...",name);
JXSet("Name", name);
JXPromptText takes 2 parameters:
Another popup dialog type gives the user a list of values they
can choose from a dropdown.
JXPromptChoice takes 4 parameters:var animal = JXPromptChoice( "Select an animal...", "Tiger,Lion,Zebra,Salamander", "Lion", true );
Another related prompt dialog is able to prompt based on values
that are already in the database.
var person = JXPromptDB( "Select a co-worker...", "Worker", "Name" );
What the example above will do is pop up a dialog where the user
can choose values from a drop-down list. The values
come from the "Worker" object spec,
and the "Name" variable.
JXPromptDB takes 5 parameters:
There are 2 special cases that you can use for this dialog - If
the object spec name is set to "SYSTEM":
It is possible to search for values within the database using simple pattern matching. Here is an example:
var pattern = JXPrompt("Search for","");
var results = new Array();
results = JXSearchDB( "Task", "Title", pattern );
This lets the user search for whatever was entered into the
"pattern" variable. It will search in objects with
object spec "Task" and in the "Title" variable.
The parameters for JXSearchDB are:
Trigger scripts are scripts that are run automatically when some event happens in the system, such as completing a task.
In this example, lets say we want a repeating task that happens less frequently each time you run it. In the object spec, we have a variable called "Frequency" which defines how many days till the task runs again. It might look something like this:
$<Frequency> = init("1");
$<Repeat_Start> = eval("+$<Frequency> days 9AM");
$<Repeat_Due> = eval("+$<Frequency> days 5PM");
Now, we can adjust frequency each time the task is complete.
@Script on_complete
>"
freq = JXGet("Frequency");
freq++;
JXSet("Frequency",freq);
"<;
Trigger scripts always start with "on_" - If you start a script with "on_" it will NOT appear in the list of scripts or on the toolbar, and shortcut keys will have no effect. This is because these are tied to other things that happen in the system...
Trigger | Called |
on_start | When a session is started for the entry. |
on_stop | When a session is stopped for the entry. |
on_complete | When a task or appointment is marked as complete. |
on_create | When an entry is created. |
on_edit | Called after an entry has been edited. This is useful if you have some value in your entry that needs to be automatic, but you don't need it to slow down the system by being recalculated all the time. |
on_recalculate | Called when the user triggers a full recalculate on the system. This will NOT happen during a background recalculate. Useful if you want to do a one-off change to a whole lot of entries. |
on_startup |
Called when the application first starts
up. This is not called at any other time. |
It is possible for one script to call another script in the same object, or elsewhere in the diary.
JXCallSelf("Script");
This calls a script in the same object. For example, this calls the "LessFrequent" script:
JXCallSelf("LessFrequent");
JXCallParent("Script");
This calls a named script in the parent object of this one.
JXCallChild("Script","ChildName",ALL);
This calls a named script on a given child.
For example, if we had in the object spec:
$[Task] = ${MyTask}[];
and MyTask has a script called DoIt, we could use:
JXCallChild("DoIt","Task",1);
This will call DoIt for all of the children in the "Task" group.
If we only wanted to call DoIt for the first one, then we would use
JXCallChild("DoIt","Task",0);
JXCallAll( "Script", ALL );
JXCallAll("Script",ALL);
This just searches through the whole diary and runs any scripts
that have than name. If ALL is 1, then it runs all of that script.
If ALL is 0, then it will stop after it finds the first one. ALL
means call for all children..
JXCallID( "Script", id );
This calls a script on an object with a specific ID.
var results = new Array();
results = JXSearchDB("Task","Title","Sleep");
for( int i = 0; i < results.length; i++ )
{
JXCallID( "Wake Up", results[i]);
}
This will call the Wake Up script for all entries with spec Task
and Title = Sleep.
JXDateCompare(Date1,Operation,Date2);
This compares 2 dates. It returns 1 if the operation is true. The operation can be one of "==", "<=", "<", ">", ">=".
JXDateEval(Date);
This returns an expanded form of a date - For example JXDateEval("Tomorrow 11AM") will return "Tue 15-Nov-2011 11:00" (assuming today is 14-Nov-2011). See below for an example...
This makes sure the start date is greater than the due date. If it isn't, it sets it to the start date +1 day.
if( JXDateCompare( JXGet("Start_After"), ">", JXGet("Due_Date") ) )
{
JXSet("Due_Date",JXDateEval(JXGet("Start_After") + "+1 day" ) );
}
JXOpenUrl("https://www.google.com");