Skip to main content
Known Participant
November 30, 2023
Answered

Illustrator jsx to delete <b>, </b> tags in paragraph text an keep the differents font style

  • November 30, 2023
  • 2 replies
  • 777 views

I do a script to recognise tags <b> and <i> in paragraph text and replace font by choised font style and it works

But now I want to delete tags <b>, </b>, <i> and </i> but the diffrents font style disapare when I run a script to delete those tags

Illustrator keep the first style caracter it find in the paragraph

I have this :and I want to have this :

But it done that :

Correct answer m1b

Here is a version that has a UI. If anybody uses it, please let me know if you find any bugs.

- Mark

 

 

/**
 * Find/Change RegExp with UI.
 * @7111211 m1b
 * @discussion https://community.adobe.com/t5/illustrator-discussions/illustrator-jsx-to-delete-lt-b-gt-lt-b-gt-tags-in-paragraph-text-an-keep-the-differents-font-style/m-p/14269543
 */
(function () {

    if (app.documents.length === 0) {
        alert('Please open a document and try again.');
        return;
    }

    var settings = {
        target: app.activeDocument,
        findWhat: /<\/?[ib]>/,
        changeTo: '',
        ignoreLockedHidden: false,
        showUI: true,
        showResult: true,
    };

    // show UI
    if (settings.showUI == true && ui(settings) == 2)
        // user cancelled
        return;

    if (
        settings.findWhat == undefined
        || settings.findWhat.constructor.name !== 'RegExp'
    ) {
        alert('Sorry, "' + (settings.findText || 'findWhat') + '" was an invalid RegExp.');
        return;
    }

    // do the find/change
    var counter = findChangeRegExp(settings.target, settings.findWhat, settings.changeTo, settings.ignoreLockedHidden);

    if (settings.showResult) {
        app.redraw();
        alert('Performed ' + counter + ' find/change operations.');
    }

})();


/**
 * Performs a Find/Change operation on `text` and
 * returns a count of how many changes were made.
 * @7111211 m1b
 * @version 2023-12-01
 * @9397041 {TextRange|TextFrame} text - the text to search.
 * @9397041 {RegExp} findWhat - the RegExp to find with.
 * @9397041 {String} [changeTo] - the change-to string.
 * @9397041 {Boolean} [ignoreLockedHidden] - whether to ignore locked or hidden text (default: true).
 * @9397041 {Boolean} [adjustSelection] - whether to adjust the selection (default: true when `text` has textSelection).
 * @Returns {Number}
 */
function findChangeRegExp(text, findWhat, changeTo, ignoreLockedHidden, adjustSelection) {

    ignoreLockedHidden = ignoreLockedHidden !== false;

    var counter = 0;

    if (text == undefined)
        throw Error('findChange: bad `text` supplied. Expected [TextRange] or [TextFrame]');

    if (
        (
            // to bypass bug in TextFrames object:
            text.typename
            && text.typename == 'TextFrames'
        )
        || text.constructor.name == 'Stories'
        || text.constructor.name == 'Array'
    ) {
        // handle array of text frames
        for (var i = text.length - 1; i >= 0; i--)
            counter += findChangeRegExp(text[i], findWhat, changeTo, ignoreLockedHidden, false) || 0;

        return counter;

    }

    else if (text.constructor.name == 'GroupItem') {

        // handle the group's items
        for (var i = text.pageItems.length - 1; i >= 0; i--)
            counter += findChangeRegExp(text.pageItems[i], findWhat, changeTo, ignoreLockedHidden, false) || 0;

        return counter;

    }

    else if (text.constructor.name == 'Document')
        return findChangeRegExp(text.stories, findWhat, changeTo, ignoreLockedHidden, false) || 0;

    else if (
        text.constructor.name == 'Story'
        || text.constructor.name == 'TextFrame'
    )
        text = text.textRange;

    else if (text.constructor.name !== 'TextRange')
        return;

    if (
        ignoreLockedHidden
        && !testItem(text.story.textFrames[0], isLockedOrHidden)
    )
        // ignore this text
        return;

    if (
        findWhat !== undefined
        && findWhat.constructor.name === 'String'
    )
        findWhat = new RegExp(findWhat, 'g');

    else if (
        findWhat == undefined
        || findWhat.constructor.name !== 'RegExp'
    )
        throw TypeError('findChange: Bad `findWhat` supplied.');

    // findWhat regex must be global!
    if (!findWhat.global)
        findWhat = new RegExp(findWhat.source, 'g' + (findWhat.ignoreCase ? 'i' : '') + (findWhat.multiline ? 'm' : ''));

    // reset findWhat index
    findWhat.lastIndex = 0;

    if (changeTo == undefined)
        changeTo = '';

    var contents = text.contents,
        selectLength = 0,
        selectStart,
        selectEnd,
        match,
        found = [];

    if (text.textSelection.length > 0) {
        // record the selection for later
        selectStart = text.textSelection[0].start;
        selectEnd = text.textSelection[0].end;
        selectLength = selectEnd - selectStart;
    }

    while (match = findWhat.exec(contents))
        found.push({
            start: match.index,
            end: findWhat.lastIndex,
            str: contents.slice(match.index, findWhat.lastIndex),
        });

    counter = found.length;

    // process each found, going backwards
    var s, e;
    while (match = found.pop()) {

        // remove the found text, except first character
        for (e = match.end - 1, s = match.start; s < e; e--) {
            text.characters[e].remove();
            selectEnd--;
        }

        var replacement = match.str.replace(findWhat, changeTo);

        if (replacement) {
            // set the contents of the first character
            text.characters[e].contents = replacement;
            selectEnd += replacement.length - match.str.length;
        }
        else {
            // no contents to replace with
            text.characters[e].remove();
            selectEnd--;
        }

    }

    if (
        adjustSelection !== false
        && selectLength > 0
    ) {
        // adjust the selection
        app.selection = [];
        for (var s = selectStart; s < selectEnd; s++)
            text.story.characters[s].select(true);
    }

    return counter;

};


/**
 * Performs `failFunction` on the item
 * and its ancestors, returning false
 * immediately that `failFunction`
 * returns true.
 * @9397041 {PageItem} item
 * @9397041 {Function} failFunction
 * @Returns {Boolean} - true, if item n
 */
function testItem(item, failFunction) {

    while (
        item.constructor.name !== 'Document'
        && item.hasOwnProperty('parent')
    ) {

        if (failFunction(item))
            return false;

        item = item.parent;

    }

    return true;

};


/**
 * Returns true if item
 * is locked or hidden.
 * @9397041 {PageItem} item - an Illustrator PageItem.
 * @Returns {Boolean}
 */
function isLockedOrHidden(item) {

    return (
        (
            item.locked != undefined
            && item.locked == true
        )
        || (
            item.hidden != undefined
            && item.hidden == true
        )
        || (
            item.layer != undefined
            && (
                item.layer.locked == true
                || item.layer.visible == false
            )
        )
    );
};


/**
 * Shows UI suitable for Find/Change
 * @9397041 {Object} settings
 * @Returns {1|2} - ScriptUI result code.
 */
function ui(settings) {

    var targets = [];

    if (app.documents.length == 0)
        return;

    if (app.activeDocument.selection.length > 0)
        targets.push(
            { label: 'Selection', get: function () { return app.activeDocument.selection } }
        );

    targets.push(
        { label: 'Document', get: function () { return app.activeDocument } },
    );

    var labelWidth = 100,
        columnWidth = 200,

        w = new Window("dialog { text:'Find/Change RegExp' }"),

        fields = w.add("Group { orientation: 'column', alignment: ['fill','fill'] }"),
        findWhatGroup = fields.add("Group { orientation: 'row', alignment: ['fill','fill'] }"),
        findWhatLabel = findWhatGroup.add("StaticText { text: 'Find what:', justify: 'right' }"),
        findWhatField = findWhatGroup.add("EditText { text:'', alignment:['fill','top'] }"),
        changeToGroup = fields.add("Group { orientation: 'row', alignment: ['fill','fill'] }"),
        changeToLabel = changeToGroup.add("StaticText { text: 'Change to:', justify: 'right' }"),
        changeToField = changeToGroup.add("EditText { text:'', alignment:['fill','top'] }"),

        targetMenuGroup = w.add("Group { orientation: 'row', alignment: ['fill','fill'] }"),
        targetLabel = targetMenuGroup.add("StaticText { text: 'Target', justify: 'right' }"),
        targetMenu = targetMenuGroup.add("Dropdownlist {alignment:['right','center'] }"),

        checkBoxes = w.add("group {orientation:'row', alignment:['fill','bottom'], alignChildren:'left', margins:[5,0,5,0] }"),
        ignoreCaseCheckBox = checkBoxes.add("Checkbox { text:'Ignore case', alignment:'left', value:false }"),
        ignoreLockedHiddenCheckBox = checkBoxes.add("Checkbox { text:'Ignore locked/hidden text', alignment:'left', value:false }"),

        bottomUI = w.add("group {orientation:'row', alignment:['fill','fill'], margins:[0,20,0,0] }"),
        buttons = bottomUI.add("group {orientation:'row', alignment:['right','center'], alignChildren:'right' }"),
        cancelButton = buttons.add("Button { text: 'Cancel', properties: {name:'cancel'} }"),
        okayButton = buttons.add("Button { text:'Change', enabled: true, properties: {name:'ok'} }");

    targetLabel.preferredSize.width = labelWidth;
    targetMenu.preferredSize.width = columnWidth;

    findWhatLabel.preferredSize.width = labelWidth;
    findWhatField.preferredSize.width = columnWidth;
    findWhatField.text = settings.findWhat.source;

    changeToLabel.preferredSize.width = labelWidth;
    changeToField.preferredSize.width = columnWidth;
    changeToField.text = settings.changeTo;

    ignoreCaseCheckBox.value = settings.findWhat.ignoreCase;
    ignoreLockedHiddenCheckBox.value = settings.ignoreLockedHidden;

    var targetTypes = [];
    for (var i = 0; i < targets.length; i++)
        targetTypes.push(targets[i].label);

    buildMenu(targetMenu, targetTypes, settings.targetType);

    okayButton.onClick = function () { return update() && w.close(1) };
    cancelButton.onClick = function () { w.close(2) };

    w.center();
    return w.show();

    /**
     * Builds dropdown menu items.
     */
    function buildMenu(menu, arr, index) {
        for (var i = 0; i < arr.length; i++)
            menu.add('item', arr[i]);
        menu.selection = [index || 0];
    };

    /**
     * Updates settings.
     * @Returns {Boolean} - valid RegExp?
     */
    function update() {

        settings.target = targets[targetMenu.selection.index].get();
        settings.changeTo = changeToField.text;
        settings.findText = findWhatField.text;
        settings.ignoreCase = !!ignoreCaseCheckBox.value;
        settings.ignoreLockedHidden = !!ignoreLockedHiddenCheckBox.value;

        try {
            settings.findWhat = RegExp(findWhatField.text, 'g' + (ignoreCaseCheckBox.value ? 'i' : ''));
        } catch (error) {
            settings.findWhat = undefined;
        }

        return settings.findWhat !== undefined;

    };

};

 

 

 

2 replies

femkeblanco
Legend
November 30, 2023

There may be an easier way, but this is what came to me intuitively.  Not extensively tested.

// select textFrame
var string1 = app.selection[0].textRange.contents;
var regex = /<b>|<\/b>|<i>|<\/i>/g;

// create array of attributes of characters
var textRanges = app.selection[0].textRanges;
var attributes = [];
for (var i = 0; i < textRanges.length; i++) {
    var o = {};
    o.textFont = textRanges[i].characterAttributes.textFont;
    o.size = textRanges[i].characterAttributes.size;
    attributes.push(o);
}

// create array of indices of to-be-removed substrings
var indices = [];
for (var i = regex.exec(string1); i != null; i = regex.exec(string1)) {
    var o = {};
    o.start = i.index;
    if (i == "<b>" || i == "<i>") o.n = 3;
    else o.n = 4;
    indices.push(o);
}

// remove attributes of to-be-removed substrings
for (var i = indices.length - 1; i > -1; i--) {
    attributes.splice(indices[i].start, indices[i].n)
}

// remove substrings
var string2 = string1.replace(regex, "");
app.selection[0].contents = string2;

// re-assign attributes to characters
for (var i = 0; i < textRanges.length; i++) {
    textRanges[i].characterAttributes.textFont = attributes[i].textFont;
    textRanges[i].characterAttributes.size = attributes[i].size;
}

 

 

m1b
Community Expert
Community Expert
December 1, 2023

EDIT 2023-12-01: The code for this post is the old version—I'll leave it for anyone who's interested because it's a bit simpler to understand, but if you just want to use it, please use the newer one I posted. The UI is totally separate to the function—you can use with or without the UI.

 

Hi @femkeblanco, I was pondering this too.

 

I realised that I had no general find/change function in my toolbox, so I've written one now. I take a slightly different approach to yours, by removing the found text except the first character, and then adding the replacement to just that first character. This means the non-found text will be untouched, such as the orange word BOLD in the screen grab below.

 

There is a lot of sanity checking and a bit for adjusting the text selection, but otherwise that's all it does. See what you think. It seems like a strange way to do it, but I don't know any way to create a TextRange by specifying the start and end chacacters. Let me know if you do!

- Mark

 

 

/**
 * Demo of `findChangeRegExp` function.
 * The function attempts to perform the find/change
 * without modifying any character attributes (beyond
 * those implicit in the change).
 * @author m1b
 * @discussion https://community.adobe.com/t5/illustrator-discussions/illustrator-jsx-to-delete-lt-b-gt-lt-b-gt-tags-in-paragraph-text-an-keep-the-differents-font-style/m-p/14269543
 */
(function () {

    try {

        /* demo example 1: find/change the whole document */
        var counter = findChangeRegExp(app.activeDocument, /<\/?([ib])>/g, '');

        /* demo example 2: find/change just the selection */
        // var counter = findChange(app.activeDocument.selection, /<\/?([ib])>/g, '');

        app.redraw();
        alert('Performed ' + counter + ' find/change operations.');

    }
    catch (error) {
        alert('Find Change function reported an error: ' + error.message);
    }

})();


/**
 * Performs a Find/Change operation on `text` and
 * returns a count of how many changes were made.
 * @author m1b
 * @version 2023-12-01
 * @param {TextRange|TextFrame} text - the text to search.
 * @param {RegExp} findWhat - the RegExp to find with.
 * @param {String} [changeTo] - the change-to string.
 * @param {Boolean} [adjustSelection] - whether to adjust the selection (default: true when `text` has textSelection).
 * @returns {Number}
 */
function findChangeRegExp(text, findWhat, changeTo, adjustSelection) {

    var counter = 0;

    if (text == undefined)
        throw Error('findChange: bad `text` supplied. Expected [TextRange] or [TextFrame]');

    if (
        (
            // to bypass bug in TextFrames object:
            text.typename
            && text.typename == 'TextFrames'
        )
        || text.constructor.name == 'Stories'
        || text.constructor.name == 'Array'
    ) {
        // handle array of text frames
        for (var i = text.length - 1; i >= 0; i--)
            counter += findChangeRegExp(text[i], findWhat, changeTo, false);

        return counter;

    }

    else if (text.constructor.name == 'Document')
        return findChangeRegExp(text.stories, findWhat, changeTo, false);

    else if (
        text.constructor.name == 'Story'
        || text.constructor.name == 'TextFrame'
    )
        text = text.textRange;

    else if (text.constructor.name !== 'TextRange')
        throw TypeError('findChange: Bad `text` supplied.');

    if (
        findWhat !== undefined
        && findWhat.constructor.name === 'String'
    )
        findWhat = RegExp(findWhat, 'g');

    else if (
        findWhat == undefined
        || findWhat.constructor.name !== 'RegExp'
    )
        throw TypeError('findChange: Bad `findWhat` supplied.');

    if (changeTo == undefined)
        changeTo = '';

    var contents = text.contents,
        selectLength = 0,
        selectStart,
        selectEnd,
        match,
        found = [];

    if (text.textSelection.length > 0) {
        // record the selection for later
        selectStart = text.textSelection[0].start;
        selectEnd = text.textSelection[0].end;
        selectLength = selectEnd - selectStart;
    }

    findWhat.lastIndex = 0;

    while (match = findWhat.exec(contents))
        found.push({
            start: match.index,
            end: findWhat.lastIndex,
            str: contents.slice(match.index, findWhat.lastIndex),
        });

    counter = found.length;

    // process each found, going backwards
    var s, e;
    while (match = found.pop()) {

        // remove the found text, except first character
        for (e = match.end - 1, s = match.start; s < e; e--) {
            text.characters[e].remove();
            selectEnd--;
        }

        var replacement = match.str.replace(findWhat, changeTo);

        if (replacement) {
            // set the contents of the first character
            text.characters[e].contents = replacement;
            selectEnd += replacement.length - match.str.length;
        }
        else {
            // no contents to replace with
            text.characters[e].remove();
            selectEnd--;
        }

    }

    if (
        adjustSelection !== false
        && selectLength > 0
    ) {
        // adjust the selection
        app.selection = [];
        for (var s = selectStart; s < selectEnd; s++)
            text.story.characters[s].select(true);
    }

    return counter;

};

 

 

m1b
Community Expert
m1bCommunity ExpertCorrect answer
Community Expert
December 1, 2023

Here is a version that has a UI. If anybody uses it, please let me know if you find any bugs.

- Mark

 

 

/**
 * Find/Change RegExp with UI.
 * @7111211 m1b
 * @discussion https://community.adobe.com/t5/illustrator-discussions/illustrator-jsx-to-delete-lt-b-gt-lt-b-gt-tags-in-paragraph-text-an-keep-the-differents-font-style/m-p/14269543
 */
(function () {

    if (app.documents.length === 0) {
        alert('Please open a document and try again.');
        return;
    }

    var settings = {
        target: app.activeDocument,
        findWhat: /<\/?[ib]>/,
        changeTo: '',
        ignoreLockedHidden: false,
        showUI: true,
        showResult: true,
    };

    // show UI
    if (settings.showUI == true && ui(settings) == 2)
        // user cancelled
        return;

    if (
        settings.findWhat == undefined
        || settings.findWhat.constructor.name !== 'RegExp'
    ) {
        alert('Sorry, "' + (settings.findText || 'findWhat') + '" was an invalid RegExp.');
        return;
    }

    // do the find/change
    var counter = findChangeRegExp(settings.target, settings.findWhat, settings.changeTo, settings.ignoreLockedHidden);

    if (settings.showResult) {
        app.redraw();
        alert('Performed ' + counter + ' find/change operations.');
    }

})();


/**
 * Performs a Find/Change operation on `text` and
 * returns a count of how many changes were made.
 * @7111211 m1b
 * @version 2023-12-01
 * @9397041 {TextRange|TextFrame} text - the text to search.
 * @9397041 {RegExp} findWhat - the RegExp to find with.
 * @9397041 {String} [changeTo] - the change-to string.
 * @9397041 {Boolean} [ignoreLockedHidden] - whether to ignore locked or hidden text (default: true).
 * @9397041 {Boolean} [adjustSelection] - whether to adjust the selection (default: true when `text` has textSelection).
 * @Returns {Number}
 */
function findChangeRegExp(text, findWhat, changeTo, ignoreLockedHidden, adjustSelection) {

    ignoreLockedHidden = ignoreLockedHidden !== false;

    var counter = 0;

    if (text == undefined)
        throw Error('findChange: bad `text` supplied. Expected [TextRange] or [TextFrame]');

    if (
        (
            // to bypass bug in TextFrames object:
            text.typename
            && text.typename == 'TextFrames'
        )
        || text.constructor.name == 'Stories'
        || text.constructor.name == 'Array'
    ) {
        // handle array of text frames
        for (var i = text.length - 1; i >= 0; i--)
            counter += findChangeRegExp(text[i], findWhat, changeTo, ignoreLockedHidden, false) || 0;

        return counter;

    }

    else if (text.constructor.name == 'GroupItem') {

        // handle the group's items
        for (var i = text.pageItems.length - 1; i >= 0; i--)
            counter += findChangeRegExp(text.pageItems[i], findWhat, changeTo, ignoreLockedHidden, false) || 0;

        return counter;

    }

    else if (text.constructor.name == 'Document')
        return findChangeRegExp(text.stories, findWhat, changeTo, ignoreLockedHidden, false) || 0;

    else if (
        text.constructor.name == 'Story'
        || text.constructor.name == 'TextFrame'
    )
        text = text.textRange;

    else if (text.constructor.name !== 'TextRange')
        return;

    if (
        ignoreLockedHidden
        && !testItem(text.story.textFrames[0], isLockedOrHidden)
    )
        // ignore this text
        return;

    if (
        findWhat !== undefined
        && findWhat.constructor.name === 'String'
    )
        findWhat = new RegExp(findWhat, 'g');

    else if (
        findWhat == undefined
        || findWhat.constructor.name !== 'RegExp'
    )
        throw TypeError('findChange: Bad `findWhat` supplied.');

    // findWhat regex must be global!
    if (!findWhat.global)
        findWhat = new RegExp(findWhat.source, 'g' + (findWhat.ignoreCase ? 'i' : '') + (findWhat.multiline ? 'm' : ''));

    // reset findWhat index
    findWhat.lastIndex = 0;

    if (changeTo == undefined)
        changeTo = '';

    var contents = text.contents,
        selectLength = 0,
        selectStart,
        selectEnd,
        match,
        found = [];

    if (text.textSelection.length > 0) {
        // record the selection for later
        selectStart = text.textSelection[0].start;
        selectEnd = text.textSelection[0].end;
        selectLength = selectEnd - selectStart;
    }

    while (match = findWhat.exec(contents))
        found.push({
            start: match.index,
            end: findWhat.lastIndex,
            str: contents.slice(match.index, findWhat.lastIndex),
        });

    counter = found.length;

    // process each found, going backwards
    var s, e;
    while (match = found.pop()) {

        // remove the found text, except first character
        for (e = match.end - 1, s = match.start; s < e; e--) {
            text.characters[e].remove();
            selectEnd--;
        }

        var replacement = match.str.replace(findWhat, changeTo);

        if (replacement) {
            // set the contents of the first character
            text.characters[e].contents = replacement;
            selectEnd += replacement.length - match.str.length;
        }
        else {
            // no contents to replace with
            text.characters[e].remove();
            selectEnd--;
        }

    }

    if (
        adjustSelection !== false
        && selectLength > 0
    ) {
        // adjust the selection
        app.selection = [];
        for (var s = selectStart; s < selectEnd; s++)
            text.story.characters[s].select(true);
    }

    return counter;

};


/**
 * Performs `failFunction` on the item
 * and its ancestors, returning false
 * immediately that `failFunction`
 * returns true.
 * @9397041 {PageItem} item
 * @9397041 {Function} failFunction
 * @Returns {Boolean} - true, if item n
 */
function testItem(item, failFunction) {

    while (
        item.constructor.name !== 'Document'
        && item.hasOwnProperty('parent')
    ) {

        if (failFunction(item))
            return false;

        item = item.parent;

    }

    return true;

};


/**
 * Returns true if item
 * is locked or hidden.
 * @9397041 {PageItem} item - an Illustrator PageItem.
 * @Returns {Boolean}
 */
function isLockedOrHidden(item) {

    return (
        (
            item.locked != undefined
            && item.locked == true
        )
        || (
            item.hidden != undefined
            && item.hidden == true
        )
        || (
            item.layer != undefined
            && (
                item.layer.locked == true
                || item.layer.visible == false
            )
        )
    );
};


/**
 * Shows UI suitable for Find/Change
 * @9397041 {Object} settings
 * @Returns {1|2} - ScriptUI result code.
 */
function ui(settings) {

    var targets = [];

    if (app.documents.length == 0)
        return;

    if (app.activeDocument.selection.length > 0)
        targets.push(
            { label: 'Selection', get: function () { return app.activeDocument.selection } }
        );

    targets.push(
        { label: 'Document', get: function () { return app.activeDocument } },
    );

    var labelWidth = 100,
        columnWidth = 200,

        w = new Window("dialog { text:'Find/Change RegExp' }"),

        fields = w.add("Group { orientation: 'column', alignment: ['fill','fill'] }"),
        findWhatGroup = fields.add("Group { orientation: 'row', alignment: ['fill','fill'] }"),
        findWhatLabel = findWhatGroup.add("StaticText { text: 'Find what:', justify: 'right' }"),
        findWhatField = findWhatGroup.add("EditText { text:'', alignment:['fill','top'] }"),
        changeToGroup = fields.add("Group { orientation: 'row', alignment: ['fill','fill'] }"),
        changeToLabel = changeToGroup.add("StaticText { text: 'Change to:', justify: 'right' }"),
        changeToField = changeToGroup.add("EditText { text:'', alignment:['fill','top'] }"),

        targetMenuGroup = w.add("Group { orientation: 'row', alignment: ['fill','fill'] }"),
        targetLabel = targetMenuGroup.add("StaticText { text: 'Target', justify: 'right' }"),
        targetMenu = targetMenuGroup.add("Dropdownlist {alignment:['right','center'] }"),

        checkBoxes = w.add("group {orientation:'row', alignment:['fill','bottom'], alignChildren:'left', margins:[5,0,5,0] }"),
        ignoreCaseCheckBox = checkBoxes.add("Checkbox { text:'Ignore case', alignment:'left', value:false }"),
        ignoreLockedHiddenCheckBox = checkBoxes.add("Checkbox { text:'Ignore locked/hidden text', alignment:'left', value:false }"),

        bottomUI = w.add("group {orientation:'row', alignment:['fill','fill'], margins:[0,20,0,0] }"),
        buttons = bottomUI.add("group {orientation:'row', alignment:['right','center'], alignChildren:'right' }"),
        cancelButton = buttons.add("Button { text: 'Cancel', properties: {name:'cancel'} }"),
        okayButton = buttons.add("Button { text:'Change', enabled: true, properties: {name:'ok'} }");

    targetLabel.preferredSize.width = labelWidth;
    targetMenu.preferredSize.width = columnWidth;

    findWhatLabel.preferredSize.width = labelWidth;
    findWhatField.preferredSize.width = columnWidth;
    findWhatField.text = settings.findWhat.source;

    changeToLabel.preferredSize.width = labelWidth;
    changeToField.preferredSize.width = columnWidth;
    changeToField.text = settings.changeTo;

    ignoreCaseCheckBox.value = settings.findWhat.ignoreCase;
    ignoreLockedHiddenCheckBox.value = settings.ignoreLockedHidden;

    var targetTypes = [];
    for (var i = 0; i < targets.length; i++)
        targetTypes.push(targets[i].label);

    buildMenu(targetMenu, targetTypes, settings.targetType);

    okayButton.onClick = function () { return update() && w.close(1) };
    cancelButton.onClick = function () { w.close(2) };

    w.center();
    return w.show();

    /**
     * Builds dropdown menu items.
     */
    function buildMenu(menu, arr, index) {
        for (var i = 0; i < arr.length; i++)
            menu.add('item', arr[i]);
        menu.selection = [index || 0];
    };

    /**
     * Updates settings.
     * @Returns {Boolean} - valid RegExp?
     */
    function update() {

        settings.target = targets[targetMenu.selection.index].get();
        settings.changeTo = changeToField.text;
        settings.findText = findWhatField.text;
        settings.ignoreCase = !!ignoreCaseCheckBox.value;
        settings.ignoreLockedHidden = !!ignoreLockedHiddenCheckBox.value;

        try {
            settings.findWhat = RegExp(findWhatField.text, 'g' + (ignoreCaseCheckBox.value ? 'i' : ''));
        } catch (error) {
            settings.findWhat = undefined;
        }

        return settings.findWhat !== undefined;

    };

};

 

 

 

m1b
Community Expert
Community Expert
November 30, 2023

Hi @Jeffosaure, my guess is that your script is setting all the text in one go; something like:

var foundText.contents = textWithoutTags;

 

But when you set the `contents` of a text range, it (1) deletes the current text, eg "<i>italique</i>", then (2) inserts the specified text, eg. "italique" at the first insertion point of the text range (which now has no `contents`) and therefore (3) applies the text styles of that first insertion point to all the text. So that's why you may be losing the styling.

 

If my guess is correct, then here's what you can do to fix the problem: get text ranges that *only* include the tags themselves, not the middle contents, and remove them, starting at the last.

- Mark