Skip to main content
Inspiring
October 22, 2022
Answered

Change color of a single word in a text layer and turn symbols to superscript using Javascript?

  • October 22, 2022
  • 2 replies
  • 1585 views

Hi, 

Kindly help me in modifying the below javascript. Totally two things that I would like to modify it,

 

1) If the given input in the dialog box as "Get 20% discount", the word "Discount" alone has to turn Green in color.  Example: Get 20% discount --> Get 20% discount
2) If the given input in the dialog box is "Get 20% discount#", the symbol "#" has to turn into a superscript. Example: Get 20% discount# ---> Get 20% discount#

 

The below script basically replaces the existing text layer in specific artboards if the text layer matches the font type(Arial-BoldMT) & artboard dimension. 

 

var doc = app.activeDocument;
var oldPref = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
 
var ab, aLayer, aW, aH

var defaultValue = '';
var desktopHead = prompt("Paste your new headline", defaultValue);

var docLayers = doc.layers.length; //getting top layers because artboards are top layers

for(var i=0;i<docLayers;i++){
aLayer = doc.layers[i];
ab = artboard_rectangle(aLayer);
aW = ab[2]-ab[0];
aH = ab[3]-ab[1];
if((aW == 1000 && aH == 1000) || (aW == 400 && aH == 500)){//add more sizes here
findTextLayer (aLayer)
}//end if for artboard size
}//end for loop

app.preferences.rulerUnits = oldPref;

function findTextLayer(pLayer){
var layLen = pLayer.layers.length;
for(var j = 0;j<layLen;j++){
var layerRef = pLayer.layers[j];
if(pLayer.layers[j].typename == 'LayerSet'){
findTextLayer (pLayer.layers[j]);
}//end if for finding layerset
else{
if (layerRef.kind === LayerKind.TEXT) {
if(layerRef.textItem.font === "Arial-BoldMT"){//make sure you have correct font name
layerRef.textItem.contents = desktopHead;
}//end if for text font
}//end if for layerkind text
}//end else
};//end for loop
 
};//end function

function artboard_rectangle(layer)
{
try {
var r = new ActionReference();
r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("artboard"));
if (layer) r.putIdentifier(stringIDToTypeID("layer"), layer.id);
else r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
var d = executeActionGet(r).getObjectValue(stringIDToTypeID("artboard")).getObjectValue(stringIDToTypeID("artboardRect"));
var bounds = new Array();
bounds[0] = d.getUnitDoubleValue(stringIDToTypeID("left"));
bounds[1] = d.getUnitDoubleValue(stringIDToTypeID("top"));
bounds[2] = d.getUnitDoubleValue(stringIDToTypeID("right"));
bounds[3] = d.getUnitDoubleValue(stringIDToTypeID("bottom"));

return bounds;
}
catch(e) { alert(e); }
}
 
 

Thanks in advance. 

This topic has been closed for replies.
Correct answer jazz-y

 

#target photoshop

var replaceColor = [
    { text: 'discount', color: '00ff00' },
    { text: 'get', color: 'ff0000' },
    { text: '20%', color: '0000ff' },
    { text: '#', color: 'ff00ff' }],
    superscriptText = '#',
    s2t = stringIDToTypeID;

var doc = app.activeDocument;
var oldPref = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;

var ab, aLayer, aW, aH

var defaultValue = 'Get 20% discount#';
var desktopHead = prompt("Paste your new headline", defaultValue);

var docLayers = doc.layers.length; //getting top layers because artboards are top layers

for (var i = 0; i < docLayers; i++) {
    aLayer = doc.layers[i];
    ab = artboard_rectangle(aLayer);
    aW = ab[2] - ab[0];
    aH = ab[3] - ab[1];
    if ((aW == 1000 && aH == 1000) || (aW == 400 && aH == 500)) {//add more sizes here
        findTextLayer(aLayer)
    }//end if for artboard size
}//end for loop

app.preferences.rulerUnits = oldPref;

function findTextLayer(pLayer) {
    var layLen = pLayer.layers.length;
    for (var j = 0; j < layLen; j++) {
        var layerRef = pLayer.layers[j];
        if (pLayer.layers[j].typename == 'LayerSet') {
            findTextLayer(pLayer.layers[j]);
        }//end if for finding layerset
        else {
            if (layerRef.kind === LayerKind.TEXT) {
                if (layerRef.textItem.font === "Arial-BoldMT") {//make sure you have correct font name
                    layerRef.textItem.contents = desktopHead;
                    for (var i = 0; i < replaceColor.length; i++) {
                        replaceTextStyleByContent(layerRef.id, replaceColor[i].text, colorDescFromHEX(replaceColor[i].color))
                    }
                    var style = new ActionDescriptor();
                    style.putEnumerated(s2t('baseline'), s2t('baseline'), s2t('superScript'))
                    replaceTextStyleByContent(layerRef.id, superscriptText, style)
                }//end if for text font
            }//end if for layerkind text
        }//end else
    };//end for loop

};//end function

function artboard_rectangle(layer) {
    try {
        var r = new ActionReference();
        r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("artboard"));
        if (layer) r.putIdentifier(stringIDToTypeID("layer"), layer.id);
        else r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
        var d = executeActionGet(r).getObjectValue(stringIDToTypeID("artboard")).getObjectValue(stringIDToTypeID("artboardRect"));
        var bounds = new Array();
        bounds[0] = d.getUnitDoubleValue(stringIDToTypeID("left"));
        bounds[1] = d.getUnitDoubleValue(stringIDToTypeID("top"));
        bounds[2] = d.getUnitDoubleValue(stringIDToTypeID("right"));
        bounds[3] = d.getUnitDoubleValue(stringIDToTypeID("bottom"));

        return bounds;
    }
    catch (e) { alert(e); }
}

function colorDescFromHEX(hex) {
    var d = new ActionDescriptor(),
        style = new ActionDescriptor(),
        c = new SolidColor;
    c.rgb.hexValue = hex;
    d.putDouble(s2t('red'), c.rgb.red)
    d.putDouble(s2t('grain'), c.rgb.green)
    d.putDouble(s2t('blue'), c.rgb.blue)
    style.putObject(s2t('color'), s2t('RGBColor'), d)

    return style;
}

function replaceTextStyleByContent(layerID, text, newStyleDesc) {
    var s2t = stringIDToTypeID;
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('textKey'));
    r.putIdentifier(s2t('layer'), layerID);
    if (executeActionGet(r).hasKey(p)) {
        var textItem = executeActionGet(r).getObjectValue(p),
            sList = textItem.getList(s2t('textStyleRange')),
            l = new ActionList(),
            styleSheet = [],
            content = textItem.getString(p);
        for (var i = 0; i < sList.count; i++) {
            var cur = sList.getObjectValue(i);
            styleSheet.push({
                from: cur.getInteger(s2t('from')),
                to: cur.getInteger(s2t('to')),
                style: function (d) {
                    if (d.hasKey(p = s2t('styleSheetHasParent')) && d.getBoolean(p)) if (d.hasKey(p = s2t('baseParentStyle'))) extendDescriptor(d.getObjectValue(p), d)
                    return d;
                }(cur.getObjectValue(s2t('textStyle'))),
            })
            styleSheet[i].text = content.substring(styleSheet[i].from, styleSheet[i].to);
        };

        do {
            var len = styleSheet.length,
                found = false;
            for (var i = 0; i < len; i++) {
                var offset = 0,
                    cur = styleSheet[i].text;
                if (cur) {
                    var match = cur.match(new RegExp(text, 'i')),
                        from, to;
                    if (match) {
                        from = cur.indexOf(match[0]) + offset
                        to = from + match[0].length
                        offset += match[0].length
                        cur = cur.substring(cur.indexOf(match[0]) + match[0].length)
                        customStyle = setCustomStyle(styleSheet[i], from, to, newStyleDesc)
                        styleSheet.splice.apply(styleSheet, [i, 1].concat(customStyle));
                        len += customStyle.length - 1;
                        i += customStyle.length - 1;
                        found = true
                    }
                }
            }
        } while (found)

        var l = new ActionList();
        for (var i = 0; i < styleSheet.length; i++) {
            var d = new ActionDescriptor();
            d.putObject(s2t('textStyle'), s2t('textStyle'), styleSheet[i].style)
            d.putInteger(s2t('from'), styleSheet[i].from)
            d.putInteger(s2t('to'), styleSheet[i].to)
            l.putObject(s2t('textStyleRange'), d)
        }
        textItem.putList(s2t('textStyleRange'), l);
        (r = new ActionReference()).putIdentifier(s2t('layer'), layerID);
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        d.putObject(s2t('to'), s2t('textLayer'), textItem);
        executeAction(s2t('set'), d, DialogModes.NO);
    }

    function setCustomStyle(baseStyleSheet, from, to, newStyleDesc) {
        var output = [],
            offset = baseStyleSheet.from;
        if (baseStyleSheet.from != from + offset) {
            output.push({
                from: baseStyleSheet.from,
                to: from + offset,
                style: baseStyleSheet.style,
                text: baseStyleSheet.text.substring(0, from)
            })
        }
        var customStyle = new ActionDescriptor();
        extendDescriptor(baseStyleSheet.style, customStyle);
        extendDescriptor(customStyle, newStyleDesc, true);

        output.push({
            from: from + offset,
            to: to + offset,
            style: newStyleDesc,
            text: null
        })
        if (baseStyleSheet.to != to + offset) {
            output.push({
                from: to + offset,
                to: baseStyleSheet.to,
                style: baseStyleSheet.style,
                text: baseStyleSheet.text.substring(to)
            })
        }
        return output;
    }

    /** tnx to 
     * https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-copy-save-styles-typeface-font-size-design-etc-of-arbitrary-text-fragments-and-apply-them-to/m-p/10522630
     */
    function extendDescriptor(src_desc, dst_desc) {
        try {
            for (var i = 0; i < src_desc.count; i++) {
                var key = src_desc.getKey(i);
                if (dst_desc.hasKey(key)) continue;
                var type = src_desc.getType(key);
                switch (type) {
                    case DescValueType.ALIASTYPE: dst_desc.putPath(key, src_desc.getPath(key)); break;
                    case DescValueType.BOOLEANTYPE: dst_desc.putBoolean(key, src_desc.getBoolean(key)); break;
                    case DescValueType.CLASSTYPE: dst_desc.putClass(key, src_desc.getClass(key)); break;
                    case DescValueType.DOUBLETYPE: dst_desc.putDouble(key, src_desc.getDouble(key)); break;
                    case DescValueType.INTEGERTYPE: dst_desc.putInteger(key, src_desc.getInteger(key)); break;
                    case DescValueType.LISTTYPE: dst_desc.putList(key, src_desc.getList(key)); break;
                    case DescValueType.RAWTYPE: dst_desc.putData(key, src_desc.getData(key)); break;
                    case DescValueType.STRINGTYPE: dst_desc.putString(key, src_desc.getString(key)); break;
                    case DescValueType.LARGEINTEGERTYPE: dst_desc.putLargeInteger(key, src_desc.getLargeInteger(key)); break;
                    case DescValueType.REFERENCETYPE: dst_desc.putReference(key, src_desc.getReference(key)); break;
                    case DescValueType.OBJECTTYPE: dst_desc.putObject(key, src_desc.getObjectType(key), src_desc.getObjectValue(key)); break;
                    case DescValueType.ENUMERATEDTYPE: dst_desc.putEnumerated(key, src_desc.getEnumerationType(key), src_desc.getEnumerationValue(key)); break;
                    case DescValueType.UNITDOUBLE: dst_desc.putUnitDouble(key, src_desc.getUnitDoubleType(key), src_desc.getUnitDoubleValue(key)); break;
                    default: alert("Unknown data type in descriptor"); return false;
                }
            }
            return true;
        }
        catch (e) { throw (e); }
    }
}

 

* in principle, there is no need to update the text layer when searching and changing each word (we can build a new style sheet and update text layer once), however, I did not take into account this way based on the initial setting of the task and now more effort is required to optimize the code. Perhaps later I will return to this issue.

2 replies

Legend
October 25, 2022

 

#target photoshop

var greenText = 'discount',
    greenColor = [0, 255, 0],
    superscriptText = '#',
    s2t = stringIDToTypeID;

var doc = app.activeDocument;
var oldPref = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;

var ab, aLayer, aW, aH

var defaultValue = 'Get 20% discount#';
var desktopHead = prompt("Paste your new headline", defaultValue);

var docLayers = doc.layers.length; //getting top layers because artboards are top layers

for (var i = 0; i < docLayers; i++) {
    aLayer = doc.layers[i];
    ab = artboard_rectangle(aLayer);
    aW = ab[2] - ab[0];
    aH = ab[3] - ab[1];
    if ((aW == 1000 && aH == 1000) || (aW == 400 && aH == 500)) {//add more sizes here
        findTextLayer(aLayer)
    }//end if for artboard size
}//end for loop

app.preferences.rulerUnits = oldPref;

function findTextLayer(pLayer) {
    var layLen = pLayer.layers.length;
    for (var j = 0; j < layLen; j++) {
        var layerRef = pLayer.layers[j];
        if (pLayer.layers[j].typename == 'LayerSet') {
            findTextLayer(pLayer.layers[j]);
        }//end if for finding layerset
        else {
            if (layerRef.kind === LayerKind.TEXT) {
                if (layerRef.textItem.font === "Arial-BoldMT") {//make sure you have correct font name
                    layerRef.textItem.contents = desktopHead;

                    var d = new ActionDescriptor(),
                        style = new ActionDescriptor();
                    d.putDouble(s2t('red'), greenColor[0])
                    d.putDouble(s2t('grain'), greenColor[1])
                    d.putDouble(s2t('blue'), greenColor[2])
                    style.putObject(s2t('color'), s2t('RGBColor'), d)

                    replaceTextStyleByContent(layerRef.id, greenText, style)

                    var style = new ActionDescriptor();
                    style.putEnumerated(s2t('baseline'), s2t('baseline'), s2t('superScript'))
                    replaceTextStyleByContent(layerRef.id, superscriptText, style)
                }//end if for text font
            }//end if for layerkind text
        }//end else
    };//end for loop

};//end function

function artboard_rectangle(layer) {
    try {
        var r = new ActionReference();
        r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("artboard"));
        if (layer) r.putIdentifier(stringIDToTypeID("layer"), layer.id);
        else r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
        var d = executeActionGet(r).getObjectValue(stringIDToTypeID("artboard")).getObjectValue(stringIDToTypeID("artboardRect"));
        var bounds = new Array();
        bounds[0] = d.getUnitDoubleValue(stringIDToTypeID("left"));
        bounds[1] = d.getUnitDoubleValue(stringIDToTypeID("top"));
        bounds[2] = d.getUnitDoubleValue(stringIDToTypeID("right"));
        bounds[3] = d.getUnitDoubleValue(stringIDToTypeID("bottom"));

        return bounds;
    }
    catch (e) { alert(e); }
}

function replaceTextStyleByContent(layerID, text, newStyleDesc) {
    var s2t = stringIDToTypeID;
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('textKey'));
    r.putIdentifier(s2t('layer'), layerID);
    if (executeActionGet(r).hasKey(p)) {
        var textItem = executeActionGet(r).getObjectValue(p),
            sList = textItem.getList(s2t('textStyleRange')),
            l = new ActionList(),
            styleSheet = [],
            content = textItem.getString(p);
        for (var i = 0; i < sList.count; i++) {
            var cur = sList.getObjectValue(i);
            styleSheet.push({
                from: cur.getInteger(s2t('from')),
                to: cur.getInteger(s2t('to')),
                style: function (d) {
                    if (d.hasKey(p = s2t('styleSheetHasParent')) && d.getBoolean(p)) if (d.hasKey(p = s2t('baseParentStyle'))) extendDescriptor(d.getObjectValue(p), d)
                    return d;
                }(cur.getObjectValue(s2t('textStyle'))),
            })
            styleSheet[i].text = content.substring(styleSheet[i].from, styleSheet[i].to);
        };

        do {
            var len = styleSheet.length,
                found = false;
            for (var i = 0; i < len; i++) {
                var offset = 0,
                    cur = styleSheet[i].text;
                if (cur) {
                    var match = cur.match(new RegExp(text, 'i')),
                        from, to;
                    if (match) {
                        from = cur.indexOf(match[0]) + offset
                        to = from + match[0].length
                        offset += match[0].length
                        cur = cur.substring(cur.indexOf(match[0]) + match[0].length)
                        customStyle = setCustomStyle(styleSheet[i], from, to, newStyleDesc)
                        styleSheet.splice.apply(styleSheet, [i, 1].concat(customStyle));
                        len += customStyle.length - 1;
                        i += customStyle.length - 1;
                        found = true
                    }
                }
            }
        } while (found)

        var l = new ActionList();
        for (var i = 0; i < styleSheet.length; i++) {
            var d = new ActionDescriptor();
            d.putObject(s2t('textStyle'), s2t('textStyle'), styleSheet[i].style)
            d.putInteger(s2t('from'), styleSheet[i].from)
            d.putInteger(s2t('to'), styleSheet[i].to)
            l.putObject(s2t('textStyleRange'), d)
        }
        textItem.putList(s2t('textStyleRange'), l);
        (r = new ActionReference()).putIdentifier(s2t('layer'), layerID);
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        d.putObject(s2t('to'), s2t('textLayer'), textItem);
        executeAction(s2t('set'), d, DialogModes.NO);
    }

    function setCustomStyle(baseStyleSheet, from, to, newStyleDesc) {
        var output = [],
            offset = baseStyleSheet.from;
        if (baseStyleSheet.from != from + offset) {
            output.push({
                from: baseStyleSheet.from,
                to: from + offset,
                style: baseStyleSheet.style,
                text: baseStyleSheet.text.substring(0, from)
            })
        }
        var customStyle = new ActionDescriptor();
        extendDescriptor(baseStyleSheet.style, customStyle);
        extendDescriptor(customStyle, newStyleDesc, true);

        output.push({
            from: from + offset,
            to: to + offset,
            style: newStyleDesc,
            text: null
        })
        if (baseStyleSheet.to != to + offset) {
            output.push({
                from: to + offset,
                to: baseStyleSheet.to,
                style: baseStyleSheet.style,
                text: baseStyleSheet.text.substring(to)
            })
        }
        return output;
    }

    /** tnx to @r-bin
     * https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-copy-save-styles-typeface-font-size-design-etc-of-arbitrary-text-fragments-and-apply-them-to/m-p/10522630
     */
    function extendDescriptor(src_desc, dst_desc) {
        try {
            for (var i = 0; i < src_desc.count; i++) {
                var key = src_desc.getKey(i);
                if (dst_desc.hasKey(key)) continue;
                var type = src_desc.getType(key);
                switch (type) {
                    case DescValueType.ALIASTYPE: dst_desc.putPath(key, src_desc.getPath(key)); break;
                    case DescValueType.BOOLEANTYPE: dst_desc.putBoolean(key, src_desc.getBoolean(key)); break;
                    case DescValueType.CLASSTYPE: dst_desc.putClass(key, src_desc.getClass(key)); break;
                    case DescValueType.DOUBLETYPE: dst_desc.putDouble(key, src_desc.getDouble(key)); break;
                    case DescValueType.INTEGERTYPE: dst_desc.putInteger(key, src_desc.getInteger(key)); break;
                    case DescValueType.LISTTYPE: dst_desc.putList(key, src_desc.getList(key)); break;
                    case DescValueType.RAWTYPE: dst_desc.putData(key, src_desc.getData(key)); break;
                    case DescValueType.STRINGTYPE: dst_desc.putString(key, src_desc.getString(key)); break;
                    case DescValueType.LARGEINTEGERTYPE: dst_desc.putLargeInteger(key, src_desc.getLargeInteger(key)); break;
                    case DescValueType.REFERENCETYPE: dst_desc.putReference(key, src_desc.getReference(key)); break;
                    case DescValueType.OBJECTTYPE: dst_desc.putObject(key, src_desc.getObjectType(key), src_desc.getObjectValue(key)); break;
                    case DescValueType.ENUMERATEDTYPE: dst_desc.putEnumerated(key, src_desc.getEnumerationType(key), src_desc.getEnumerationValue(key)); break;
                    case DescValueType.UNITDOUBLE: dst_desc.putUnitDouble(key, src_desc.getUnitDoubleType(key), src_desc.getUnitDoubleValue(key)); break;
                    default: alert("Unknown data type in descriptor"); return false;
                }
            }
            return true;
        }
        catch (e) { throw (e); }
    }
}

 

Vibi DevAuthor
Inspiring
October 26, 2022

Thank you so much @jazz-y This is working great. I am able to replace it with any symbol to make it a superscript. That's amazing. I just had one more question. Is it possible to input multiple words to change the colors? Currently, it's only a one-word "discount". What if I have multiple words that need to change color? 

jazz-yCorrect answer
Legend
October 26, 2022

 

#target photoshop

var replaceColor = [
    { text: 'discount', color: '00ff00' },
    { text: 'get', color: 'ff0000' },
    { text: '20%', color: '0000ff' },
    { text: '#', color: 'ff00ff' }],
    superscriptText = '#',
    s2t = stringIDToTypeID;

var doc = app.activeDocument;
var oldPref = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;

var ab, aLayer, aW, aH

var defaultValue = 'Get 20% discount#';
var desktopHead = prompt("Paste your new headline", defaultValue);

var docLayers = doc.layers.length; //getting top layers because artboards are top layers

for (var i = 0; i < docLayers; i++) {
    aLayer = doc.layers[i];
    ab = artboard_rectangle(aLayer);
    aW = ab[2] - ab[0];
    aH = ab[3] - ab[1];
    if ((aW == 1000 && aH == 1000) || (aW == 400 && aH == 500)) {//add more sizes here
        findTextLayer(aLayer)
    }//end if for artboard size
}//end for loop

app.preferences.rulerUnits = oldPref;

function findTextLayer(pLayer) {
    var layLen = pLayer.layers.length;
    for (var j = 0; j < layLen; j++) {
        var layerRef = pLayer.layers[j];
        if (pLayer.layers[j].typename == 'LayerSet') {
            findTextLayer(pLayer.layers[j]);
        }//end if for finding layerset
        else {
            if (layerRef.kind === LayerKind.TEXT) {
                if (layerRef.textItem.font === "Arial-BoldMT") {//make sure you have correct font name
                    layerRef.textItem.contents = desktopHead;
                    for (var i = 0; i < replaceColor.length; i++) {
                        replaceTextStyleByContent(layerRef.id, replaceColor[i].text, colorDescFromHEX(replaceColor[i].color))
                    }
                    var style = new ActionDescriptor();
                    style.putEnumerated(s2t('baseline'), s2t('baseline'), s2t('superScript'))
                    replaceTextStyleByContent(layerRef.id, superscriptText, style)
                }//end if for text font
            }//end if for layerkind text
        }//end else
    };//end for loop

};//end function

function artboard_rectangle(layer) {
    try {
        var r = new ActionReference();
        r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("artboard"));
        if (layer) r.putIdentifier(stringIDToTypeID("layer"), layer.id);
        else r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
        var d = executeActionGet(r).getObjectValue(stringIDToTypeID("artboard")).getObjectValue(stringIDToTypeID("artboardRect"));
        var bounds = new Array();
        bounds[0] = d.getUnitDoubleValue(stringIDToTypeID("left"));
        bounds[1] = d.getUnitDoubleValue(stringIDToTypeID("top"));
        bounds[2] = d.getUnitDoubleValue(stringIDToTypeID("right"));
        bounds[3] = d.getUnitDoubleValue(stringIDToTypeID("bottom"));

        return bounds;
    }
    catch (e) { alert(e); }
}

function colorDescFromHEX(hex) {
    var d = new ActionDescriptor(),
        style = new ActionDescriptor(),
        c = new SolidColor;
    c.rgb.hexValue = hex;
    d.putDouble(s2t('red'), c.rgb.red)
    d.putDouble(s2t('grain'), c.rgb.green)
    d.putDouble(s2t('blue'), c.rgb.blue)
    style.putObject(s2t('color'), s2t('RGBColor'), d)

    return style;
}

function replaceTextStyleByContent(layerID, text, newStyleDesc) {
    var s2t = stringIDToTypeID;
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('textKey'));
    r.putIdentifier(s2t('layer'), layerID);
    if (executeActionGet(r).hasKey(p)) {
        var textItem = executeActionGet(r).getObjectValue(p),
            sList = textItem.getList(s2t('textStyleRange')),
            l = new ActionList(),
            styleSheet = [],
            content = textItem.getString(p);
        for (var i = 0; i < sList.count; i++) {
            var cur = sList.getObjectValue(i);
            styleSheet.push({
                from: cur.getInteger(s2t('from')),
                to: cur.getInteger(s2t('to')),
                style: function (d) {
                    if (d.hasKey(p = s2t('styleSheetHasParent')) && d.getBoolean(p)) if (d.hasKey(p = s2t('baseParentStyle'))) extendDescriptor(d.getObjectValue(p), d)
                    return d;
                }(cur.getObjectValue(s2t('textStyle'))),
            })
            styleSheet[i].text = content.substring(styleSheet[i].from, styleSheet[i].to);
        };

        do {
            var len = styleSheet.length,
                found = false;
            for (var i = 0; i < len; i++) {
                var offset = 0,
                    cur = styleSheet[i].text;
                if (cur) {
                    var match = cur.match(new RegExp(text, 'i')),
                        from, to;
                    if (match) {
                        from = cur.indexOf(match[0]) + offset
                        to = from + match[0].length
                        offset += match[0].length
                        cur = cur.substring(cur.indexOf(match[0]) + match[0].length)
                        customStyle = setCustomStyle(styleSheet[i], from, to, newStyleDesc)
                        styleSheet.splice.apply(styleSheet, [i, 1].concat(customStyle));
                        len += customStyle.length - 1;
                        i += customStyle.length - 1;
                        found = true
                    }
                }
            }
        } while (found)

        var l = new ActionList();
        for (var i = 0; i < styleSheet.length; i++) {
            var d = new ActionDescriptor();
            d.putObject(s2t('textStyle'), s2t('textStyle'), styleSheet[i].style)
            d.putInteger(s2t('from'), styleSheet[i].from)
            d.putInteger(s2t('to'), styleSheet[i].to)
            l.putObject(s2t('textStyleRange'), d)
        }
        textItem.putList(s2t('textStyleRange'), l);
        (r = new ActionReference()).putIdentifier(s2t('layer'), layerID);
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        d.putObject(s2t('to'), s2t('textLayer'), textItem);
        executeAction(s2t('set'), d, DialogModes.NO);
    }

    function setCustomStyle(baseStyleSheet, from, to, newStyleDesc) {
        var output = [],
            offset = baseStyleSheet.from;
        if (baseStyleSheet.from != from + offset) {
            output.push({
                from: baseStyleSheet.from,
                to: from + offset,
                style: baseStyleSheet.style,
                text: baseStyleSheet.text.substring(0, from)
            })
        }
        var customStyle = new ActionDescriptor();
        extendDescriptor(baseStyleSheet.style, customStyle);
        extendDescriptor(customStyle, newStyleDesc, true);

        output.push({
            from: from + offset,
            to: to + offset,
            style: newStyleDesc,
            text: null
        })
        if (baseStyleSheet.to != to + offset) {
            output.push({
                from: to + offset,
                to: baseStyleSheet.to,
                style: baseStyleSheet.style,
                text: baseStyleSheet.text.substring(to)
            })
        }
        return output;
    }

    /** tnx to 
     * https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-copy-save-styles-typeface-font-size-design-etc-of-arbitrary-text-fragments-and-apply-them-to/m-p/10522630
     */
    function extendDescriptor(src_desc, dst_desc) {
        try {
            for (var i = 0; i < src_desc.count; i++) {
                var key = src_desc.getKey(i);
                if (dst_desc.hasKey(key)) continue;
                var type = src_desc.getType(key);
                switch (type) {
                    case DescValueType.ALIASTYPE: dst_desc.putPath(key, src_desc.getPath(key)); break;
                    case DescValueType.BOOLEANTYPE: dst_desc.putBoolean(key, src_desc.getBoolean(key)); break;
                    case DescValueType.CLASSTYPE: dst_desc.putClass(key, src_desc.getClass(key)); break;
                    case DescValueType.DOUBLETYPE: dst_desc.putDouble(key, src_desc.getDouble(key)); break;
                    case DescValueType.INTEGERTYPE: dst_desc.putInteger(key, src_desc.getInteger(key)); break;
                    case DescValueType.LISTTYPE: dst_desc.putList(key, src_desc.getList(key)); break;
                    case DescValueType.RAWTYPE: dst_desc.putData(key, src_desc.getData(key)); break;
                    case DescValueType.STRINGTYPE: dst_desc.putString(key, src_desc.getString(key)); break;
                    case DescValueType.LARGEINTEGERTYPE: dst_desc.putLargeInteger(key, src_desc.getLargeInteger(key)); break;
                    case DescValueType.REFERENCETYPE: dst_desc.putReference(key, src_desc.getReference(key)); break;
                    case DescValueType.OBJECTTYPE: dst_desc.putObject(key, src_desc.getObjectType(key), src_desc.getObjectValue(key)); break;
                    case DescValueType.ENUMERATEDTYPE: dst_desc.putEnumerated(key, src_desc.getEnumerationType(key), src_desc.getEnumerationValue(key)); break;
                    case DescValueType.UNITDOUBLE: dst_desc.putUnitDouble(key, src_desc.getUnitDoubleType(key), src_desc.getUnitDoubleValue(key)); break;
                    default: alert("Unknown data type in descriptor"); return false;
                }
            }
            return true;
        }
        catch (e) { throw (e); }
    }
}

 

* in principle, there is no need to update the text layer when searching and changing each word (we can build a new style sheet and update text layer once), however, I did not take into account this way based on the initial setting of the task and now more effort is required to optimize the code. Perhaps later I will return to this issue.

Chuck Uebele
Community Expert
Community Expert
October 25, 2022

Just looking at old unanswered post. That script I wrote, will mess up with your example here, as it looks for the % sign after discount.

Vibi DevAuthor
Inspiring
October 26, 2022

Ya, that's right Chuck. The solution given by @jazz-y  for the superscript works well. Thanks to both of you for pitching in. Nice to have such skillful developers here.