Skip to content

Instantly share code, notes, and snippets.

@indiscripts
Created October 12, 2022 23:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save indiscripts/144e800818b830e979498940114adf5c to your computer and use it in GitHub Desktop.
Save indiscripts/144e800818b830e979498940114adf5c to your computer and use it in GitHub Desktop.
// InDesign script (DRAFT.)
//----------------------------------
// Apply some text conversion routine on consistent
// style ranges *while preserving special characters*
// (anchored objects, tables, footnotes...)
function myConverter(/*str*/text)
//----------------------------------
// Change a string into something else...
// Put your ascii-to-unicode routine here
{
return 'x' + text.split('').reverse().join('');
}
(function( doc,pp,ptn,src,rng,a,i,tx,t,x,b,j,z)
//----------------------------------
{
if( !(doc=app.properties.activeDocument) ) { alert("No document."); return; }
// Special characters that MUST be skipped.
// Footnote refs, tables, anchored objects...
// ---
const RE_SKIP = /[\u0004\u0016\uFFFC]/;
// YOUR SETTINGS
// ---
const TARGET_FAMILY_LOWER = ("Minion Pro").toLowerCase(); // E.g "nudi";
const DEST_FONT_NAME = "Myriad Pro\tItalic" // E.g "Tunga";
// Check dest font and set properties.
// ---
if( !(t=app.fonts.item(DEST_FONT_NAME)).isValid )
{ alert("The font " + DEST_FONT_NAME + " is missing."); return; }
pp =
{
contents: '',
appliedFont: t.getElements()[0],
composer: "$ID/HL Composer Optyca", // Adobe World-Ready Composer
// etc
};
// Pattern formatter.
// ---
const __ = $.global.localize;
// Array of consistently styled Text items.
// ---
a = doc.stories.everyItem().textStyleRanges.everyItem().getElements().slice();
for( i=a.length ; i-- ; )
{
// [REM] Forcing resolve is important!
// ---
tx = a[i].getElements()[0]; // tx :: Text ; consistent text range
// Filter based on font family.
// ---
t = (tx.properties.appliedFont||0).fontFamily||'';
if( -1 == t.toLowerCase().indexOf(TARGET_FAMILY_LOWER) ) continue;
// Get the last character index (x) and create a specifier
// pattern for accessing character ranges from %1 to %2.
// ---
ptn = tx.toSpecifier().split('%').join('%%'); // Safer (in case the spec contains `%`, change into `%%` for the pattern.)
ptn = ptn.split('/character['); // E.g `(/document[@id=4]//story[@id=222]`, `12] to /document[@id=4]//story[@id=222]`, `34])`
if( 3 != ptn.length || isNaN(x=parseInt(ptn[2],10)) ) continue; // Shouldn't happen.
ptn = ptn[0]+'/character[%1] to '+ptn[0].slice(1)+'/character[%2])'; // Pattern for characterRange(%1,%2)
// Split text contents w.r.t SPLIT_CHARS (U+0016, U+FFFC, etc)
// in order to preserve anchored objects and so.
// ---
t = tx.texts[0].contents + '\x01'; // [HACK] Help prevent the split(RegExp) bug (last char issue.)
b = t.split(RE_SKIP);
( t=b.length-1, b[t]=b[t].slice(0,-1) ); // [HACK] Remove \x01 suffix.
for( j=b.length ; j-- ; x-=(1+z) ) // b :: [src1, src2, src3...] ; tx.contents == `src1•src2•src3•...` where • is any INDD mark.
{
z = (src=b[j]).length; // src :: original substring ; z :: length
if( !z ) continue; // Empty -> simply jump over the mark.
rng = resolve( __(ptn, ''+(x-z+1), ''+x) ); // rng :: character range of the source (Text object.)
pp.contents = myConverter(src)||''; // Converted substring.
rng.properties = pp; // Replace.
}
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment