// **** WARNING **** // // This is a release version of the StyleCleanup.jsx script // It has been automatically collated from multiple source code files // // Apart from simple configuration changes, you should not edit // this script. // // Instead you should edit the original source code, then re-generate // this release version of the script from the updated source code // // ***************** // // StyleCleanup.jsx - a script for Adobe InDesign // // v 1.0.2, April 11, 2019 // written by Kris Coppieters, kris@rorohiko.com // https://www.linkedin.com/in/kristiaan/ // // Commissioned by NNELS (National Network for Equitable Library Service/The Canadian Accessible Library System) // // See License information at end of script. // // Check for updated versions at // // https://github.com/BCLibCoop/nnels-a11y-publishing // // --------------- // // About this script: // // This script will scan an InDesign document and find any manual text style overriddes // Manual text style overrides are not easy to spot or clean up. // // This script will help removing or restructuring these manual overrides. // // For each manual style override, the script will create a new paragraph or character // style. Once all manual overrides have been converted to styles, the user can // then delete, rename, remap,... all these styles and clean up the document. // // The makeReleaseVersion.command script will replace this to "CONFIG.jsx" instead of "CONFIG.jsx" // **** CONFIGURATION - BEGIN // Set DEBUG to 1 to enable debugging facilities embedded in this script // Set to 0 to disable var DEBUG = 0; // Set LOG_TO_CONSOLE to 1 to enable logging to ExtendScript Toolkit // JavaScript Console window. Set to 0 to disable var LOG_TO_CONSOLE = 0; // Set LOG_LEVEL to a value: 0 to 4. The higher the value, the more extensive // the log output will be // // 0 = LOG_NONE // 1 = LOG_ERROR // 2 = LOG_WARNING // 3 = LOG_NOTE // 4 = LOG_TRACE var LOG_LEVEL = 0; // Set FILE_PATH_LOG to either double-quoted file path or undefined. Examples: // // var FILE_PATH_LOG = undefined; // var FILE_PATH_LOG = "/Users/kris/Desktop/t.log"; // var FILE_PATH_LOG = "C:\\Users\\Kris Coppieters\\Desktop\\t.log"; var FILE_PATH_LOG = undefined; // Set LOG_ENTRY_EXIT to 1 to enable extensive logging on a per-function // call basis. Set to 0 to disable var LOG_ENTRY_EXIT = 0; // Set WRITE_STYLE_REPORT to 1 to enable a report file. var WRITE_STYLE_REPORT = 1; var ARTIFICIAL_PARA_STYLE_NAME_PREFIX = "ArtificialParaStyle_"; var ARTIFICIAL_CHAR_STYLE_NAME_PREFIX = "ArtificialCharStyle_"; // Flags all attributes to consider when comparing styles or style components // // If two styles are identical for these attributes, they will be // considered to be synonymous, and one of them could be considered for // elimination. // // Set to: 0 to ignore, and: 1 to consider when comparing // var ATTRIBUTES_FOR_STYLE_COMPARISONS = { ParagraphStyle: { alignToBaseline: 0, allowArbitraryHyphenation: 0, appliedFont: 1, appliedLanguage: 0, appliedNumberingList: 0, autoLeading: 0, autoTcy: 0, autoTcyIncludeRoman: 0, balanceRaggedLines: 0, basedOn: 0, baselineShift: 0, bulletChar: 0, bulletsAlignment: 0, bulletsAndNumberingListType: 0, bulletsCharacterStyle: 0, bulletsTextAfter: 0, bunriKinshi: 0, capitalization: 1, characterAlignment: 1, characterDirection: 1, characterRotation: 1, cjkGridTracking: 0, composer: 0, desiredGlyphScaling: 0, desiredLetterSpacing: 0, desiredWordSpacing: 0, diacriticPosition: 0, digitsType: 0, dropCapCharacters: 0, dropcapDetail: 0, dropCapLines: 0, dropCapStyle: 0, emitCss: 0, endJoin: 0, eventListeners: 0, events: 0, fillColor: 1, fillTint: 1, firstLineIndent: 1, fontStyle: 1, glyphForm: 0, gradientFillAngle: 0, gradientFillLength: 0, gradientFillStart: 0, gradientStrokeAngle: 0, gradientStrokeLength: 0, gradientStrokeStart: 0, gridAlignFirstLineOnly: 0, gridAlignment: 0, gridGyoudori: 0, horizontalScale: 1, hyphenateAcrossColumns: 0, hyphenateAfterFirst: 0, hyphenateBeforeLast: 0, hyphenateCapitalizedWords: 0, hyphenateLadderLimit: 0, hyphenateLastWord: 0, hyphenateWordsLongerThan: 0, hyphenation: 0, hyphenationZone: 0, hyphenWeight: 0, id: 0, ignoreEdgeAlignment: 0, imported: 0, includeClass: 0, index: 0, isValid: 0, jidori: 0, justification: 1, kashidas: 0, keepAllLinesTogether: 0, keepFirstLines: 0, keepLastLines: 0, keepLinesTogether: 0, keepRuleAboveInFrame: 0, keepWithNext: 0, keepWithPrevious: 0, kentenAlignment: 0, kentenCharacterSet: 0, kentenCustomCharacter: 0, kentenFillColor: 0, kentenFont: 0, kentenFontSize: 0, kentenFontStyle: 0, kentenKind: 0, kentenOverprintFill: 0, kentenOverprintStroke: 0, kentenPlacement: 0, kentenPosition: 0, kentenStrokeColor: 0, kentenStrokeTint: 0, kentenTint: 0, kentenWeight: 0, kentenXScale: 0, kentenYScale: 0, kerningMethod: 0, keyboardDirection: 0, kinsokuHangType: 0, kinsokuSet: 0, kinsokuType: 0, label: 0, lastLineIndent: 1, leading: 1, leadingAki: 0, leadingModel: 0, leftIndent: 1, ligatures: 0, maximumGlyphScaling: 0, maximumLetterSpacing: 0, maximumWordSpacing: 0, mergeConsecutiveParaBorders: 0, minimumGlyphScaling: 0, minimumLetterSpacing: 0, minimumWordSpacing: 0, miterLimit: 0, mojikumi: 0, name: 0, nestedGrepStyles: 0, nestedLineStyles: 0, nestedStyles: 0, nextStyle: 0, noBreak: 0, numberingAlignment: 0, numberingApplyRestartPolicy: 0, numberingCharacterStyle: 0, numberingContinue: 0, numberingExpression: 0, numberingFormat: 0, numberingLevel: 0, numberingRestartPolicies: 0, numberingStartAt: 0, otfContextualAlternate: 0, otfDiscretionaryLigature: 0, otfFigureStyle: 0, otfFraction: 0, otfHistorical: 0, otfHVKana: 0, otfJustificationAlternate: 0, otfLocale: 0, otfMark: 0, otfOrdinal: 0, otfOverlapSwash: 0, otfProportionalMetrics: 0, otfRomanItalics: 0, otfSlashedZero: 0, otfStretchedAlternate: 0, otfStylisticAlternate: 0, otfStylisticSets: 0, otfSwash: 0, otfTitling: 0, overprintFill: 0, overprintStroke: 0, paragraphBorderBottomLeftCornerOption: 0, paragraphBorderBottomLeftCornerRadius: 0, paragraphBorderBottomLineWeight: 0, paragraphBorderBottomOffset: 0, paragraphBorderBottomOrigin: 0, paragraphBorderBottomRightCornerOption: 0, paragraphBorderBottomRightCornerRadius: 0, paragraphBorderColor: 0, paragraphBorderDisplayIfSplits: 0, paragraphBorderGapColor: 0, paragraphBorderGapOverprint: 0, paragraphBorderGapTint: 0, paragraphBorderLeftLineWeight: 0, paragraphBorderLeftOffset: 0, paragraphBorderOn: 0, paragraphBorderOverprint: 0, paragraphBorderRightLineWeight: 0, paragraphBorderRightOffset: 0, paragraphBorderStrokeEndCap: 0, paragraphBorderStrokeEndJoin: 0, paragraphBorderTint: 0, paragraphBorderTopLeftCornerOption: 0, paragraphBorderTopLeftCornerRadius: 0, paragraphBorderTopLineWeight: 0, paragraphBorderTopOffset: 0, paragraphBorderTopOrigin: 0, paragraphBorderTopRightCornerOption: 0, paragraphBorderTopRightCornerRadius: 0, paragraphBorderType: 0, paragraphBorderWidth: 0, paragraphDirection: 0, paragraphGyoudori: 0, paragraphJustification: 1, paragraphKashidaWidth: 0, paragraphShadingBottomLeftCornerOption: 0, paragraphShadingBottomLeftCornerRadius: 0, paragraphShadingBottomOffset: 0, paragraphShadingBottomOrigin: 0, paragraphShadingBottomRightCornerOption: 0, paragraphShadingBottomRightCornerRadius: 0, paragraphShadingClipToFrame: 0, paragraphShadingColor: 0, paragraphShadingLeftOffset: 0, paragraphShadingOn: 0, paragraphShadingOverprint: 0, paragraphShadingRightOffset: 0, paragraphShadingSuppressPrinting: 0, paragraphShadingTint: 0, paragraphShadingTopLeftCornerOption: 0, paragraphShadingTopLeftCornerRadius: 0, paragraphShadingTopOffset: 0, paragraphShadingTopOrigin: 0, paragraphShadingTopRightCornerOption: 0, paragraphShadingTopRightCornerRadius: 0, paragraphShadingWidth: 0, parent: 0, pointSize: 1, position: 0, positionalForm: 0, preferences: 0, previewColor: 0, properties: 0, providerHyphenationStyle: 0, rensuuji: 0, rightIndent: 1, rotateSingleByteCharacters: 0, rubyAlignment: 0, rubyAutoAlign: 0, rubyAutoScaling: 0, rubyAutoTcyAutoScale: 0, rubyAutoTcyDigits: 0, rubyAutoTcyIncludeRoman: 0, rubyFill: 0, rubyFont: 0, rubyFontSize: 0, rubyFontStyle: 0, rubyOpenTypePro: 0, rubyOverhang: 0, rubyOverprintFill: 0, rubyOverprintStroke: 0, rubyParentOverhangAmount: 0, rubyParentScalingPercent: 0, rubyParentSpacing: 0, rubyPosition: 0, rubyStroke: 0, rubyStrokeTint: 0, rubyTint: 0, rubyType: 0, rubyWeight: 0, rubyXOffset: 0, rubyXScale: 0, rubyYOffset: 0, rubyYScale: 0, ruleAbove: 1, ruleAboveColor: 0, ruleAboveGapColor: 0, ruleAboveGapOverprint: 0, ruleAboveGapTint: 0, ruleAboveLeftIndent: 0, ruleAboveLineWeight: 0, ruleAboveOffset: 0, ruleAboveOverprint: 0, ruleAboveRightIndent: 0, ruleAboveTint: 0, ruleAboveType: 0, ruleAboveWidth: 0, ruleBelow: 1, ruleBelowColor: 0, ruleBelowGapColor: 0, ruleBelowGapOverprint: 0, ruleBelowGapTint: 0, ruleBelowLeftIndent: 0, ruleBelowLineWeight: 0, ruleBelowOffset: 0, ruleBelowOverprint: 0, ruleBelowRightIndent: 0, ruleBelowTint: 0, ruleBelowType: 0, ruleBelowWidth: 0, sameParaStyleSpacing: 0, scaleAffectsLineHeight: 0, shataiAdjustRotation: 0, shataiAdjustTsume: 0, shataiDegreeAngle: 0, shataiMagnification: 0, singleWordJustification: 0, skew: 0, spaceAfter: 1, spaceBefore: 1, spanColumnMinSpaceAfter: 0, spanColumnMinSpaceBefore: 0, spanColumnType: 0, spanSplitColumnCount: 0, splitColumnInsideGutter: 0, splitColumnOutsideGutter: 0, splitDocument: 0, startParagraph: 0, strikeThroughColor: 0, strikeThroughGapColor: 0, strikeThroughGapOverprint: 0, strikeThroughGapTint: 0, strikeThroughOffset: 0, strikeThroughOverprint: 0, strikeThroughTint: 0, strikeThroughType: 0, strikeThroughWeight: 0, strikeThru: 0, strokeAlignment: 0, strokeColor: 0, strokeTint: 0, strokeWeight: 0, styleExportTagMaps: 0, styleUniqueId: 0, tabList: 0, tabStops: 0, tatechuyoko: 0, tatechuyokoXOffset: 0, tatechuyokoYOffset: 0, tracking: 0, trailingAki: 0, treatIdeographicSpaceAsSpace: 0, tsume: 0, underline: 1, underlineColor: 0, underlineGapColor: 0, underlineGapOverprint: 0, underlineGapTint: 0, underlineOffset: 0, underlineOverprint: 0, underlineTint: 0, underlineType: 0, underlineWeight: 0, verticalScale: 1, warichu: 0, warichuAlignment: 0, warichuCharsAfterBreak: 0, warichuCharsBeforeBreak: 0, warichuLines: 0, warichuLineSpacing: 0, warichuSize: 0, xOffsetDiacritic: 0, yOffsetDiacritic: 0 }, CharacterStyle: { appliedFont: 1, appliedLanguage: 0, basedOn: 0, baselineShift: 0, capitalization: 1, characterAlignment: 1, characterDirection: 1, characterRotation: 1, cjkGridTracking: 0, diacriticPosition: 0, digitsType: 0, emitCss: 0, endJoin: 0, eventListeners: 0, events: 0, fillColor: 1, fillTint: 1, fontStyle: 1, glyphForm: 0, gradientFillAngle: 0, gradientFillLength: 0, gradientFillStart: 0, gradientStrokeAngle: 0, gradientStrokeLength: 0, gradientStrokeStart: 0, horizontalScale: 1, id: 0, imported: 0, includeClass: 0, index: 0, isValid: 0, jidori: 0, kashidas: 0, kentenAlignment: 0, kentenCharacterSet: 0, kentenCustomCharacter: 0, kentenFillColor: 0, kentenFont: 0, kentenFontSize: 0, kentenFontStyle: 0, kentenKind: 0, kentenOverprintFill: 0, kentenOverprintStroke: 0, kentenPlacement: 0, kentenPosition: 0, kentenStrokeColor: 0, kentenStrokeTint: 0, kentenTint: 0, kentenWeight: 0, kentenXScale: 0, kentenYScale: 0, kerningMethod: 0, keyboardDirection: 0, label: 0, leading: 1, leadingAki: 0, ligatures: 0, miterLimit: 0, name: 0, noBreak: 0, otfContextualAlternate: 0, otfDiscretionaryLigature: 0, otfFigureStyle: 0, otfFraction: 0, otfHistorical: 0, otfHVKana: 0, otfJustificationAlternate: 0, otfLocale: 0, otfMark: 0, otfOrdinal: 0, otfOverlapSwash: 0, otfProportionalMetrics: 0, otfRomanItalics: 0, otfSlashedZero: 0, otfStretchedAlternate: 0, otfStylisticAlternate: 0, otfStylisticSets: 0, otfSwash: 0, otfTitling: 0, overprintFill: 0, overprintStroke: 0, parent: 0, pointSize: 1, position: 0, positionalForm: 0, previewColor: 0, properties: 0, rubyAlignment: 0, rubyAutoAlign: 0, rubyAutoScaling: 0, rubyAutoTcyAutoScale: 0, rubyAutoTcyDigits: 0, rubyAutoTcyIncludeRoman: 0, rubyFill: 0, rubyFont: 0, rubyFontSize: 0, rubyFontStyle: 0, rubyOpenTypePro: 0, rubyOverhang: 0, rubyOverprintFill: 0, rubyOverprintStroke: 0, rubyParentOverhangAmount: 0, rubyParentScalingPercent: 0, rubyParentSpacing: 0, rubyPosition: 0, rubyStroke: 0, rubyStrokeTint: 0, rubyTint: 0, rubyType: 0, rubyWeight: 0, rubyXOffset: 0, rubyXScale: 0, rubyYOffset: 0, rubyYScale: 0, scaleAffectsLineHeight: 0, shataiAdjustRotation: 0, shataiAdjustTsume: 0, shataiDegreeAngle: 0, shataiMagnification: 0, skew: 0, splitDocument: 0, strikeThroughColor: 0, strikeThroughGapColor: 0, strikeThroughGapOverprint: 0, strikeThroughGapTint: 0, strikeThroughOffset: 0, strikeThroughOverprint: 0, strikeThroughTint: 0, strikeThroughType: 0, strikeThroughWeight: 0, strikeThru: 0, strokeAlignment: 0, strokeColor: 0, strokeTint: 0, strokeWeight: 0, styleExportTagMaps: 0, styleUniqueId: 0, tatechuyoko: 0, tatechuyokoXOffset: 0, tatechuyokoYOffset: 0, tracking: 0, trailingAki: 0, tsume: 0, underline: 1, underlineColor: 0, underlineGapColor: 0, underlineGapOverprint: 0, underlineGapTint: 0, underlineOffset: 0, underlineOverprint: 0, underlineTint: 0, underlineType: 0, underlineWeight: 0, verticalScale: 1, warichu: 0, warichuAlignment: 0, warichuCharsAfterBreak: 0, warichuCharsBeforeBreak: 0, warichuLines: 0, warichuLineSpacing: 0, warichuSize: 0, xOffsetDiacritic: 0, yOffsetDiacritic: 0 } }; // **** CONFIGURATION - END // // LOG.jsx - an ExtendScript shared module for Adobe InDesign // // v 1.0.0, March 23, 2019 // written by Kris Coppieters, kris@rorohiko.com // https://www.linkedin.com/in/kristiaan/ // // Commissioned by NNELS (National Network for Equitable Library Service/The Canadian Accessible Library System) // // See License information at end of script. // // Check for source code at // // https://github.com/BCLibCoop/nnels-a11y-publishing // // --------------- // // About this module // // This module provides logging facilities for ExtendScript code // var LOG; if (! LOG) { (function() { // -- LOG = {}; LOG.LOG_NONE = 0; LOG.LOG_ERROR = 1; LOG.LOG_WARNING = 2; LOG.LOG_NOTE = 3; LOG.LOG_TRACE = 4; LOG.LOG_TO_CONSOLE = false; LOG.LOG_LEVEL = LOG.LOG_NONE; LOG.LOG_ENTRY_EXIT = false; LOG.FILE_PATH_LOG = undefined; // File path or undefined LOG.logMessage = function(in_message) { if (! LOG.busyWriting) { LOG.busyWriting = true; try { if (LOG.LOG_TO_CONSOLE) { $.writeln(in_message); } if (LOG.FILE_PATH_LOG) { var f = File(LOG.FILE_PATH_LOG); f.open("a"); f.writeln(in_message); f.close(); } } catch (err) { } LOG.busyWriting = false; } }; LOG.logError = function(in_message) { if (LOG.LOG_LEVEL >= LOG.LOG_ERROR) { LOG.logMessage("ERROR: " + in_message); } }; LOG.logWarning = function(in_message) { if (LOG.LOG_LEVEL >= LOG.LOG_WARNING) { LOG.logMessage("WARN : " + in_message); } }; LOG.logNote = function(in_message) { if (LOG.LOG_LEVEL >= LOG.LOG_NOTE) { LOG.logMessage("NOTE : " + in_message); } }; LOG.logTrace = function(in_message) { if (LOG.LOG_LEVEL >= LOG.LOG_TRACE) { LOG.logMessage("TRACE: " + in_message); } }; LOG.logEntry = function(in_functionName) { if (LOG.LOG_ENTRY_EXIT) { LOG.logTrace("ENTRY: " + in_functionName); } }; LOG.logExit = function(in_functionName) { if (LOG.LOG_ENTRY_EXIT) { LOG.logTrace("EXIT : " + in_functionName); } }; // -- })();} /************************************************************* LOG.jsx (c) 2019 NNELS, The National Network for Equitable Library Service (formerly, CALS, The Canadian Accessible Library System) https://nnels.ca This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . Neither the name of NNELS, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. ============================================== */ // // UTILS.jsx - an ExtendScript shared module for Adobe InDesign // // v 1.0.0, March 23, 2019 // written by Kris Coppieters, kris@rorohiko.com // https://www.linkedin.com/in/kristiaan/ // // Commissioned by NNELS (National Network for Equitable Library Service/The Canadian Accessible Library System) // // See License information at end of script. // // Check for source code at // // https://github.com/BCLibCoop/nnels-a11y-publishing // // --------------- // // About this module // // This module provides some additional utility functions for ExtendScript code // var UTILS; if (DEBUG) { UTILS = undefined; } if (! UTILS) { (function() { // -- UTILS = {}; UTILS.REGEXP_EXTRACT_FUNCTION_NAME = /function (.{1,})\(/; UTILS.REGEXP_SPACES = /\s/g; UTILS.shortenedString = function(in_s, in_targetLength) { var retVal; LOG.logEntry("UTILS.shortenedString"); try { if (in_s.length <= in_targetLength) { retVal = in_s; } else { var splitLen = Math.trunc((in_targetLen - 3) / 2); retVal = in_s.substr(0, splitLen) + "..." + in_s.substr(-splitLen); } } catch (err) { LOG.logError("UTILS.shortenedString: throws " + err); } LOG.logExit("UTILS.shortenedString"); return retVal; } UTILS.baseName = function(in_filePath, in_separator) { var retVal = undefined; LOG.logEntry("UTILS.baseName"); try { if (! in_separator) { in_separator = UTILS.SEPARATOR; } LOG.logNote("UTILS.baseName: using separator " + in_separator); // toString() handles cases where in_filePath is an ExtendScript File/Folder object var splitPath = in_filePath.toString().split(in_separator); do { var endSegment = splitPath.pop(); } while (splitPath.length > 0 && endSegment == ""); retVal = endSegment; } catch (err) { LOG.logError("UTILS.baseName: throws " + err); retVal = undefined; } return retVal; }; UTILS.checkMac = function() { var retVal = $.os.substr(0,3) == "Mac"; return retVal; }; UTILS.deepClone = function(in_obj) { var retVal = undefined; LOG.logEntry("UTILS.deepClone"); try { if (in_obj instanceof Array) { retVal = []; } else { retVal = {}; } for (var x in in_obj) { var val = in_obj[x]; if (typeof val == "object") { retVal[x] = UTILS.deepClone(val); } else { retVal[x] = val; } } } catch (err) { LOG.logError("UTILS.deepClone: throws " + err); retVal = undefined; } LOG.logExit("UTILS.deepClone"); return retVal; }; UTILS.despace = function(s) { var retVal = s.replace(UTILS.REGEXP_SPACES, ""); return retVal; }; UTILS.dirName = function(in_filePath, in_separator) { var retVal = undefined; LOG.logEntry("UTILS.dirName"); try { if (! in_separator) { in_separator = UTILS.SEPARATOR; } LOG.logNote("UTILS.dirName: using in_separator " + in_separator); // toString() handles cases where in_filePath is an ExtendScript File/Folder object var splitPath = in_filePath.toString().split(in_separator); do { var endSegment = splitPath.pop(); } while (splitPath.length > 0 && endSegment == ""); retVal = splitPath.join(in_separator) + in_separator; } catch (err) { LOG.logError("UTILS.dirName: throws " + err); } LOG.logExit("UTILS.dirName"); return retVal; }; UTILS.dQ = function(in_s) { var retVal = '"' + in_s.replace(/\\/g,"\\\\").replace(/"/g,'\\"') + '"'; return retVal; }; UTILS.endsWith = function(in_s, in_end) { var retVal = in_s.substr(-in_end.length) == in_end; return retVal; }; UTILS.exists = function(in_filePath) { var f = File(in_filePath); var retVal = f.exists; return retVal; }; UTILS.fileNameExtension = function(in_filePath, in_separator) { var retVal = ""; LOG.logEntry("UTILS.fileNameExtension"); try { var splitName = UTILS.baseName(in_filePath, in_separator).split("."); if (splitName.length > 1) { retVal = splitName.pop(); retVal = retVal.toLowerCase(); } } catch (err) { LOG.logError("UTILS.fileNameExtension: throws " + err); } LOG.logExit("UTILS.fileNameExtension"); return retVal; }; UTILS.getClassName = function(in_object) { var retVal; LOG.logEntry("UTILS.getClassName"); do { try { if ("object" != typeof in_object) { LOG.logError("UTILS.getClassName: in_object is not an object"); break; } if (! in_object) { LOG.logError("UTILS.getClassName: no in_object"); break; } var match = UTILS.REGEXP_EXTRACT_FUNCTION_NAME.exec(in_object.constructor.toString()); retVal = (match && match.length > 1) ? match[1] : ""; } catch (err) { LOG.logError("UTILS.getClassName: throws " + err); } } while (false); LOG.logExit("UTILS.getClassName"); return retVal; }; UTILS.hashCode = function(in_s) { LOG.logEntry("UTILS.hashCode"); var hash = 0; do { try { if (! in_s.length) { break; } for (var i = 0; i < in_s.length; i++) { var chr = in_s.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // Convert to 32bit integer } } catch (err) { LOG.logError("UTILS.hashCode: throws " + err); } } while (false); LOG.logExit("UTILS.hashCode"); return hash; }; UTILS.isDir = function(in_folderPath) { // This casts to a File instead of a Folder if the // path references a file var folder = Folder(in_folderPath); var retVal = (folder instanceof Folder); return retVal; }; UTILS.mkdir = function(in_folderPath, in_separator) { var success = false; do { try { if (! in_folderPath) { LOG.logError("UTILS.mkdir: no in_folderPath"); break; } if (UTILS.exists(in_folderPath)) { success = true; break; } var parentFolderPath = UTILS.dirName(in_folderPath, in_separator); success = UTILS.mkdir(parentFolderPath, in_separator); if (! success) { LOG.logError("UTILS.mkdir: cannot create parent folder"); break; } var folder = Folder(in_folderPath); folder.create(); success = folder.exists; } catch (err) { LOG.logError("UTILS.mkdir throws" + err); } } while (false); return success; }; UTILS.shallowClone = function(in_obj) { var retVal = {}; for (var x in in_obj) { retVal[x] = in_obj[x]; } return retVal; } UTILS.startsWith = function(in_s, in_start) { var retVal = in_s.substr(0, in_start.length) == in_start; return retVal; }; UTILS.stripFileNameExtension = function(in_filePath, in_separator) { var retVal = in_filePath; do { try { var fileNameExtension = UTILS.fileNameExtension(in_filePath); if (! fileNameExtension) { break; } retVal = in_filePath.substr(0, in_filePath.length - fileNameExtension.length - 1); } catch (err) { LOG.logError("UTILS.stripFileNameExtension: throws " + err); } } while (false); return retVal; } if (UTILS.checkMac()) { UTILS.SEPARATOR = "/"; UTILS.isMac = true; UTILS.isWindows = false; } else { UTILS.SEPARATOR = "\\"; UTILS.isMac = false; UTILS.isWindows = true; } // -- })();} /************************************************************* UTILS.jsx (c) 2019 NNELS, The National Network for Equitable Library Service (formerly, CALS, The Canadian Accessible Library System) https://nnels.ca This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . Neither the name of NNELS, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. ============================================== */ var STYC; if (DEBUG) { // Clear persistent code on each run when debugging STYC = undefined; } if (! STYC) { STYC = {}; (function() { // ---- STYC.addToCharacterStyleLookup = function(io_context, in_characterStyle, in_definingTextStyleRangeHash) { var success = false; LOG.logEntry("STYC.addToCharacterStyleLookup"); do { try { if (! io_context) { LOG.logError("STYC.addToCharacterStyleLookup: no io_context"); break; } if (! (in_characterStyle instanceof CharacterStyle)) { LOG.logError("STYC.addToCharacterStyleLookup: no in_characterStyle"); break; } success = true; var characterStyleHash = STYC.inDesignElementHash(io_context, in_characterStyle); if (! characterStyleHash) { break; } if (! io_context.characterStylesByHash) { io_context.characterStylesByHash = {}; } var characterStyleByHashString = io_context.characterStylesByHash[characterStyleHash.hash]; if (! characterStyleByHashString) { characterStyleByHashString = {}; io_context.characterStylesByHash[characterStyleHash.hash] = characterStyleByHashString; } var characterStylesByName = characterStyleByHashString[characterStyleHash.string]; if (! characterStylesByName) { characterStylesByName = {}; characterStyleByHashString[characterStyleHash.string] = characterStylesByName; } characterStylesByName[in_characterStyle.name] = in_characterStyle; if (! in_definingTextStyleRangeHash) { break; } if (! io_context.artificialCharacterStylesByDefiningTextStyleRangeHashString) { io_context.artificialCharacterStylesByDefiningTextStyleRangeHashString = {}; } io_context.artificialCharacterStylesByDefiningTextStyleRangeHashString[in_definingTextStyleRangeHash.string] = in_characterStyle; } catch (err) { LOG.logError("STYC.addToCharacterStyleLookup: throws " + err); } } while (false); LOG.logExit("STYC.addToCharacterStyleLookup"); return success; } STYC.addToParagraphStyleLookup = function(io_context, in_paragraphStyle, in_isArtificial) { var success = false; LOG.logEntry("STYC.addToParagraphStyleLookup"); do { try { if (! io_context) { LOG.logError("STYC.addToParagraphStyleLookup: no io_context"); break; } if (! (in_paragraphStyle instanceof ParagraphStyle)) { LOG.logError("STYC.addToParagraphStyleLookup: no in_paragraphStyle"); break; } success = true; var paragraphStyleHash = STYC.inDesignElementHash(io_context, in_paragraphStyle); if (! paragraphStyleHash) { break; } if (! io_context.paragraphStyleLookup) { io_context.paragraphStyleLookup = {}; } var paragraphStyleByHashString = io_context.paragraphStyleLookup[paragraphStyleHash.hash]; if (! paragraphStyleByHashString) { paragraphStyleByHashString = {}; io_context.paragraphStyleLookup[paragraphStyleHash.hash] = paragraphStyleByHashString; } var paragraphStylesByName = paragraphStyleByHashString[paragraphStyleHash.string]; if (! paragraphStylesByName) { paragraphStylesByName = {}; paragraphStyleByHashString[paragraphStyleHash.string] = paragraphStylesByName; } paragraphStylesByName[in_paragraphStyle.name] = in_paragraphStyle; if (! in_isArtificial) { break; } if (! io_context.artificialParagraphStylesByHashString) { io_context.artificialParagraphStylesByHashString = {}; } io_context.artificialParagraphStylesByHashString[paragraphStyleHash.string] = in_paragraphStyle; } catch (err) { LOG.logError("STYC.addToParagraphStyleLookup: throws " + err); } } while (false); LOG.logExit("STYC.addToParagraphStyleLookup"); return success; } STYC.appendLineToReport = function(io_context, in_line) { LOG.logEntry("STYC.appendLineToReport"); do { try { if (! io_context) { LOG.logError("STYC.appendLineToReport: no io_context"); break; } if (! io_context.report) { io_context.report = ""; } if (! in_line) { in_line = ""; } io_context.report += in_line + "\n"; } catch (err) { LOG.logError("STYC.appendLineToReport: throws " + err); } } while (false); LOG.logExit("STYC.appendLineToReport"); } STYC.buildCharacterStyleLookup = function(io_context) { var success = false; LOG.logEntry("STYC.buildCharacterStyleLookup"); do { try { if (! io_context) { LOG.logError("STYC.buildCharacterStyleLookup: no io_context"); break; } var doc = io_context.doc; if (! (doc instanceof Document)) { LOG.logError("STYC.buildCharacterStyleLookup: no doc"); break; } success = true; var characterStyles = doc.characterStyles; if (! characterStyles || characterStyles.length == 0) { LOG.logWarning("STYC.buildCharacterStyleLookup: doc contains no character styles"); break; } for (var characterStyleIdx = 0; characterStyleIdx < characterStyles.length; characterStyleIdx++) { var characterStyle = characterStyles.item(characterStyleIdx); STYC.addToCharacterStyleLookup(io_context, characterStyle); } } catch (err) { LOG.logError("STYC.buildCharacterStyleLookup: throws " + err); } } while (false); LOG.logExit("STYC.buildCharacterStyleLookup"); return success; } STYC.buildParagraphStyleLookup = function(io_context) { var success = false; LOG.logEntry("STYC.buildParagraphStyleLookup"); do { try { if (! io_context) { LOG.logError("STYC.buildParagraphStyleLookup: no io_context"); break; } var doc = io_context.doc; if (! (doc instanceof Document)) { LOG.logError("STYC.buildParagraphStyleLookup: no doc"); break; } success = true; var paragraphStyles = doc.paragraphStyles; if (! paragraphStyles || paragraphStyles.length == 0) { LOG.logWarning("STYC.buildParagraphStyleLookup: doc contains no paragraph styles"); break; } for (var paragraphStyleIdx = 0; paragraphStyleIdx < paragraphStyles.length; paragraphStyleIdx++) { var paragraphStyle = paragraphStyles.item(paragraphStyleIdx); STYC.addToParagraphStyleLookup(io_context, paragraphStyle); } } catch (err) { LOG.logError("STYC.buildParagraphStyleLookup: throws " + err); } } while (false); LOG.logExit("STYC.buildParagraphStyleLookup"); return success; } STYC.equalHashes = function(in_hash1, in_hash2) { var retVal = false; LOG.logEntry("STYC.equalHashes"); do { if (in_hash1 && ! in_hash2) { break; } if (in_hash2 && ! in_hash1) { break; } if (! in_hash1 && ! in_hash2) { retVal = true; break; } retVal = in_hash1.hash == in_hash2.hash && in_hash1.string == in_hash2.string; } while (false); LOG.logExit("STYC.equalHashes"); return retVal; } STYC.generateCharacterStyleReport = function(io_context) { var success = false; LOG.logEntry("STYC.generateCharacterStyleReport"); try { success = true; var styleReportState = 0; var styleGroupNumber = 0; for (var hashCode in io_context.characterStylesByHash) { var characterStyleByHashString = io_context.characterStylesByHash[hashCode]; for (var hashString in characterStyleByHashString) { var characterStylesByName = characterStyleByHashString[hashString]; var styleGroupState = 0; var styleGroupReportBuffer = ""; // Do not write groups with just one style for (var styleName in characterStylesByName) { if (styleGroupState == 0) { styleGroupState = 1; styleGroupNumber++; styleGroupReportBuffer += "### Character Style Group " + styleGroupNumber + "\n"; styleGroupReportBuffer += " " + styleName; } else { if (styleGroupState == 1) { styleGroupState = 2; if (styleReportState == 0) { styleReportState = 1; STYC.appendLineToReport(io_context, "## Character Style Report"); } STYC.appendLineToReport(io_context, styleGroupReportBuffer); } STYC.appendLineToReport(io_context, " " + styleName); } } if (styleGroupState == 2) { STYC.appendLineToReport(io_context); } } } if (styleReportState == 0) { STYC.appendLineToReport(io_context, "## Character Style Report: no synonyms found"); } } catch (err) { LOG.logError("STYC.generateCharacterStyleReport: throws " + err); } LOG.logExit("STYC.generateCharacterStyleReport"); return success; } STYC.generateParagraphStyleReport = function(io_context) { var success = false; LOG.logEntry("STYC.generateParagraphStyleReport"); try { success = true; var styleReportState = 0; var styleGroupNumber = 0; for (var hashCode in io_context.paragraphStyleLookup) { var paragraphStyleByHashString = io_context.paragraphStyleLookup[hashCode]; for (var hashString in paragraphStyleByHashString) { var paragraphStylesByName = paragraphStyleByHashString[hashString]; var styleGroupState = 0; var styleGroupReportBuffer = ""; // Do not write groups with just one style for (var styleName in paragraphStylesByName) { if (styleGroupState == 0) { styleGroupState = 1; styleGroupNumber++; styleGroupReportBuffer += "### Paragraph Style Group " + styleGroupNumber + "\n"; styleGroupReportBuffer += " " + styleName; } else { if (styleGroupState == 1) { styleGroupState = 2; if (styleReportState == 0) { styleReportState = 1; STYC.appendLineToReport(io_context, "## Paragraph Style Report"); } STYC.appendLineToReport(io_context, styleGroupReportBuffer); } STYC.appendLineToReport(io_context, " " + styleName); } } if (styleGroupState == 2) { STYC.appendLineToReport(io_context); } } } if (styleReportState == 0) { STYC.appendLineToReport(io_context, "## Paragraph Style Report: no synonyms found"); } } catch (err) { LOG.logError("STYC.generateParagraphStyleReport: throws " + err); } LOG.logExit("STYC.generateParagraphStyleReport"); return success; } STYC.inDesignElementHash = function(io_context, in_element) { function wrapHash(hashString) { return { hash: UTILS.hashCode(hashString), string: hashString }; } var retVal = undefined; LOG.logEntry("STYC.inDesignElementHash"); do { try { if (! io_context) { LOG.logError("STYC.inDesignElementHash: no io_context"); break; } if (in_element === undefined) { LOG.logError("STYC.inDesignElementHash: no in_element"); break; } if ("number" == typeof in_element) { retVal = wrapHash("N:" + in_element); break; } if ("string" == typeof in_element) { retVal = wrapHash('S:"' + in_element + '"'); break; } if ("boolean" == typeof in_element) { retVal = wrapHash(in_element ? "T" : "F"); break; } if (in_element === null) { retVal = wrapHash("n"); break; } if (in_element === undefined) { retVal = wrapHash("U"); break; } if (in_element instanceof Enumerator) { retVal = wrapHash("E:" + (in_element + 0).toString(16)); break; } if ("id" in in_element) { if (! io_context.hashCache) { io_context.hashCache = {}; } if (in_element.id in io_context.hashCache) { retVal = io_context.hashCache[in_element.id]; break; } } if ("isValid" in in_element && ! in_element.isValid) { break; } var className = UTILS.getClassName(in_element); var attributesForComparison = undefined; if (className in ATTRIBUTES_FOR_STYLE_COMPARISONS) { attributesForComparison = ATTRIBUTES_FOR_STYLE_COMPARISONS[className]; } if ("id" in in_element && className != "ParagraphStyle" && className != "CharacterStyle" && className != "TextStyleRange") { retVal = wrapHash("ID:" + in_element.id); break; } for (var attr in in_element) { do { try { if (attributesForComparison && ! attributesForComparison[attr]) { break; } if (attr == "properties" || attr == "isValid" || attr == "index" || UTILS.startsWith(attr, "parent")) { break; } var attrValue = in_element[attr]; var elementAttrHash = STYC.inDesignElementHash(io_context, attrValue); if (elementAttrHash) { if (! retVal) { retVal = ""; } retVal += "[" + attr + "]=" + elementAttrHash.string + ";"; } } catch (err) { LOG.logNote("STYC.inDesignElementHash: cannot access " + attr); } } while (false); } if (! retVal) { break; } retVal = wrapHash(retVal); if ("id" in in_element) { io_context.hashCache[in_element.id] = retVal; } } catch (err) { LOG.logError("STYC.inDesignElementHash: throws " + err); } } while (false); LOG.logExit("STYC.inDesignElementHash"); return retVal; } STYC.main = function() { LOG.logEntry("STYC.main"); do { try { if (! app.documents.length || !(app.activeDocument instanceof Document)) { LOG.logWarning("STYC.main: no documents open"); alert("Please make sure you have a document open."); break; } var context = {}; context.doc = app.activeDocument; var success = STYC.styleCleanup(context); if (success) { alert("StyleCleanup completed."); } else { alert("StyleCleanup was attempted, but some problems occurred."); } } catch (err) { LOG.logError("STYC.main: throws " + err); } } while (false); LOG.logExit("STYC.main"); } STYC.storyParagraphCleanup = function(io_context, in_paragraph) { var success = false; LOG.logEntry("STYC.storyParagraphCleanup"); do { try { if (! io_context) { LOG.logError("STYC.storyParagraphCleanup: no io_context"); break; } if (! (in_paragraph instanceof Paragraph)) { LOG.logError("STYC.storyParagraphCleanup: no in_story"); break; } if (! in_paragraph.isValid) { LOG.logError("STYC.storyParagraphCleanup: invalid in_paragraph"); break; } var doc = io_context.doc; if (! (doc instanceof Document)) { LOG.logError("STYC.storyParagraphCleanup: no doc"); break; } success = true; if (! in_paragraph.textHasOverrides(StyleType.PARAGRAPH_STYLE_TYPE, false)) { break; } var hasRelevantDifferences = false; for (var attr in ATTRIBUTES_FOR_STYLE_COMPARISONS.ParagraphStyle) { if (ATTRIBUTES_FOR_STYLE_COMPARISONS.ParagraphStyle[attr]) { if (in_paragraph[attr] != in_paragraph.appliedParagraphStyle[attr]) { hasRelevantDifferences = true; break; // exit for } } } if (! hasRelevantDifferences) { // Paragraph has manual overrides, but they are irrelevant for our purposes LOG.logNote("STYC.storyParagraphCleanup: clearing in_paragraph overrides"); STYC.appendLineToReport(io_context, "Cleared manual paragraph style overrides on paragraph with text:\n" + '"' + UTILS.shortenedString(in_paragraph.contents, 100)) + '"'; break; } if (! io_context.paragraphCleanupBatch) { io_context.paragraphCleanupBatch = []; } var newParagraphStyleHash = STYC.inDesignElementHash(io_context, in_paragraph); if (io_context.artificialParagraphStylesByHashString && io_context.artificialParagraphStylesByHashString[newParagraphStyleHash.string]) { var reusedArificialParagraphStyle = io_context.artificialParagraphStylesByHashString[newParagraphStyleHash.string]; io_context.paragraphCleanupBatch.push({ paragraph: in_paragraph, paraStyle: reusedArificialParagraphStyle }); break; } if (! io_context.paragraphStyleCounter) { io_context.paragraphStyleCounter = 0; } io_context.paragraphStyleCounter++; var paraStyle; var name = ARTIFICIAL_PARA_STYLE_NAME_PREFIX + io_context.paragraphStyleCounter; do { paraStyle = doc.paragraphStyles.itemByName(name); if (paraStyle && ! paraStyle.isValid) { paraStyle = null; } if (paraStyle) { io_context.paragraphStyleCounter++; name = ARTIFICIAL_PARA_STYLE_NAME_PREFIX + io_context.paragraphStyleCounter; } } while (paraStyle); var properties = {}; properties.name = name; properties.basedOn = in_paragraph.appliedParagraphStyle; for (var attr in ATTRIBUTES_FOR_STYLE_COMPARISONS.ParagraphStyle) { if (ATTRIBUTES_FOR_STYLE_COMPARISONS.ParagraphStyle[attr]) { if (in_paragraph[attr] != in_paragraph.appliedParagraphStyle[attr]) { properties[attr] = in_paragraph[attr]; } } } var newArtificialParagraphStyle = doc.paragraphStyles.add(properties); STYC.addToParagraphStyleLookup(io_context, newArtificialParagraphStyle, true); io_context.paragraphCleanupBatch.push({ paragraph: in_paragraph, paraStyle: newArtificialParagraphStyle }); } catch (err) { LOG.logError("STYC.storyParagraphCleanup: throws " + err); } } while (false); LOG.logExit("STYC.storyParagraphCleanup"); return success; } STYC.storyParagraphsCleanup = function(io_context, in_story) { var success = false; LOG.logEntry("STYC.storyParagraphsCleanup"); do { try { if (! io_context) { LOG.logError("STYC.storyParagraphsCleanup: no io_context"); break; } if (! (in_story instanceof Story)) { LOG.logError("STYC.storyParagraphsCleanup: no in_story"); break; } success = true; var paragraphs = in_story.paragraphs; for (var paragraphIdx = 0; paragraphIdx < paragraphs.length; paragraphIdx++) { var paragraph = paragraphs.item(paragraphIdx); success = STYC.storyParagraphCleanup(io_context, paragraph) && success; } } catch (err) { LOG.logError("STYC.storyParagraphsCleanup: throws " + err); } } while (false); LOG.logExit("STYC.storyParagraphsCleanup"); return success; } STYC.storyStyleCleanup = function(io_context, in_story) { var success = false; LOG.logEntry("STYC.storyStyleCleanup"); do { try { if (! io_context) { LOG.logError("STYC.storyStyleCleanup: no io_context"); break; } if (! (in_story instanceof Story)) { LOG.logError("STYC.storyStyleCleanup: no in_story"); break; } success = true; io_context.paragraphCleanupBatch = undefined; io_context.textStyleRangeCleanupBatch = undefined; success = STYC.storyParagraphsCleanup(io_context, in_story) && success; success = STYC.storyTextStyleRangesCleanup(io_context, in_story) && success; in_story.clearOverrides(OverrideType.ALL); if (io_context.paragraphCleanupBatch) { for (var idx = 0; idx < io_context.paragraphCleanupBatch.length; idx++) { var entry = io_context.paragraphCleanupBatch[idx]; var paragraph = entry.paragraph; var paraStyle = entry.paraStyle; paragraph.applyParagraphStyle(paraStyle, false); } io_context.paragraphCleanupBatch = undefined; } if (io_context.textStyleRangeCleanupBatch) { for (var idx = 0; idx < io_context.textStyleRangeCleanupBatch.length; idx++) { var entry = io_context.textStyleRangeCleanupBatch[idx]; var startIdx = entry.startIdx; var endIdx = entry.endIdx; var textStyleRange = in_story.characters.itemByRange(startIdx, endIdx); var charStyle = entry.charStyle; textStyleRange.applyCharacterStyle(charStyle, false); } io_context.textStyleRangeCleanupBatch = undefined; } } catch (err) { LOG.logError("STYC.storyStyleCleanup: throws " + err); } } while (false); LOG.logExit("STYC.storyStyleCleanup"); return success; } STYC.storyTextStyleRangeCleanup = function(io_context, in_textStyleRange) { var success = false; LOG.logEntry("STYC.storyTextStyleRangeCleanup"); do { try { if (! io_context) { LOG.logError("STYC.storyTextStyleRangeCleanup: no io_context"); break; } if (! (in_textStyleRange instanceof TextStyleRange)) { LOG.logError("STYC.storyTextStyleRangeCleanup: no in_textStyleRange"); break; } if (! in_textStyleRange.isValid) { LOG.logError("STYC.storyTextStyleRangeCleanup: invalid in_textStyleRange"); break; } var doc = io_context.doc; if (! (doc instanceof Document)) { LOG.logError("STYC.storyTextStyleRangeCleanup: no doc"); break; } success = true; if (! in_textStyleRange.textHasOverrides(StyleType.CHARACTER_STYLE_TYPE, false)) { break; } var hasRelevantDifferences = false; for (var attr in ATTRIBUTES_FOR_STYLE_COMPARISONS.CharacterStyle) { if (ATTRIBUTES_FOR_STYLE_COMPARISONS.CharacterStyle[attr]) { var paraStyleAttrVal = in_textStyleRange.appliedParagraphStyle[attr]; var charStyleAttrVal = in_textStyleRange.appliedCharacterStyle[attr]; var effectiveStyleAttrVal = paraStyleAttrVal; if (charStyleAttrVal && charStyleAttrVal != NothingEnum.NOTHING && charStyleAttrVal != "") { effectiveStyleAttrVal = charStyleAttrVal; } if (in_textStyleRange[attr] != effectiveStyleAttrVal) { hasRelevantDifferences = true; break; // exit for } } } if (! hasRelevantDifferences) { // Range has manual overrides, but they are irrelevant for our purposes LOG.logNote("STYC.storyTextStyleRangeCleanup: clearing character overrides"); STYC.appendLineToReport(io_context, "Cleared manual character style overrides on text range:\n" + UTILS.shortenedString(in_textStyleRange.contents, 100)); break; } if (! io_context.textStyleRangeCleanupBatch) { io_context.textStyleRangeCleanupBatch = []; } var definingTextStyleRangeHash = STYC.inDesignElementHash(io_context, in_textStyleRange); if ( io_context.artificialCharacterStylesByDefiningTextStyleRangeHashString && io_context.artificialCharacterStylesByDefiningTextStyleRangeHashString[definingTextStyleRangeHash.string] ) { var reusedArtificialCharacterStyle = io_context.artificialCharacterStylesByDefiningTextStyleRangeHashString[definingTextStyleRangeHash.string]; var startIdx = in_textStyleRange.characters.firstItem().index; var endIdx = startIdx + in_textStyleRange.characters.length - 1; io_context.textStyleRangeCleanupBatch.push({ startIdx: startIdx, endIdx: endIdx, charStyle: reusedArtificialCharacterStyle }); break; } if (! io_context.characterStyleCounter) { io_context.characterStyleCounter = 0; } io_context.characterStyleCounter++; var charStyle; var name = ARTIFICIAL_CHAR_STYLE_NAME_PREFIX + io_context.characterStyleCounter; do { charStyle = doc.characterStyles.itemByName(name); if (charStyle && ! charStyle.isValid) { charStyle = null; } if (charStyle) { io_context.characterStyleCounter++; name = ARTIFICIAL_CHAR_STYLE_NAME_PREFIX + io_context.characterStyleCounter; } } while (charStyle); var properties = {}; properties.name = name; properties.basedOn = in_textStyleRange.appliedCharacterStyle; for (var attr in ATTRIBUTES_FOR_STYLE_COMPARISONS.TextStyleRange) { if (ATTRIBUTES_FOR_STYLE_COMPARISONS.TextStyleRange[attr]) { properties[attr] = in_textStyleRange[attr]; } } var newArtificialCharacterStyle = io_context.doc.characterStyles.add(properties); STYC.addToCharacterStyleLookup(io_context, newArtificialCharacterStyle, definingTextStyleRangeHash); var startIdx = in_textStyleRange.characters.firstItem().index; var endIdx = startIdx + in_textStyleRange.characters.length - 1; io_context.textStyleRangeCleanupBatch.push({ startIdx: startIdx, endIdx: endIdx, charStyle: newArtificialCharacterStyle }); } catch (err) { LOG.logError("STYC.storyTextStyleRangeCleanup: throws " + err); } } while (false); LOG.logExit("STYC.storyTextStyleRangeCleanup"); return success; } STYC.storyTextStyleRangesCleanup = function(io_context, in_story) { var success = false; LOG.logEntry("STYC.storyTextStyleRangesCleanup"); do { try { if (! io_context) { LOG.logError("STYC.storyTextStyleRangesCleanup: no io_context"); break; } if (! (in_story instanceof Story)) { LOG.logError("STYC.storyTextStyleRangesCleanup: no in_story"); break; } success = true; var textStyleRanges = in_story.textStyleRanges; for (var textStyleRangeIdx = 0; textStyleRangeIdx < textStyleRanges.length; textStyleRangeIdx++) { var textStyleRange = textStyleRanges.item(textStyleRangeIdx); success = STYC.storyTextStyleRangeCleanup(io_context, textStyleRange) && success; } } catch (err) { LOG.logError("STYC.storyTextStyleRangesCleanup: throws " + err); } } while (false); LOG.logExit("STYC.storyTextStyleRangesCleanup"); return success; } STYC.styleCleanup = function(io_context) { var success = false; LOG.logEntry("STYC.styleCleanup"); do { try { if (! io_context) { LOG.logError("STYC.styleCleanup: no io_context"); break; } var doc = io_context.doc; if (! (doc instanceof Document)) { LOG.logError("STYC.styleCleanup: no doc"); break; } if (WRITE_STYLE_REPORT) { if (! doc.saved) { LOG.logError("STYC.styleCleanup: doc has never been saved. Cannot generate report file"); } else { try { var docFolderPath = UTILS.dirName(doc.fullName.fsName); var docName = UTILS.stripFileNameExtension(doc.name); io_context.reportFilePath = docFolderPath + docName + ".md"; io_context.report = ""; } catch (err) { LOG.logError("STYC.styleCleanup: report file path throws " + err); io_context.reportFilePath = undefined; } } } if (! STYC.buildParagraphStyleLookup(io_context)) { LOG.logError("STYC.styleCleanup: failed to build character style lookup table"); break; } STYC.generateParagraphStyleReport(io_context); if (! STYC.buildCharacterStyleLookup(io_context)) { LOG.logError("STYC.styleCleanup: failed to build character style lookup table"); break; } STYC.generateCharacterStyleReport(io_context); success = true; var stories = doc.stories; if (! stories || stories.length == 0) { LOG.logWarning("STYC.styleCleanup: doc contains no stories"); break; } for (var storyIdx = 0; storyIdx < stories.length; storyIdx++) { var story = stories.item(storyIdx); success = STYC.storyStyleCleanup(io_context, story) && success; } if (io_context.reportFilePath) { try { var reportFile = new File(io_context.reportFilePath); reportFile.open("w"); reportFile.writeln(io_context.report); reportFile.close(); } catch (err) { LOG.logError("STYC.styleCleanup: writing report throws " + err); } } } catch (err) { LOG.logError("STYC.styleCleanup: throws " + err); } } while (false); LOG.logExit("STYC.styleCleanup"); return success; } // ---- })()}; // Pass configuration data to LOG module LOG.LOG_TO_CONSOLE = LOG_TO_CONSOLE; LOG.LOG_LEVEL = LOG_LEVEL; LOG.LOG_ENTRY_EXIT = LOG_ENTRY_EXIT; LOG.FILE_PATH_LOG = FILE_PATH_LOG; ATTRIBUTES_FOR_STYLE_COMPARISONS.Paragraph = ATTRIBUTES_FOR_STYLE_COMPARISONS.ParagraphStyle; ATTRIBUTES_FOR_STYLE_COMPARISONS.TextStyleRange = ATTRIBUTES_FOR_STYLE_COMPARISONS.CharacterStyle; ATTRIBUTES_FOR_STYLE_COMPARISONS.Font = { fullName: 1 }; ATTRIBUTES_FOR_STYLE_COMPARISONS.Application = {}; ATTRIBUTES_FOR_STYLE_COMPARISONS.Events = {}; ATTRIBUTES_FOR_STYLE_COMPARISONS.EventListeners = {}; // ---- if (DEBUG) { STYC.main(); } else { // Running the non-debug version is wrapped into a single Undo for the user. app.doScript("STYC.main()", ScriptLanguage.JAVASCRIPT, [], UndoModes.ENTIRE_SCRIPT); } /************************************************************* StyleCleanup.jsx (c) 2019 NNELS, The National Network for Equitable Library Service (formerly, CALS, The Canadian Accessible Library System) https://nnels.ca This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . Neither the name of NNELS, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. ============================================== */