Preferences
The ability for plug-ins to store, retrieve, and share data is an essential element for creating versatile automation tools. The Preferences class enables plug-ins to fully retain and utilize data for optimum workflow design and function.
NOTE:
- Stored Preferences data is not encrypted. Use the Credentials class to store data securely in the system Keychain. The Preferences class stores its values in the host application’s preferences structure, but the keys are mapped to "omnijs:<identifier>.<key>" so that scripts can't read/write arbitrary things, and can't forget to prefix their preference keys with a domain identifier.
- Plug-ins can cooperate (share data) by using the same preference domain identifier. For example, if a a plug-in declares a Preferences instance with the identifier "com.my-company.shared-data" then other plug-ins can access that data by creating an instance using the same identifier.
- If a Preferences identifier is not declared in the instantiating statement, the identifier of the host plug-in is used instead.
- Preferences data cannot be shared between Omni applications, even if the plug-ins linked by the applications use the same identifier. This is because each application’s Preferences data is stored in a property list within that application’s application sandbox realm, which is not accessible by other applications.
- More complicated values (arrays or dictionaries of values, etc.) should be stored as strings by archiving them to JSON prior to writing the results to a Preferences instance.
Constructors
new Preferences(identifier: String or null) → (Preferences) • Creates a new Preferences instance. The identifier specified may be null to create an instance for the currently loading plug-in. If it is null and a plug-in is not being loaded, an error will be thrown. Key/value pairs stored in the instance will be prefixed with the identifier and a “.”.
Instance Properties
identifier (String r/o) • The scoping identifier the instance given when created, or the plug-in identifier if none was given.
Instance Functions
read(key: String) → (Object or null) • Returns the previously stored value for the given key, or null if no value is stored.
readBoolean(key: String) → (Boolean) • Returns the previously stored value as a Boolean, or false if there is no stored value or it can’t be converted to a Boolean.
readString(key: String) → (String or null) • Returns the previously stored value as a String, or null if there is no stored value or it is not a String.
readNumber(key: String) → (Number or null) • Returns the previously stored value as a Number, or null if there is no stored value or it is not a Number.
readDate(key: String) → (Date or null) • Returns the previously stored value as a Date, or null if there is no stored value or it is not a Date.
readData(key: String) → (Data or null) • Returns the previously stored value as a Data, or null if there is no stored value or it is not a Data.
write(key: String, value: Boolean, String, Number, Date, Data, or null) → ( ) • Stores the specified key/value pair. A null value is equivalent to removing the key/value pair.
remove(key: String) → ( ) • Removes the previously stored value for the given key.
Example Plug-In: Counter
The following example plug-in displays a counter showing the number of times the alert has been displayed.
![preferences-counter-alert](gfx/preferences-counter-alert.jpg)
To reset the counter, hold down the Control key when selecting the plug-in from the Automation menu.
Incrementing Alert
/*{
"type": "action",
"targets": ["omnifocus","omniplan","omnigraffle","omnioutliner"],
"author": "Otto Automator",
"identifier": "com.omni-automation.all.preferences-counter",
"version": "1.1",
"description": "Demonstrates the use of the Preferences class to store and retrieve data.",
"label": "Preferences Counter Example",
"shortLabel": "Preferences Counter Example",
"paletteLabel": "Preferences Counter Example",
"image": "number.square"
}*/
(() => {
// DECLARE PREFERENCES INSTANCE
preferences = new Preferences() // NO ID = PLUG-IN ID
console.log(preferences.identifier)
const action = new PlugIn.Action(function(selection, sender){
incrementedCount = 0
console.log("app.controlKeyDown", app.controlKeyDown)
if (app.controlKeyDown){
console.log("Show Alert")
alertMessage = "Reset the stored value?"
alert = new Alert("Confirmation Required", alertMessage)
alert.addOption("Reset")
alert.addOption("Cancel")
alert.show(buttonIndex => {
if (buttonIndex === 0){
preferences.write("incrementedCount", 0)
}
})
} else {
incrementedCount = preferences.readNumber("incrementedCount")
console.log("incrementedCount-stored", incrementedCount)
newIncrementedCount = incrementedCount + 1
preferences.write("incrementedCount", newIncrementedCount)
alertTitle = "Incrementing Alert"
alertMessage = "This alert has been shown " + String(newIncrementedCount) + " times."
alert = new Alert(alertTitle, alertMessage).show()
}
});
action.validate = function(selection, sender){
return true
};
return action;
})();
Example Plug-In: Form Data
A standard use of the Preferences class is to store the chosen values of forms so that the forms will return to their former state when displayed again. The following plug-in displays a form containing a menu, text field, date input, and checkbox. The Preferences class is used to store and retrieve the values set by the user.
![preferences-class-dialog](gfx/preferences-class-dialog.jpg)
To reset the values to their defaults, hold down the Control key when selecting the plug-in from the Automation menu.
Preferences Form Example
/*{
"type": "action",
"targets": ["omnifocus","omniplan","omnigraffle","omnioutliner"],
"author": "Otto Automator",
"identifier": "com.omni-automation.all.preferences-example",
"version": "1.6",
"description": "Demonstrates the use of the Preferences class to store and retrieve data.",
"label": "Preferences Example",
"shortLabel": "Preferences Example",
"paletteLabel": "Preferences Example",
"image":"switch.2"
}*/
(() => {
// DECLARE PREFERENCES INSTANCE
var preferences = new Preferences() // NO ID = PLUG-IN ID
const action = new PlugIn.Action(async function(selection, sender){
// action code
try {
// HOLD DOWN CONTROL KEY TO RESET VALUES
if (app.controlKeyDown){
console.log("Show Alert")
alertMessage = "Remove the stored values?"
alert = new Alert("Confirmation Required", alertMessage)
alert.addOption("Remove")
alert.addOption("Cancel")
alert.show(buttonIndex => {
if (buttonIndex === 0){
preferences.remove("optionsMenu")
preferences.remove("textInput")
preferences.remove("checkboxSwitch")
preferences.remove("dateInput")
}
})
} else {
// DEFAULT VALUES
defaultMenuIndex = 0
defaultNameValue = ""
defaultBooleanValue = false
defaultdateValue = new Date()
// READ STORED VALUES IF ANY. SET DEFAULTS IF NEEDED.
menuIndex = preferences.readNumber("optionsMenu")
console.log("menuIndex-stored", menuIndex)
if(!menuIndex){
menuIndex = defaultMenuIndex
}
nameValue = preferences.readString("textInput")
console.log("nameValue-stored", nameValue)
if(!nameValue){
nameValue = defaultNameValue
}
booleanValue = preferences.readBoolean("checkboxSwitch")
console.log("booleanValue-stored", booleanValue)
if(!booleanValue instanceof Boolean){
booleanValue = defaultBooleanValue
}
dateValue = preferences.readDate("dateInput")
console.log("dateValue-stored", dateValue)
if(!dateValue){
dateValue = defaultdateValue
}
// CONSTRUCT THE FORM
menuItems = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
menuIndexes = [0,1,2,3,4,5,6]
optionsMenu = new Form.Field.Option(
"optionsMenu",
"Weekday",
menuIndexes,
menuItems,
menuIndex
)
textInputField = new Form.Field.String(
"textInput",
"Name",
nameValue
)
checkSwitchField = new Form.Field.Checkbox(
"checkboxSwitch",
"I accept the standard terms and conditions",
booleanValue
)
dateInputField = new Form.Field.Date(
"dateInput",
"Date",
dateValue
)
inputForm = new Form()
inputForm.addField(optionsMenu)
inputForm.addField(textInputField)
inputForm.addField(checkSwitchField)
inputForm.addField(dateInputField)
inputForm.validate = function(formObject){
return true
}
formPrompt = "Make selections and enter values:"
buttonTitle = "Continue"
formObject = await inputForm.show(formPrompt, buttonTitle)
menuIndex = formObject.values['optionsMenu']
console.log('menuIndex-write', menuIndex)
nameValue = formObject.values['textInput']
if(!nameValue){nameValue = ""} // convert null to empty string
console.log('nameValue-write', nameValue)
booleanValue = formObject.values['checkboxSwitch']
console.log('booleanValue-write', booleanValue)
dateValue = formObject.values['dateInput']
console.log('dateValue-write', dateValue)
// STORE THE VALUES
preferences.write("optionsMenu", menuIndex)
preferences.write("textInput", nameValue)
preferences.write("checkboxSwitch", booleanValue)
preferences.write("dateInput", dateValue)
}
}
catch(err){
if(!err.causedByUserCancelling){
console.error(err.name, err.message)
//new Alert(err.name, err.message).show()
}
}
});
action.validate = function(selection, sender){
// validation code
return true
};
return action;
})();
1st-Run Interaction Plug-In
A plug-in that uses the Preferences class to create a 1st-run interaction. To reset the plug-in, hold down Control modifier key when selecting plug-in from the Automation menu.
1st-Run Sensor
/*{
"type": "action",
"targets": ["omnifocus","omniplan","omnigraffle","omnioutliner"],
"author": "Otto Automator",
"identifier": "com.omni-automation.all.first-run-sensor",
"version": "1.0",
"description": "This plug-in will present an alert the first time it is executed. To reset the plug-in, hold down Control key when selecting from Automation menu.",
"label": "First Run Example",
"shortLabel": "First Run Example",
"paletteLabel": "First Run Example",
"image": "1.brakesignal"
}*/
(() => {
var preferences = new Preferences()
const action = new PlugIn.Action(async function(selection, sender){
incrementedCount = preferences.readNumber("incrementedCount")
if(!incrementedCount){
preferences.write("incrementedCount", 0)
incrementedCount = 0
}
if (app.controlKeyDown){
alertMessage = "Reset the stored count?"
alert = new Alert("Confirmation Required", alertMessage)
alert.addOption("Reset")
alert.addOption("Cancel")
buttonIndex = await alert.show()
if (buttonIndex === 0){
preferences.write("incrementedCount", 0)
console.log("incrementedCount", "reset")
return "user reset"
}
}
console.log("incrementedCount", incrementedCount)
if (incrementedCount === 0){
alertTitle = "Plug-In 1st Run"
alertMessage = "Welcome to the 1st-Run Plug-In!"
await new Alert(alertTitle, alertMessage).show()
}
preferences.write("incrementedCount", incrementedCount + 1)
// PROCESSING CODE GOES HERE
});
action.validate = function(selection, sender){
return true
};
return action;
})();