Skip to main content
Inspiring
February 8, 2022
Answered

Script prefernce file

  • February 8, 2022
  • 4 replies
  • 3673 views

I am interested to find out how a preference file works with a custom script.

How is the preference file or settings file normally attached to the script?

Does this makes sense to attach  the parent-settings.jsx to the parent .jsx script?

 

parent.jsx

parent-settings.jsx

This topic has been closed for replies.
Correct answer Chuck Uebele

Thanks Chuck, the functionality of your script saving, reusing, and updating presets is very useful.

I copied the UI portion of your script to a new script file and was able to alert the values from the XML file.

The issue is that I'm only able to get the original default values even after I update the preference XML with new data. I'm not sure if I'm doing this correctly tho, because it worked without having to deal with the dlg.hide() and onClick(), onChange() methods.  Here is a screen recording for reference:

https://imageasel.com/wp-content/uploads/Screen-Recording-2022-02-28-at-10.36.49-PM.mp4


You still need all this code in the script that reads the XML

///////////Preference and XML vars  YOU NEED ALL THIS CODE
  
var presetList = new Array(  );//Blank array to be populated with the users preferences stored in an XML file  

var xmlFile = new File('~/Desktop/XYZ/xmlTest.xml');  
if(xmlFile.exists){  
    prefXML = new XML(readXMLFile(xmlFile))  
    };// see if a preference file exists and load it.  
else {alert('There is no preset file')}  
  
var dlg = new Window('dialog','XML Test')  

        
        /////////All elements separated in a separate window
        ///////////////////////////////////////////////////////////////////////////////////////////  THIS PART WHICH IS JUST THE CODE FOR THE UI IS THE ONLY THING THAT YOU CAN CHANGE
       
       var dlg = new Window('dialog','XML Test')  
        
        var myCheckBox = dlg.add('checkbox',undefined,'Check Box'); myCheckBox.name='myCheckBox';  
        var myRadio1 = dlg.add('radiobutton',undefined,'Radio 1'); myRadio1.name='myRadio1';  
        var myRadio2 = dlg.add('radiobutton',undefined,'Radio 2'); myRadio2.name='myRadio2';  
        myRadio1.value = true;  
        var myEditT = dlg.add('edittext',undefined,'Edit Test '); myEditT.name='myEditT';  
        var myStaticT = dlg.add('statictext',undefined,'Static Test '); myStaticT.name='myStaticT';  
        var mySlider = dlg.add('slider',undefined,25,0,100); mySlider.name='mySlider';  
        var myDropList = dlg.add('dropdownlist',undefined,['one','two','three']); myDropList.name='myDropList';  
          
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
         ///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

     
/////////////////////////////////// This needs to be in any dialog box for the presets to work///////////////////////////////////////////////////////////  
/////////////////////////////////// The name of the dialog has to match whatever is in the current UI///////////////////////////////////////////  
dlg.gp = dlg.add('group');  
dlg.gp.orientation = 'row';  
    var presetListDrop = dlg.gp.add('dropdownlist',undefined, ['No Presets']); //presetListDrop.name = 'presetListDrop';  
        presetListDrop.size = [200,16]  
        presetListDrop.selection = 0;  

      if(prefXML.presets.children().length()>0){//loads presets into UI  
            setPresetList()      
            setUIvar(prefXML,0,dlg)  
            presetListDrop.selection = 0
            }  
  
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  
      

  
  
dlg.hide();  
////////////////////////////////////////////////////

alert (myCheckBox.value + '\n' + myEditT.text)
  
//  YOU NEED THE REST OF THIS CODE
////////////////////////////////Presets//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  

////////////////////////////////////////////////////////////////////////////////////////////////  
//function loops through the ui object and if a control item has been assigned a name uses that name to look up the preset value in the XML.  
function setUIvar(x,n,d){//x= xml file; n = node number (0 is default node), d = UI dialog  
  
    var currentXMLVal;//used to store values from XML file.  When this value is assigned, it checks to see if value from XML exist  
    var noMatch = false  
      
    for(var i = 0;i<d.children.length;i++){  
        noMatch = false;  
          
        if(d.children[i].type == 'panel' || d.children[i].type == 'group' || d.children[i].type == 'tab' || d.children[i].type == 'tabbedpanel'){setUIvar(x,n,d.children[i])};//reruns function if child is container and not control item.      
        else{  
            if(d.children[i].name){//Checks to see if child has a name assigned so only will reset those control items that have a name will be stored.  
                try{  
                    //Assigns all variables from presets node.  The "n" tells which preset to select.   
                    currentXMLVal = x.presets.preset[n].child(d.children[i].name);     
                    if(currentXMLVal == 'null'){currentXMLVal = null};  
                    }//end try  
                //catch assigns 'no_good' to current XMLVal so that if there is no value in the XML file, it will not try to assign a bad value to the UI controls.  
                catch(e){currentXMLVal = 'no_good'};//end catch  
                //switch makes sure proper type of value is reassigned back to UI controls.  
                if(x.presets.preset[n].child(d.children[i].name).length() > 0 || d.children[i].type == 'button'){  
                      
                    switch(d.children[i].type){  
                        case 'radiobutton':  
                            d.children[i].value = returnBoolean(currentXMLVal);  
                            break;  
                         case 'checkbox':  
                            d.children[i].value = returnBoolean(currentXMLVal);                          
                            break;  
                        case 'edittext':  
                            d.children[i].text = currentXMLVal;  
                            break;  
                        case 'slider':  
                            d.children[i].value = parseFloat(currentXMLVal);  
                            break;  
                        case 'dropdownlist':  
                            varHold = false;  
  
                          if(x.presets.preset[n].child(d.children[i].name).@selecIndex.toString() == 'null'){d.children[i].selection = null}  
                          else{d.children[i].selection = parseInt(x.presets.preset[n].child(d.children[i].name).@selecIndex)};  
  
                          break;  
                          };//end switch else  
  
                   };//end if to see if there is a good value from the XML  
                 
                };//end if for UI control having name  
            };//end else for if child is container or control  
        };//end for loop   
  
 };//end function setUIvar  
  
 //function returns a boolean value.  Values stored in XML are returned as strings, so they need to be converted back to boolean values.  
function returnBoolean(b){  
    if(b == 'true'){return true}  
    else{return false}  
    };  
  
//Function resets the values of the preset list when items are added or deleted.  
function setPresetList(){  
    presetList = new Array();  
    presetListDrop.removeAll();  
    for(var i=0;i<prefXML.presets.children().length();i++){presetListDrop.add('item',prefXML.presets.children()[i].@presetName)}  
};//end function setPresetList  
  
function readXMLFile(file) {  
    if (!file.exists) {  
        alert( "Cannot find file: " + deodeURI(file.absoluteURI));  
        }  
    else{  
        file.encoding = "UTF8";  
        file.lineFeed = "unix";  
        file.open("r", "TEXT", "????");  
        var str = file.read();  
        file.close();  
  
        return new XML(str);  
        };  
};  

4 replies

Chuck Uebele
Community Expert
Community Expert
February 26, 2022

I know I posted an example with one script that I wrote, but here is a simplified version of just the UI and the code to save the UI variables to an XML file. Like I said before, the nice thing about this script is that you can change the UI at any time and the script will read the UI and store all the variables.

 

///////////Preference and XML vars  
var startNodes = new XML('<root><presets/></root>');//creates a start for addin info to the XML preference file.  
//var startNodes = new XML('<root><presets><preset presetName ="Current Default"/></presets></root>');//creates a start for addin info to the XML preference file.  
var prefXML = new XML();// the actual XML file that holds the preferences until written to a file.  
//var prefXML = new XML();// the actual XML file that holds the preferences until written to a file.  
var presetList = new Array(  );//Blank array to be populated with the users preferences stored in an XML file  
var saveName;//Name for the saved preset  
  
var xmlFile = new File('~/Desktop/XYZ/xmlTest.xml');  
if(xmlFile.exists){  
    prefXML = new XML(readXMLFile(xmlFile))  
    };// see if a preference file exists and load it.  
else {prefXML = startNodes}  
  
var dlg = new Window('dialog','XML Test')  

        
        /////////All elements separated in a separate window
        ///////////////////////////////////////////////////////////////////////////////////////////
       
       var dlg = new Window('dialog','XML Test')  
        
        var myCheckBox = dlg.add('checkbox',undefined,'Check Box'); myCheckBox.name='myCheckBox';  
        var myRadio1 = dlg.add('radiobutton',undefined,'Radio 1'); myRadio1.name='myRadio1';  
        var myRadio2 = dlg.add('radiobutton',undefined,'Radio 2'); myRadio2.name='myRadio2';  
        myRadio1.value = true;  
        var myEditT = dlg.add('edittext',undefined,'Edit Test '); myEditT.name='myEditT';  
        var myStaticT = dlg.add('statictext',undefined,'Static Test '); myStaticT.name='myStaticT';  
        var mySlider = dlg.add('slider',undefined,25,0,100); mySlider.name='mySlider';  
        var myDropList = dlg.add('dropdownlist',undefined,['one','two','three']); myDropList.name='myDropList';  
          
         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
         ///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

     
/////////////////////////////////// This needs to be in any dialog box for the presets to work///////////////////////////////////////////////////////////  
/////////////////////////////////// The name of the dialog has to match whatever is in the current UI///////////////////////////////////////////  
dlg.gp = dlg.add('group');  
dlg.gp.orientation = 'row';  
    var presetListDrop = dlg.gp.add('dropdownlist',undefined, ['No Presets']); //presetListDrop.name = 'presetListDrop';  
        presetListDrop.size = [200,16]  
        presetListDrop.selection = 0;  
          
        presetListDrop.onChange = function(){//updates UI when new preset is selected  
              if(prefXML.presets.children().length()>0){//loads presets into UI                       
                 setUIvar(prefXML,parseInt(presetListDrop.selection),dlg);  
              };                  
        };          
    var saveP = dlg.gp.add('button',undefined,'Create New Preset')  
    var deleteP = dlg.gp.add('button',undefined,'Delete Current Preset')  
  
        saveP.onClick = function(){  
            var goodName = true;  
            saveName = prompt ('Enter a name for the preset', '', 'Preset Save');  
            
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////   
            
            for(var i=0;i<presetListDrop.items.length;i++){  
                if(presetListDrop.items[i].text==saveName){  
                    goodName = false;  
                    alert(saveName +' is already in use. Choose another name.')  
                    }   
                }  
             
            if(saveName && goodName){                
                storePrefs()  
                presetListDrop.selection = presetListDrop.items.length -1  
                }  
            };  
          
        deleteP.onClick = function(){  
            if(isNaN(parseInt(presetListDrop.selection))){alert('You must select a preset to delete first')}  
            else{  
                var delPre = confirm ('Do you want to delete the preset "' + presetListDrop.selection.text +'"?', 'Yes', 'Delete Preset')  
                if(delPre){  
                    delete prefXML.presets.preset[parseInt(presetListDrop.selection)];  
                    setPresetList();  
                    writeXMLFile(xmlFile,prefXML);  
                    presetListDrop.selection = 0  
                }//end if  
            };//end else  
        };//end function      
  
  
      if(prefXML.presets.children().length()>0){//loads presets into UI  
            setPresetList()      
            setUIvar(prefXML,0,dlg)  
            //presetListDrop.selection = 0  
            }  
  
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  
      
    var myOkButton = dlg.add('button',undefined,'Close');  
  
    myOkButton.onClick = function(){dlg.close()};  
  
  
dlg.show();  
  
  
////////////////////////////////Presets//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  
//function to add a new preset  
function storePrefs(){  
    var tempXML  
        tempXML = new XML('<root><presets><preset presetName ="' + saveName + '"/></presets></root>');  
        setXML(tempXML,0,dlg);  
        prefXML.presets.appendChild (XML(tempXML.presets.preset[0]))  
        setPresetList();               
        writeXMLFile(xmlFile,prefXML);        
      };//end function storePrefs  
    
  
/////////////////////////////////////////////////////////////////////////////////////////////////////  
//function loops through the ui object and if the control items have been assigned a name it stores the name and the value to an XML file.  
 function setXML(x,n,d){//x = xml file, n = starting node, d = dialog.   
    for(var i = 0;i<d.children.length;i++){  
       if(d.children[i].type == 'panel' || d.children[i].type == 'group' || d.children[i].type == 'tabbedpanel' || d.children[i].type == 'tab'){setXML(x,n,d.children[i])}//loops though UI and restarts function if it comes to a container that might have more children  
        else{  
            if(d.children[i].name){//check to make sure the control has a name assigned so that it only records those with name.  
                switch(d.children[i].type){  
                    case 'radiobutton':  
                        x.presets.child(n).appendChild(XML('<' + d.children[i].name +' type="' + d.children[i].type + '">' + d.children[i].value + '</' + d.children[i].name + '>'));                          
                        break;  
                    case 'checkbox':  
                        x.presets.child(n).appendChild(XML('<' + d.children[i].name +' type="' + d.children[i].type + '">' + d.children[i].value + '</' + d.children[i].name + '>'));                          
                        break;  
                    case 'slider':  
                        x.presets.child(n).appendChild(XML('<' + d.children[i].name +' type="' + d.children[i].type + '">' + d.children[i].value + '</' + d.children[i].name + '>'));                          
                        break;  
                    case 'edittext':                      
                        x.presets.child(n).appendChild(XML('<' + d.children[i].name +' type="' + d.children[i].type + '"><![CDATA[' + d.children[i].text + ']]\></' + d.children[i].name + '>'));                          
                        break;                      
                    case 'dropdownlist':  
                        if(d.children[i].selection){varHold = d.children[i].selection.text}  
                        else{varHold = 'null'};  
                        x.presets.child(n).appendChild(XML('<' + d.children[i].name +' selecIndex="' + d.children[i].selection + '" type="' + d.children[i].type + '"><![CDATA[' + varHold + ']]\></' + d.children[i].name + '>'));                          
                        break;  
                  };//end switch  
                }//end if for child having name  
            };//end else  
        };//end for loop  
 }//end function setXML  
  
////////////////////////////////////////////////////////////////////////////////////////////////  
//function loops through the ui object and if a control item has been assigned a name uses that name to look up the preset value in the XML.  
function setUIvar(x,n,d){//x= xml file; n = node number (0 is default node), d = UI dialog  
  
    var currentXMLVal;//used to store values from XML file.  When this value is assigned, it checks to see if value from XML exist  
    var noMatch = false  
      
    for(var i = 0;i<d.children.length;i++){  
        noMatch = false;  
          
        if(d.children[i].type == 'panel' || d.children[i].type == 'group' || d.children[i].type == 'tab' || d.children[i].type == 'tabbedpanel'){setUIvar(x,n,d.children[i])};//reruns function if child is container and not control item.      
        else{  
            if(d.children[i].name){//Checks to see if child has a name assigned so only will reset those control items that have a name will be stored.  
                try{  
                    //Assigns all variables from presets node.  The "n" tells which preset to select.   
                    currentXMLVal = x.presets.preset[n].child(d.children[i].name);     
                    if(currentXMLVal == 'null'){currentXMLVal = null};  
                    }//end try  
                //catch assigns 'no_good' to current XMLVal so that if there is no value in the XML file, it will not try to assign a bad value to the UI controls.  
                catch(e){currentXMLVal = 'no_good'};//end catch  
                //switch makes sure proper type of value is reassigned back to UI controls.  
                if(x.presets.preset[n].child(d.children[i].name).length() > 0 || d.children[i].type == 'button'){  
                      
                    switch(d.children[i].type){  
                        case 'radiobutton':  
                            d.children[i].value = returnBoolean(currentXMLVal);  
                            break;  
                         case 'checkbox':  
                            d.children[i].value = returnBoolean(currentXMLVal);                          
                            break;  
                        case 'edittext':  
                            d.children[i].text = currentXMLVal;  
                            break;  
                        case 'slider':  
                            d.children[i].value = parseFloat(currentXMLVal);  
                            break;  
                        case 'dropdownlist':  
                            varHold = false;  
  
                          if(x.presets.preset[n].child(d.children[i].name).@selecIndex.toString() == 'null'){d.children[i].selection = null}  
                          else{d.children[i].selection = parseInt(x.presets.preset[n].child(d.children[i].name).@selecIndex)};  
  
                          break;  
                          };//end switch else  
  
                   };//end if to see if there is a good value from the XML  
                 
                };//end if for UI control having name  
            };//end else for if child is container or control  
        };//end for loop   
  
 };//end function setUIvar  
  
 //function returns a boolean value.  Values stored in XML are returned as strings, so they need to be converted back to boolean values.  
function returnBoolean(b){  
    if(b == 'true'){return true}  
    else{return false}  
    };  
  
//Function resets the values of the preset list when items are added or deleted.  
function setPresetList(){  
    presetList = new Array();  
    presetListDrop.removeAll();  
    for(var i=0;i<prefXML.presets.children().length();i++){presetListDrop.add('item',prefXML.presets.children()[i].@presetName)}  
};//end function setPresetList  
  
function readXMLFile(file) {  
    if (!file.exists) {  
        alert( "Cannot find file: " + deodeURI(file.absoluteURI));  
        }  
    else{  
        file.encoding = "UTF8";  
        file.lineFeed = "unix";  
        file.open("r", "TEXT", "????");  
        var str = file.read();  
        file.close();  
  
        return new XML(str);  
        };  
};  
  
function writeXMLFile(file, xml) {  
    file.encoding = "UTF8";  
    file.open("w", "TEXT", "????");  
    //unicode signature, this is UTF16 but will convert to UTF8 "EF BB BF"  
    file.write("\uFEFF");  
    file.lineFeed = "unix";  
    if (!(xml instanceof XML)) {  
        for(var g=0;g<scriptArray.length;g++){  
            try{  
                file.writeln (scriptArray[g].toString())  
                }  
            catch(e){}  
         };//end for loop              
        }  
    else{file.write(xml.toXMLString())};  
    file.close();  
    };

 

 

Inspiring
February 27, 2022

Hi Chusck, thanks for provising the simplifed script version. It is useful to see the UI, script together and xml file interacting. Somehow, the script is not generating the xmlTest file on the desktop.

I made a screen recording to show what happesn when the script runs.

Let me know if you have any ideas why the xml file is nt genrating on the desktop.

https://imageasel.com/wp-content/uploads/Screen-Recording-2022-02-26-at-5.23.10-PM.mp4

 

OSX Catalina

 

 

 

 

Chuck Uebele
Community Expert
Community Expert
February 27, 2022

I guess I should have tried the script first. There were some issues, which should be fixed now. I replaced my previous script with the corrected one. Try that, now.

Chuck Uebele
Community Expert
Community Expert
February 9, 2022

Not sure if this applies for what you want to do, but I use a recursive function to save all variables in a scripts UI to an XML file. The nice thing about the function that I created is that you can change the UI and you don't need to modify the save function. You can see an example of it in this thread on changing the arrowheads.

 

https://community.adobe.com/t5/photoshop-ecosystem-discussions/changing-arrow-parameter-on-line-tool/m-p/11533367

Inspiring
February 9, 2022

Absolutly, that applies! in the past, I have not used a preference file with a custom script. So I like to start with a super simple test and then move to more complex preference file concepts sucha as including an UI and saving settings to an xml file. Many thanks for providing the refrence link!

Kukurykus
Legend
February 9, 2022

What about reading preferences from the other .jsx file, as you wanted. Does it work?

Inspiring
February 8, 2022

How does a script call a preference/settings file?

Kukurykus
Legend
February 8, 2022

First of all I don't know what you mean by parent.jsx & parent-settings.jsx.

Inspiring
February 8, 2022

Let’s say the parent.jsx script changes the text font family in the open document.

To assign a new font family change the font family variable in the paren-settings file.

 

Does this make sense?

Kukurykus
Legend
February 8, 2022

Probably only you understand what you are talking about.