ExtendScript Parse resource string to create variable paths

641 views Asked by At

I am looking to speed up my workflow by parsing a resource string to auto create my variable paths. Not only can it get confusing to look at large scale UI's, it's even worse getting the paths written out to access each element. ExtendScript ha s a lot of "quirks" we'll call it. So for sake of simplicity the sample below is cut way down.

var res = "group{,\
itemsToRenameGrp: Group{,\
    itemsToRenameDD: DropDownList{},\
    help: Button{},\
},\
listTabPnl: Panel{,\
    listOfItemsTab: Panel{,\
        listOfItemsPnl: Panel{,\
            listOfItemsLB: ListBox{},\
        },\
        confirmChanges: Button{},\
    },\
    badItemsTab: Panel{,\
        errorLogET: EditText{},\
    },\
},\
}";

I need to create paths like this for variable assignment:

itemsToRenameGrp.itemsToRenameDD
itemsToRenameGrp.help

listTabPnl.listOfItemsTab.listOfItemsPnl
listTabPnl.listOfItemsTab.listOfItemsPnl.listOfItemsLB
listTabPnl.listOfItemsTab.confirmChanges

listTabPnl.badItemsTab
listTabPnl.badItemsTab.errorLogET

I know there has to be a way via RegExp to parse the tab spaces, or "},\" section endings to make this work, I just can't figure out the solution myself. Any help is appreciated. Thanks.

4

There are 4 answers

1
Dirk On

Those backslashes should not be needed, there is a special multi-line mode when you start a string with three double-quotes.

Rather than parsing the source I'd leave that to ExtendScript and iterate the resulting UI objects.

0
Armali On

It's messy, but I finally figured out something that gives me what I wanted.

Solution:

var res = "group{,\
    itemsToRenameGrp: Group{,\
        itemsToRenameDD: DropDownList{},\
        help: Button{},\
    },\
    listTabPnl: Panel{,\
        listOfItemsTab: Panel{,\
            listOfItemsPnl: Panel{,\
                listOfItemsLB: ListBox{},\
            },\
            confirmChanges: Button{},\
        },\
        badItemsTab: Panel{,\
            errorLogET: EditText{},\
        },\
    },\
}";

var lines = res.split("\n");
var numLines = lines.length;
var variablePaths = new Array();
var val, newVal, firstColon, firstBrace, lastBrace, tabLength, oldTabLength, path, splitPath;
path = "";
oldTabLength = 0;
if(numLines > 0){
    for(var r=0; r<numLines; r++){
        val = lines[r];
        firstColon = val.indexOf(":");
        firstBrace = val.indexOf("{");
        lastBrace = val.lastIndexOf("}");
        try{tabLength = val.match(/\t/g).length}catch(err){};   /*  Count tabs  */
        if(firstColon > 0 && firstBrace > 0){   /*  Valid possible element line */
            if(firstColon < firstBrace){    /*  Confirmed element line  */
                newVal = val.substring(0, firstColon);  /*  Strip line down to just name and leading tabs   */
                if(tabLength > oldTabLength){   /*  Checks for line indent (child element)  */
                    path += "." + newVal.replace(new RegExp("\t", "g"), "");
                }else if(tabLength == oldTabLength){    /*  Checks for line indent match (same parent as previous element)  */
                    path = path.substring(0, path.lastIndexOf(".")) + "." + newVal.replace(new RegExp("\t", "g"), "");
                }else  if(tabLength < oldTabLength){    /*  Checks for line indent (new parent to add)  */
                    splitPath = path.split(".");
                    try{    /*  This section adjusts how far back in heirarchy to remove    */
                        if(tabLength > 0){
                            splitPath.length -= ((oldTabLength - tabLength)+1);
                        }else{
                            splitPath.length -= (oldTabLength - tabLength);
                        }
                    }catch(err){};
                    path = splitPath.join(".").toString() + "." + newVal.replace(new RegExp("\t", "g"), "");    /*  Creates new cleaned up string path (tabs removed)   */
                }
                oldTabLength = tabLength;
                if(tabLength >= oldTabLength){
                    variablePaths.push(path);   /*  Populates array */
                }
            }
        }
    }
}else{
    alert("Nothing to process");
}

alert("Element Names:\n" + variablePaths.join("\n"));

– David Torno

0
ariestav On

I agree that it is rather cumbersome to look at complex resource strings and then have to write "paths" to the UI elements that you want to work with. I'm not sure RegEx is the way, and I have not looked too far into it, but the solution I've come up with is to create a function that returns a "flattened pathway" to the elements so that I can refer to them with ease. If the resource string changes, then all I have to do is modify the "flattened pathway" function to account for those changes--this way I don't need to change anything elsewhere in the code.

For example, given the code you posted, I would make a function that might look something like this:

function getGUI(ui){

  var gui = {};

  gui.lRename  = ui.itemsToRenameGrp.itemsToRenameDD;
  gui.bHelp    = ui.itemsToRenameGrp.help;
  gui.lItems   = ui.listTabPn1.listOfItemsTab.listOfItemsPn1.listOfItemsLB;
  gui.bConfirm = ui.listTabPn1.listOfItemsTab.confirmChanges;
  gui.eLog     = ui.listTabPn1.badItemsTab.errorLogET;

  return gui;
}

Then when you finish "building" your UI with a Window object, call that function like so:

var _mainGUI = getGUI({variable that holds your Window object});

Now, when you want to access the elements, just call them like:

_mainGUI.lRename
_mainGUI.bConfirm
_mainGUI.lItems

...and so on. So this way if you ever make a change to the resource string, you'll just have to modify the getGUI function and your application code can remain the same. Hopefully this helps, and my apologies for the initial, incomplete, answer post--I accidentally hit the submit button too early.

0
Xavier Gomez On

Another possibility is parse not the the string but the finished window, like so:

function loadNamedWidgets(cont, _target){
    // cont : ScruitUI container
    // _target : Object
    var k, K, child, id;
    K=cont.children.length;
    for (k=0; k<K; k++){
        child = cont.children[k];
        if (/^(Window|Panel|Group)$/.test(child.constructor.name)){
            loadNamedWidgets(child, _target);
            }
        else{
            // check that a ownProperty of cont is same as child
            for (id in cont){
                if (cont.hasOwnProperty(id)){
                    if (cont[id] === child) {_target[id] = child; break;};
                    }
                else break;
                };
            };
        };
    return;
    };

TEST : In the test below, *radio1 and radio2 will be written twice, but those from p2 will overwrite those from p1 (name conflict), *titleST (unnamed) added at the end will not appear while valueET (named) will.

var w = new Window("palette{\
            text : 'hi',\
            header : Group{\
                        superBtn : Button{},\
                        extraBtn : Button{},\
                        helpBtn : Button{},\
                        },\
            body: Group{\
                        p1 : Panel{\
                                    _tag : 1,\
                                    radio1 : RadioButton{},\
                                    radio2 : RadioButton{},\
                                    },\
                        p2 : Panel{\
                                    _tag : 2,\
                                    radio1 : RadioButton{},\
                                    radio2 : RadioButton{},\
                                    },\
                        },\
            console : Group{\
                        consoleET : EditText{text: '', properties: {readonly: true}},\
                        },\
            footer : Group{}\
            }");
var titleST = w.footer.add("statictext{text : 'title'}");
var valueET = w.footer.valueET = w.footer.add("edittext{text : '0000'}");
var binds = {};
loadNamedWidgets(w, binds);

$.writeln(binds.toSource());