1// Straighten / smarten quote characters in a string. Shared by the polished 2// transcript textarea (quotes_controller) and the sermon outline editor, so the 3// two surfaces convert quotes identically. 4 5const CURLY_DOUBLE = /[âââââ³â¶]/g 6const CURLY_SINGLE = /[âââââ²âµ]/g 7 8// Curly quotes â straight ASCII. Context-free. 9export function toStraight(text) { 10 return text.replace(CURLY_DOUBLE, '"').replace(CURLY_SINGLE, "'") 11} 12 13// Straight ASCII quotes â curly "smart" quotes. Opening vs closing is decided 14// from the preceding character: start-of-text, whitespace, an opening bracket, 15// or a dash opens; anything else closes (which also yields the apostrophe in 16// contractions/possessives like don't and James'). Pass the character that 17// precedes `text` as `prevChar` so the choice stays correct across chunk 18// boundaries (inline markup, adjacent DOM text nodes). 19export function toSmart(text, prevChar = "") { 20 let out = "" 21 let prev = prevChar 22 for (const ch of text) { 23 if (ch === '"') { 24 out += opensQuote(prev) ? "â" : "â" 25 } else if (ch === "'") { 26 out += opensQuote(prev) ? "â" : "â" 27 } else { 28 out += ch 29 } 30 prev = ch 31 } 32 return out 33} 34 35function opensQuote(prev) { 36 return prev === "" || /[\s(\[{ââ]/.test(prev) 37}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.