Plug-In: Character Attributes
A plug-in for setting and restoring the character attributes of the note of the selected project or task.
(NOTE: This plug-in requires OmniFocus 4.x)
(above) Each of the specified character attributes has its own menu of settings and options. By default, the initial setting for each property is: “No Change”
All but the alignment property menus offer these two options:
- No Change • When this option is chosen, no changes will be made to the paragraph attribute.
- Default • When this option is chosen, the default value for the paragraph attribute will be applied to the note text.
NOTE: Immediately following each attribute title, placed within parens, is the current value of that attribute in the note.
IMPORTANT: Attribute changes are applied to all of the note text, not just a selection.
Here is a description of each of the character attributes:
- Font Family (String) • The name of the font family to be applied to the note. The cross-platform typeface options are; "Default", "Avenir Next", "Baskerville", "Bodoni 72", "Bradley Hand", "Chalkboard SE", "Cochin", "Courier New", "Damascus", "Georgia", "Gill Sans", "Helvetica Neue", "Hoefler Text", "Menlo", "Noteworthy", "Optima", "Palatino", "Rockwell", "Savoye LET", "Snell Roundhand", "Times New Roman", "Trebuchet MS", and "Verdana"
- Font Weight (Number) • This value, from 1 through 9, indicates the thickness of the typeface. Light-thin variations are usually 1-2, book or regular variations are usually 3-5, and the higher settings are for bold. Use the System Font Panel (⌘T) to confirm.
- Font Size (Number) • The size (in points) to be used. Options include: "Default", "9", "10", "11", "12", "13", "14", "15", "16", "18", "24"
- Kerning Adjustment (Number) • Controls the space between characters. For example, some of the lighter typeface when used at a larger type size, require slight positive (increased) kerning to display well. Options include: "Default", "+3", "+2", "+1", " 0", "-1", "-2", and "-3"
- Color Shade (Percent) • Whe used, this setting will cause the note text to display as a shade of black (or white for Dark Mode). Options are (%): "Default", "100", "95", "90", "85", "80", "75", "70"
Return to: OmniFocus Plug-In Collection
Character Attributes
/*{
"type": "action",
"targets": ["omnifocus"],
"author": "Otto Automator",
"identifier": "com.omni-automation.of.character-attributes",
"version": "1.5",
"description": "This plug-in will display and apply the character attribute settings of the note of the selected project or task.",
"label": "Note Style Character Attributes",
"shortLabel": "Character Attributes",
"paletteLabel": "Character Attributes",
"image": "textformat.abc.dottedunderline"
}*/
(() => {
var action = new PlugIn.Action(async function(selection, sender){
try {
var shouldLog = true
if(shouldLog){console.clear()}
var item = selection.databaseObjects[0]
// CREATE VIRTUAL TEXT OBJECT CONTAING CURRENT NOTE
var noteObj = new Text("", baseStyle)
noteObj.replace(noteObj.range, item.noteText)
var nStyle = noteObj.style
// GET ATTRIBUTES RANGES
var runRanges = noteObj.ranges(TextComponent.AttributeRuns)
// CREATE FORM AND FORM ELEMENTS
fontFamilyTitles = ["Default", "Avenir Next", "Baskerville", "Bodoni 72", "Bradley Hand", "Chalkboard SE", "Cochin", "Courier New", "Damascus", "Georgia", "Gill Sans", "Helvetica Neue", "Hoefler Text", "Menlo", "Noteworthy", "Optima", "Palatino", "Rockwell", "Savoye LET", "Snell Roundhand", "Times New Roman", "Trebuchet MS", "Verdana"]
fontFamilyIndexes = fontFamilyTitles.map((title, index) => index)
var fontFamCurVal = nStyle.get(Style.Attribute.FontFamily)
fontFamCurVal = (fontFamCurVal === ".AppleSystemUIFont") ? "System Font":fontFamCurVal
fontFamilyMenu = new Form.Field.Option(
"fontFamily",
`Font Family (${fontFamCurVal})`,
fontFamilyIndexes,
fontFamilyTitles,
null
)
fontFamilyMenu.allowsNull = true
fontFamilyMenu.nullOptionTitle = "No Change"
fntWghtCurVal = nStyle.get(Style.Attribute.FontWeight)
fntWghtValueStrings = ["Default", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
fntWghtValues = fntWghtValueStrings.map((title, index) => index)
fontWeightMenu = new Form.Field.Option(
"fontWeight",
`Font Weight (${fntWghtCurVal})`,
fntWghtValues,
fntWghtValueStrings,
null
)
fontWeightMenu.allowsNull = true
fontWeightMenu.nullOptionTitle = "No Change"
var fntSzeCurVal = nStyle.get(Style.Attribute.FontSize)
fntSzeValueStrings = ["Default", "9", "10", "11", "12", "13", "14", "15", "16", "18", "24"]
fntSzeValues = fntSzeValueStrings.map((title, index) => index)
fontSizeMenu = new Form.Field.Option(
"fontSize",
`Font Size (${fntSzeCurVal})`,
fntSzeValues,
fntSzeValueStrings,
null
)
fontSizeMenu.allowsNull = true
fontSizeMenu.nullOptionTitle = "No Change"
fntKrnCurVal = nStyle.get(Style.Attribute.KerningAdjustment)
fntKrnCurVal = fntKrnCurVal.toString()
fntKrnCurVal = (fntKrnCurVal === "NaN") ? "0":fntKrnCurVal
fntKrnValueStrings = ["Default", "+3", "+2", "+1", " 0", "-1", "-2", "-3"]
fntKrnValues = fntKrnValueStrings.map((title, index) => index)
fontKerningMenu = new Form.Field.Option(
"kerningAdjustment",
`Kerning Adjustment (${fntKrnCurVal})`,
fntKrnValues,
fntKrnValueStrings,
null
)
fontKerningMenu.allowsNull = true
fontKerningMenu.nullOptionTitle = "No Change"
fntFilClrCurVal = nStyle.get(Style.Attribute.FontFillColor)
fntFilClrCurVal = String(100 - (fntFilClrCurVal.white * 100))
fntFilClrValStrings = ["Default", "100", "95", "90", "85", "80", "75", "70"]
fntFilClrIndexes = fntFilClrValStrings.map((title, index) => index)
fontFillColorMenu = new Form.Field.Option(
"fontFillColor",
`Color Shade Pct (${fntFilClrCurVal})`,
fntFilClrIndexes,
fntFilClrValStrings,
null
)
fontFillColorMenu.allowsNull = true
fontFillColorMenu.nullOptionTitle = "No Change"
// CONSTRUCT FORM
inputForm = new Form()
inputForm.addField(fontFamilyMenu)
inputForm.addField(fontWeightMenu)
inputForm.addField(fontSizeMenu)
inputForm.addField(fontKerningMenu)
inputForm.addField(fontFillColorMenu)
formPrompt = "Note Character Attributes:"
buttonTitle = "Continue"
formObject = await inputForm.show(formPrompt, buttonTitle)
// retrieve attribute settings
if(shouldLog){console.log(">>> RETRIEVING FORM SETTINGS <<<")}
fontFamilyIndex = formObject.values["fontFamily"]
fontFamily = fontFamilyTitles[fontFamilyIndex]
console.log("fontFamily", fontFamily)
fontWeightIndex = formObject.values["fontWeight"]
fontWeight = fntWghtValueStrings[fontWeightIndex]
console.log("fontWeight", fontWeight)
fontSizeIndex = formObject.values["fontSize"]
fontSize = fntSzeValueStrings[fontSizeIndex]
console.log("fontSize", fontSize)
fontKerningIndex = formObject.values["kerningAdjustment"]
fontKerning = fntKrnValueStrings[fontKerningIndex]
console.log("fontKerning", fontKerning)
fontFillColorIndex = formObject.values["fontFillColor"]
fontFillColor = fntFilClrValStrings[fontFillColorIndex]
console.log("fontFillColor", fontFillColor)
// SET ATTRIBUTE VALUES
if(shouldLog){console.log(">>> ORGANIZING VALUES <<<")}
var attsToModify = []
var valuesToApply = []
if(fontFamily){
if(shouldLog){console.log("fontFamily", fontFamily)}
if(fontFamily === "Default"){
var valueToSet = Style.Attribute.FontFamily.defaultValue
} else {
var valueToSet = fontFamily
}
attsToModify.push(Style.Attribute.FontFamily)
valuesToApply.push(valueToSet)
}
if(fontWeight){
if(shouldLog){console.log("fontWeight", fontWeight)}
if(fontWeight === "Default"){
var valueToSet = Style.Attribute.FontWeight.defaultValue
} else {
var valueToSet = parseInt(fontWeight)
}
attsToModify.push(Style.Attribute.FontWeight)
valuesToApply.push(valueToSet)
}
if(fontSize){
if(shouldLog){console.log("fontSize", fontSize)}
if(fontSize === "Default"){
var valueToSet = Style.Attribute.FontSize.defaultValue
} else {
var valueToSet = parseInt(fontSize)
}
attsToModify.push(Style.Attribute.FontSize)
valuesToApply.push(valueToSet)
}
if(fontKerning){
if(shouldLog){console.log("fontKerning", fontKerning)}
if(fontKerning === "Default"){
var valueToSet = Style.Attribute.KerningAdjustment.defaultValue
} else {
var valueToSet = parseInt(fontKerning)
}
attsToModify.push(Style.Attribute.KerningAdjustment)
valuesToApply.push(valueToSet)
}
if(fontFillColor){
if(shouldLog){console.log("fontFillColor", fontFillColor)}
if(fontFillColor === "Default"){
var valueToSet = Style.Attribute.FontFillColor.defaultValue
} else {
var shadePct = parseInt(fontFillColor)
shadePct = shadePct * 0.01
shadeValue = 1 - shadePct
valueToSet = Color.White(shadeValue, 1)
}
attsToModify.push(Style.Attribute.FontFillColor)
valuesToApply.push(valueToSet)
attsToModify.push(Style.Attribute.FontStrokeColor)
valuesToApply.push(valueToSet)
}
// APPLY THE SPECIFIED ATTRIBUTE SETTINGS
if(shouldLog){console.log(">>> APPLYING VALUES TO NOTEOBJ <<<")}
runRanges.forEach(range => {
runStyle = noteObj.styleForRange(range)
attsToModify.forEach((att, index) => {
valueToSet = valuesToApply[index]
if(shouldLog){console.log("Range:", noteObj.textInRange(range).string)}
if(shouldLog){console.log("Attribute:", att.key)}
if(shouldLog){console.log("Value:", valueToSet)}
runStyle.set(att, valueToSet)
})
})
// REPLACE NOTE WITH VIRTUAL OBJECT
if(shouldLog){console.log(">>> REPLACING TEXT WITH NOTEOBJ <<<")}
item.noteText.replace(item.noteText.range, noteObj)
// reveal note
//if(shouldLog){console.log("SHOW NOTE")}
tree = document.windows[0].content
tree.nodeForObject(item).expandNote(false)
}
catch(err){
if(!err.causedByUserCancelling){
console.log(err.name, err.message)
}
}
});
action.validate = function(selection, sender){
// validation code
// selection options: tasks, projects, folders, tags, allObjects
return (selection.tasks.length === 1 || selection.projects.length === 1 )
};
return action;
})();