Selected text to title case?

I should preface this with the fact that I have zero coding ability.

However, something I often have to do for blog posts and documents is title case my headings. I use this website https://titlecase.com which uses the APA style for title case. This requires me to type out my heading, convert it and copy it back to my document and then format it.

What I was wondering is if it would be possible to have a script on a button that when pressed would convert any selected text into title case using the following rules:

Capitalise the first word
Capitalise the first word after a colon, em dash, or end punctuation
Capitalise major words, including the second part of hyphenated major words (e.g., “Self-Report,” not “Self-report”)
Capitalise words of four letters or more (e.g., “With,” “Between,” “From”)

Lowercase only minor words that are three letters or fewer (except the first word or the first word after a colon, em dash, or end punctuation in a heading):

short conjunctions (e.g., “and,” “as,” “but,” “for,” “if,” “nor,” “or,” “so,” “yet”)
articles (“a,” “an,” “the”)
short prepositions (e.g., “as,” “at,” “by,” “for,” “in,” “of,” “off,” “on,” “per,” “to,” “up,” “via”)

do you think their rules match yours: https://github.com/words/ap-style-title-case ?

If so I can post an example on how to use that script with BTT

From what I can see the rules are the same :slight_smile:

Do you think you might be able to help with this? :slight_smile:

Ah yes sorry.

You can use the "Transform selection with java script" predefined action and enter this script:

async (clipboardContentString) => {
    const stopwords = 'a an and at but by for in nor of on or so the to up yet'
const defaults = stopwords.split(' ')

function titleCase(str, options) {
  const opts = options || {}

  if (!str) return ''

  const stop = opts.stopwords || defaults
  const keep = opts.keepSpaces
  const splitter = /(\s+|[-‑–—])/

  return str
    .split(splitter)
    .map((word, index, all) => {
      if (word.match(/\s+/)) return keep ? word : ' '
      if (word.match(splitter)) return word

      if (
        index !== 0 &&
        index !== all.length - 1 &&
        stop.includes(word.toLowerCase())
      ) {
        return word.toLowerCase()
      }

      return capitalize(word)
    })
    .join('')
}

function capitalize(str) {
  return str.charAt(0).toUpperCase() + str.slice(1)
}
   return titleCase(clipboardContentString)
}

In this example I have assigned it to a keyboard shortcut:

1 Like

Wow This Is Going to Save Me so Much Time! Thank You so Much. to Test It, I'm Going to Try to Turn All of This Into Title Case.

IT WORKED!

Edit: slight bug, after the full stop it should be a capital, any idea how to fix that?

This is super helpful! Thanks!

I'm having trouble getting this to work with a button on a floating palette. Do you happen to know if there is there any reason it wouldn't work there? (sorry to make you think about something you did three years ago!)