×

Style

Beginning with OmniFocus 4, the textual content of project and task notes supports the standard Rich Text Format (RFT). This means that text in notes are Text Objects that can be sized, colored, and styled, and may also contain specialized text objects such as Link Objects.

While the inline RTF codes and markings remain invisible to the user, the textual contents of notes may be defined and controlled through Omni Automation scripts and plug-ins.

The following documentation details the support for the new Style class. Other classes used in processing note text are Text and Color, that are documented on this website as well.

IMPORTANT: Styling for task and project notes is on a “per-note” basis, meaning that there is no ability to change the global note settings. However, with the use of plug-ins and voice commands, changing the look of a project or task note can be a very easy process!

IMPORTANT: Colors are always modeled using values appropriate for rendering in Light mode, and they dynamically adapt as you switch between Light and Dark modes. For example, to make text appear “lighter” in color in Dark Mode, make it “darker” in the default Light Mode.

Before beginning the examination of the Style class, here’s an example script for creating a “note style” that works in both Light and Dark Mode, and adjust certain parameters based upon the type of device. To run, select a single task or project with a long note, then copy the script and paste into the Automation Console in OmniFocus. Press the Return key to see the change!

Note Style: “Legal Pad”


(async () => { try { console.log("DEVICE TYPE:", Device.current.type) var sel = document.windows[0].selection items = sel.databaseObjects.filter( item => (item instanceof Project || item instanceof Task) ) if(items.length === 1){ var item = sel.databaseObjects[0] // reveal note tree = document.windows[0].content tree.nodeForObject(item).expandNote(false) // identify objects noteObj = item.noteText var nStyle = noteObj.style // reset local attributes values to defaults to avoid conflicts from previous style localAtts = nStyle.locallyDefinedAttributes attKeys = localAtts.map(att => att.key) attKeys.forEach(thisKey => { var targetAtt = localAtts.find(att => { return att.key === thisKey }) try { nStyle.set(targetAtt, targetAtt.defaultValue) } catch(err){console.error(targetAtt.key, err.message)} }) // apply formatting nStyle.set(Style.Attribute.FontFamily, 'American Typewriter') nStyle.set(Style.Attribute.FontItalic, false) nStyle.set(Style.Attribute.FontWeight, 4) typeSize = (Device.current.type === DeviceType.iPhone) ? 14:18 nStyle.set(Style.Attribute.FontSize, typeSize) console.log("TYPESIZE:", typeSize) nStyle.set(Style.Attribute.BackgroundColor, null) nStyle.set(Style.Attribute.FontFillColor, Color.darkGray) LHFactor = (Device.current.type === DeviceType.iPhone) ? 1.5:2 nStyle.set(Style.Attribute.ParagraphLineHeightMultiple, LHFactor) console.log("LINE HEIGHT MULTIPLE:", LHFactor) nStyle.set(Style.Attribute.ParagraphSpacingBefore, 36) nStyle.set(Style.Attribute.KerningAdjustment, 1) var tailIndent = (Device.current.type === DeviceType.mac) ? 72:36 if (Device.current.type === DeviceType.iPhone){ nStyle.set(Style.Attribute.ParagraphTailIndent, 0) console.log("TAILINDENT:", 0) } else { nStyle.set(Style.Attribute.ParagraphTailIndent, tailIndent) console.log("TAILINDENT:", tailIndent) } } else { throw { name: "Selection Issue", message: "Please select a single project or task." } } } catch(err){ new Alert(err.name, err.message).show() } })();

(⬇ see below ) Note displayed in Dark Mode:

Dark Mode Note

(⬇ see below ) Note displayed in Light Mode:

Light Mode Note

NOTE: more Note Templates are available at the end of this documentation.

Next, the examination of the Style class begins an overview of the properties and functions of the Style class.

Instance Properties

Here are the basic properties of a style.

Instance Functions

An instance of style can be manipulated by the following set of methods, beginning with a set of commands for clearing, getting, and setting its style attributes:

Here's an example script demonstrating how to set the value a a note’s locally defined attributes to their default values:

Reset Local Attributes to Default


sel = document.windows[0].selection items = sel.databaseObjects.filter( item => (item instanceof Project || item instanceof Task) ) if(items.length === 1){ noteObj = items[0].noteText nStyle = noteObj.style localAtts = nStyle.locallyDefinedAttributes attKeys = localAtts.map(att => att.key) attKeys.forEach(thisKey => { var targetAtt = localAtts.find(att => { return att.key === thisKey }) try { nStyle.set(targetAtt, targetAtt.defaultValue) } catch(err){console.error(targetAtt.key, err.message)} }) }

Style Attributes

A style attribute is a particular property or characteristic of a style. For example, font size and paragraph alignment are two attributes that can be adjusted using scripts. Here is the list of the attributes of a style instance:

TIP: Examples for setting and resetting style attributes can be found in the OmniFocus Voice Commmands collection.

“BackGroundColor” Attribute


styleInst.set(Style.Attribute.BackGroundColor, Color.white)
“BaselineOffset” Attribute


styleInst.set(Style.Attribute.BaselineOffset, 3) // up styleInst.set(Style.Attribute.BaselineOffset, 0) // normal styleInst.set(Style.Attribute.BaselineOffset, -3) // down
“BaselineSuperscript” Attribute


// turn on styleInst.set(Style.Attribute.BaselineSuperscript, true) // turn off styleInst.set(Style.Attribute.BaselineSuperscript, false)
“Expansion” Attribute


// turn on styleInst.set(Style.Attribute.Expansion, true) // turn off styleInst.set(Style.Attribute.Expansion, false)
Font Attributes


styleInst.set(Style.Attribute.FontCondensed, false) styleInst.set(Style.Attribute.FontFamily, 'Helvetica Neue') styleInst.set(Style.Attribute.FontFillColor, Color.white) styleInst.set(Style.Attribute.FontFixedPitch, false) styleInst.set(Style.Attribute.FontItalic, true) styleInst.set(Style.Attribute.FontName, 'HelveticaNeue-MediumItalic') styleInst.set(Style.Attribute.FontNarrow, false) styleInst.set(Style.Attribute.FontSize, 14) styleInst.set(Style.Attribute.FontStrokeColor, Color.red) styleInst.set(Style.Attribute.FontStrokeWidth, 2) styleInst.set(Style.Attribute.FontWeight, 6)

IMPORTANT: to set the font of a style to a specific variation, use a combination of the FontFamily, FontWeight, and FontItalic attributes rather than the FontName attribute:

Set Font to Specific Variation


// Set a style’s font to “Helvetica Neue UltraLight Italic” styleInst.set(Style.Attribute.FontFamily, 'Helvetica Neue') styleInst.set(Style.Attribute.FontItalic, true) styleInst.set(Style.Attribute.FontWeight, 1) styleInst.set(Style.Attribute.FontSize, 24)

NOTE: Values for the fontWeight property vary between font families. Here are the font weight values for Helvetica Neue:

Helvetica Neue UltraLight = 1
Helvetica Neue Thin = 2
Helvetica Neue Light = 3
Helvetica Neue Book = 4
Helvetica Neue Regular = 5
Helvetica Neue Medium = 6
Helvetica Neue Demi-Bold = 7
Helvetica Neue SemiBold = 8
Helvetica Neue Bold = 9
Helvetica Neue ExtraBold = 10
Helvetica Neue Heavy = 11
Helvetica Neue Black = 12
Helvetica Neue Ultra = 13
Helvetica Neue Extrablack = 14

NOTE: to set the font family to the default system UI font:

Set Font Family to Default System UI Font


task = document.windows[0].selection.tasks[0] // OmniFocus uses the system UI font as its default task.noteText.style.set(Style.Attribute.FontFamily, Style.Attribute.FontFamily.defaultValue) // (FYI) The system UI font reference task.noteText.style.set(Style.Attribute.FontFamily, ".AppleSystemUIFont")
“KerningAdjustment” Attribute


//-> increase (loosen) styleInst.set(Style.Attribute.KerningAdjustment, 3) //-> decrease (tighten) styleInst.set(Style.Attribute.KerningAdjustment, -3) //-> default styleInst.set(Style.Attribute.KerningAdjustment, 0)
“LigatureSelection” Attribute


styleInst.set(Style.Attribute.LigatureSelection, LigatureStyle.All) styleInst.set(Style.Attribute.LigatureSelection, LigatureStyle.Essential) styleInst.set(Style.Attribute.LigatureSelection, LigatureStyle.Standard)
“Link” Attribute


url = URL.fromString('https://omni-automation.com') styleInst.set(Style.Attribute.Link, url)
“Obliqueness” Attribute


// lean right styleInst.set(Style.Attribute.Obliqueness, .25) // lean left styleInst.set(Style.Attribute.Obliqueness, -.25) // none styleInst.set(Style.Attribute.Obliqueness, 0)

Paragraph Attributes

“ParagraphAlignment” Attribute


styleInst.set(Style.Attribute.ParagraphAlignment, TextAlignment.Center) styleInst.set(Style.Attribute.ParagraphAlignment, TextAlignment.Justified) styleInst.set(Style.Attribute.ParagraphAlignment, TextAlignment.Left) styleInst.set(Style.Attribute.ParagraphAlignment, TextAlignment.Natural) styleInst.set(Style.Attribute.ParagraphAlignment, TextAlignment.Right)
“ParagraphBaseWritingDirection” Attribute


styleInst.set(Style.Attribute.ParagraphBaseWritingDirection, WritingDirection.LeftToRight) styleInst.set(Style.Attribute.ParagraphBaseWritingDirection, WritingDirection.Natural) styleInst.set(Style.Attribute.ParagraphBaseWritingDirection, WritingDirection.RightToLeft)
“ParagraphDefaultTabInterval” Attribute


styleInst.set(Style.Attribute.ParagraphDefaultTabInterval, 72) //-> true styleInst.get(Style.Attribute.ParagraphDefaultTabInterval) //-> 72
“ParagraphTabStops” Attribute


styleInst.get(Style.Attribute.ParagraphTabStops) //-> 28L,56L,84L,112L,140L,168L,196L,224L,252L,280L,308L,336L styleInst.set(Style.Attribute.ParagraphTabStops, '72L,144L,216R') styleInst.get(Style.Attribute.ParagraphTabStops) //-> 72L,144L,216R
Creating TabStop String for 6 Financial Columns


tabWidth = 128 firstTabOffset = 192 columnCount = 6 tabStops = String(firstTabOffset) + "D" for (i = 1; i < columnCount; i++) { tabStops += "," + String(firstTabOffset + (i * tabWidth)) + "D" } console.log("TABSTOPS:", tabStops) //--> TABSTOPS: 192D,320D,448D,576D,704D,832D
“ParagraphTailIndent” Attribute


styleInst.set(Style.Attribute.ParagraphTailIndent, 72)
“ShadowBlurRadius” Attribute


styleInst.set(Style.Attribute.ShadowBlurRadius, 2.5)
“ShadowColor” Attribute


styleInst.set(Style.Attribute.ShadowColor, Color.black)
“ShadowOffset” Attribute


// offset the shadow to the lower right (horizontal, vertical) styleInst.set(Style.Attribute.ShadowOffset, new Point(3, -4))
Striketrough


// Single Line styleInst.set(Style.Attribute.StrikethroughStyle, UnderlineStyle.Single) // No Strikethrough styleInst.set(Style.Attribute.StrikethroughStyle, null)

Style Attribute Instance Properties

Here are a list of all the keys for the available style attributes:

Style Attribute Keys


["text-background-color","baseline-offset","baseline-superscript","font-expansion","font-condensed","font-family","font-fill","font-fixed-pitch","font-italic","font-name","font-narrow","font-size","font-stroke","font-stroke-width","font-weight","kerning-adjust","ligature-selection","link","font-obliqueness","paragraph-alignment","paragraph-base-writing-direction","paragraph-tab-stop-interval","paragraph-first-line-head-indent","paragraph-head-indent","paragraph-line-height-multiple","paragraph-line-spacing","paragraph-maximum-line-height","paragraph-minimum-line-height","paragraph-spacing","paragraph-spacing-before","paragraph-tab-stops","paragraph-tail-indent","shadow-radius","shadow-color","shadow-offset","strikethrough-affinity","strikethrough-color","strikethrough-pattern","strikethrough-style","underline-affinity","underline-color",UnderlinePattern,"underline-style"]

Here’s a script that logs the local style attributes of the current note:

Determining Current Style Adjustments
 

sel = document.windows[0].selection items = sel.databaseObjects.filter( item => (item instanceof Project || item instanceof Task) ) if(items.length === 1){ noteObj = items[0].noteText nStyle = noteObj.style localAtts = nStyle.locallyDefinedAttributes attKeys = localAtts.map(att => att.key) attKeys.forEach(thisKey => { targetAtt = localAtts.find(att => { return att.key === thisKey }) attValue = nStyle.get(targetAtt) if (attValue instanceof Color){ colorString = `Color.RGB(${attValue.red}, ${attValue.green}, ${attValue.blue}, ${attValue.alpha})` console.log(thisKey + ":", colorString) } else { console.log(thisKey + ":", attValue) } }) } else { throw { name: "Selection Issue", message: "Please select a single project or task." } }

TIP: Install the attribute logging plug-in and add it to the Console window toolbar for quick access to style information for the note of the selected project or task:

Console window showing the local style attribute values

Default Values

Here's a script that uses the defaultValue property to derive the default values for fonts:

val = Style.Attribute.FontFamily.defaultValue console.log("FontFamily: " + val) val = Style.Attribute.FontName.defaultValue console.log("FontName: " + val) val = Style.Attribute.FontSize.defaultValue console.log("FontSize: " + val) val = Style.Attribute.FontWeight.defaultValue console.log("FontWeight: " + val) clr = Style.Attribute.FontFillColor.defaultValue console.log("FontFillColor: " + [clr.red, clr.green, clr.blue]) clr = Style.Attribute.FontStrokeColor.defaultValue console.log("FontStrokeColor: " + [clr.red, clr.green, clr.blue]) val = Style.Attribute.FontStrokeWidth.defaultValue console.log("FontStrokeWidth: " + val) val = Style.Attribute.FontCondensed.defaultValue console.log("FontCondensed: " + val) val = Style.Attribute.FontItalic.defaultValue console.log("FontItalic: " + val) val = Style.Attribute.FontNarrow.defaultValue console.log("FontNarrow: " + val)
Default Font Style Attribute Values


Style.Attribute.FontFamily.defaultValue //--> Helvetica Style.Attribute.FontName.defaultValue //--> Helvetica Style.Attribute.FontSize.defaultValue //--> 12 Style.Attribute.FontWeight.defaultValue //--> 5 clr = Style.Attribute.FontFillColor.defaultValue console.log([clr.red, clr.green, clr.blue]) //--> [0, 0, 0] clr = Style.Attribute.FontStrokeColor.defaultValue console.log([clr.red, clr.green, clr.blue]) //--> [0, 0, 0] Style.Attribute.FontStrokeWidth.defaultValue //--> 0 Style.Attribute.FontCondensed.defaultValue //--> false Style.Attribute.FontItalic.defaultValue //--> false Style.Attribute.FontNarrow.defaultValue //--> false

Here's a script that resets the current value of an attribute to its default value:

Set Style Attribute Value to Default Value for Attribute


styleInst.set(Style.Attribute.FontSize, Style.Attribute.FontSize.defaultValue)

Here’s a variation that resets all style attributes to default values for the selected note:

Reset All Attributes to Default Values
 

var attributes = [Style.Attribute.BackgroundColor, Style.Attribute.BaselineOffset, Style.Attribute.BaselineSuperscript, Style.Attribute.Expansion, Style.Attribute.FontCondensed, Style.Attribute.FontFamily, Style.Attribute.FontFillColor, Style.Attribute.FontFixedPitch, Style.Attribute.FontItalic, Style.Attribute.FontName, Style.Attribute.FontNarrow, Style.Attribute.FontSize, Style.Attribute.FontStrokeColor, Style.Attribute.FontStrokeWidth, Style.Attribute.FontWeight, Style.Attribute.KerningAdjustment, Style.Attribute.LigatureSelection, Style.Attribute.Link, Style.Attribute.Obliqueness, Style.Attribute.ParagraphAlignment, Style.Attribute.ParagraphDefaultTabInterval, Style.Attribute.ParagraphFirstLineHeadIndent, Style.Attribute.ParagraphHeadIndent, Style.Attribute.ParagraphLineHeightMultiple, Style.Attribute.ParagraphLineSpacing, Style.Attribute.ParagraphMaximumLineHeight, Style.Attribute.ParagraphMinimumLineHeight, Style.Attribute.ParagraphSpacing, Style.Attribute.ParagraphSpacingBefore, Style.Attribute.ParagraphTabStops, Style.Attribute.ParagraphTailIndent, Style.Attribute.ShadowBlurRadius, Style.Attribute.ShadowColor, Style.Attribute.ShadowOffset, Style.Attribute.StrikethroughAffinity, Style.Attribute.StrikethroughColor, Style.Attribute.StrikethroughPattern, Style.Attribute.StrikethroughStyle, Style.Attribute.UnderlineAffinity, Style.Attribute.UnderlineColor, Style.Attribute.UnderlinePattern, Style.Attribute.UnderlineStyle] var sel = document.windows[0].selection var items = sel.databaseObjects.filter(item => { if(item instanceof Project || item instanceof Task){return item} }) if(items.length === 1){ noteObj = items[0].noteText var nStyle = noteObj.styleForRange(noteObj.range) attributes.forEach(att => { nStyle.set(att, att.defaultValue) }) } else { throw { name: "Selection Issue", message: "Please select a single project or task." } }

NOTE: There’s an OmniFocus voice command for appending plain-text from the clipboard to the note of the selected project or task.

 

UnderlineAffinity

A class whose properties indicate how the text is to be underlined.

 

UnderlinePattern

A class whose properties indicate how the line pattern to be used in underlining text.

 

UnderlineStyle

Underline style specifiers.

 

LigatureStyle

A class whose properties indicate the set of ligatures to be applied to the text.

 

TextAlignment

A class whose properties indicate the text alignment options for the styled paragraphs.

 

WritingDirection

A class whose properties indicate the available writing directions to use for the styled text.

Saving Note to RTF File

Here's a plug-in that can be used to save the copied contents of a formated note to an RTF file in the OmniFocus documents folder:

Save Clipboard Text to App Documents Folder
 

/*{ "type": "action", "targets": ["omnifocus", "omnigraffle", "omniplan", "omnioutliner"], "author": "Otto Automator", "identifier": "com.omni-automation.all.write-clip-text-to-app-documents", "version": "1.2", "description": "Writes the text content of the clipboard to a file in the Omni app’s local Documents folder", "label": "Clip Text to App Documents Folder", "shortLabel": "Save to App Documents", "paletteLabel": "Save to App Documents", "image": "doc.on.clipboard.fill" }*/ (() => { var action = new PlugIn.Action(async function(selection, sender){ try { inputForm = new Form() fileNameField = new Form.Field.String( "fileBaseName", "File Name", null, null ) inputForm.addField(fileNameField) fileTypes = ["Text (plain)", "TaskPaper", "RTF", "HTML", "JavaScript", "SVG"] nameExtensions = ["txt", "taskpaper", "rtf", "html", "js", "svg"] savingTypeMenu = new Form.Field.Option( "nameExtension", "Text File Type", nameExtensions, fileTypes, nameExtensions[0] ) inputForm.addField(savingTypeMenu) if (Device.current.mac){ shouldOpenFileField = new Form.Field.Checkbox( "shouldOpenFile", "Open file in default application", null ) inputForm.addField(shouldOpenFileField) } inputForm.validate = function(formObject){ textValue = formObject.values['fileBaseName'] return (textValue && textValue.length > 0) ? true:false } formPrompt = `Clipboard to ${app.name} Documents` buttonTitle = "Continue" formObject = await inputForm.show(formPrompt, buttonTitle) fileBaseName = formObject.values["fileBaseName"] nameExtension = formObject.values["nameExtension"] fileName = fileBaseName + "." + nameExtension if (Device.current.mac){ var shouldOpenFile = formObject.values["shouldOpenFile"] } folderURL = URL.documentsDirectory fileURL = folderURL.appendingPathComponent(fileName) if (nameExtension === "rtf"){ textData = Pasteboard.general.dataForType(TypeIdentifier.rtf) } else { textData = Data.fromString(Pasteboard.general.string, StringEncoding.UTF8) } wrapper = FileWrapper.withContents(fileName, textData) wrapper.write(fileURL, [FileWrapper.WritingOptions.Atomic], null) if (Device.current.mac){ if(shouldOpenFile){fileURL.open()} } } catch(err){console.error(err.message)} }); action.validate = function(selection, sender){ return (Pasteboard.general.hasStrings) }; return action; })();
 

Note Style Plug-Ins

Here are some more note templates to try! Typefaces are available on all Apple devices.

NOTE: for style clarity all existing locally defined attributes are set to default values before applying the new styling.

Paragraph Attributes Dialog

TIP: this collection is also available as Voice Control commands.

 

Note Style Templates

The following script and plug-in templates can be used to create your own note style tools. Each template already contains the necessary code for identifying the note of the selected project or task, as well as to clear any previous settings before applying the new attributes settings.

Note Style Script Template


(async () => { try { console.log("DEVICE TYPE:", Device.current.type) var sel = document.windows[0].selection items = sel.databaseObjects.filter( item => (item instanceof Project || item instanceof Task) ) if(items.length === 1){ console.log("DEVICE:", Device.current.type) var item = sel.databaseObjects[0] // reveal note tree = document.windows[0].content tree.nodeForObject(item).expandNote(false) // identify selected note and style noteObj = item.noteText var nStyle = noteObj.style // reset local attributes values to defaults localAtts = nStyle.locallyDefinedAttributes attKeys = localAtts.map(att => att.key) attKeys.forEach(thisKey => { var targetAtt = localAtts.find(att => { return att.key === thisKey }) try { nStyle.set(targetAtt, targetAtt.defaultValue) } catch(err){console.error(targetAtt.key, err.message)} }) // FORMATTING STATEMENTS GO HERE } else { throw { name: "Selection Issue", message: "Please select a single project or task." } } } catch(err){ new Alert(err.name, err.message).show() } })();
agenda://note/WelcomeSection-Share
Note Style Plug-In Template


/*{ "type": "action", "targets": ["omnifocus"], "author": "Your Name Goes Here", "identifier": "com.YouOrCompany.of.name-for-plug-in", "version": "1.0", "description": "A plug-in for changing the note style of the selected project or task", "label": "Plug-In Menu Item Title", "shortLabel": "Short Item Title", "paletteLabel": "Toolbar Item Title", "image": "wand.and.stars" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ // action code try { console.log("DEVICE:", Device.current.type) var item = selection.databaseObjects[0] // reveal note tree = document.windows[0].content tree.nodeForObject(item).expandNote(false) // identify selected note and style noteObj = item.noteText var nStyle = noteObj.style // reset local attributes values to defaults localAtts = nStyle.locallyDefinedAttributes attKeys = localAtts.map(att => att.key) attKeys.forEach(thisKey => { var targetAtt = localAtts.find(att => { return att.key === thisKey }) try { nStyle.set(targetAtt, targetAtt.defaultValue) } catch(err){console.error(targetAtt.key, err.message)} }) // FORMATTING STATEMENTS GO HERE } catch(err){ console.error(err.name, err.message) new Alert(err.name, err.message).show() } }); action.validate = function(selection, sender){ // validation code return (selection.projects.length === 1 || selection.tasks.length === 1) }; return action; })();