Script prefernce file

Engaged ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

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

TOPICS
Actions and scripting

Views

537

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 3 Correct answers

LEGEND , Feb 08, 2022 Feb 08, 2022
Put your variables to 'parent-settings.jsx' and at beginning of 'parent.jsx' use evalFile() method with path to 'parent-settings.jsx' to collect its content for later use by 'parent.jsx'.

Likes

Translate

Translate
Adobe Community Professional , Feb 27, 2022 Feb 27, 2022
Ok, I revamped my script. It now allows for you to create a default preference, as well as saved preferences. You can save various preferences, using the Create New Preset Button. If you want to actually use that preset and set it as the default, you first select it in the dropdownlist then hit the Save as Default button. To actually get the values to another script, copy the code for the UI to that script. You can omit all the onClick and onChange functions within the block to make the UI. In...

Likes

Translate

Translate
Adobe Community Professional , Mar 01, 2022 Mar 01, 2022
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...

Likes

Translate

Translate
LEGEND ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

Probably only you understand what you are talking about.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

How does a script call a preference/settings file?

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

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

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

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?

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

Put your variables to 'parent-settings.jsx' and at beginning of 'parent.jsx' use evalFile() method with path to 'parent-settings.jsx' to collect its content for later use by 'parent.jsx'.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

Thank you. I will give the evalFile() method a try.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

Was my tip working that (I guess) you marked your reply as correct solution?

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

Absolutely! Thank you! I'll start by testing the evalFile () method, then add a UI. Next, add the UI and xml.

Before I asked the question, I did not know how to make sense of the preference file.

Now I have a good idea of what needs to happen.

Manay thanks to you all!

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 26, 2022 Feb 26, 2022

Copy link to clipboard

Copied

The eval method does work for getting a varaible from a separete script. Howwever when I add a simpe UI to the script the eval methis calls the UI and varaible instead of getting the varaible from the UI.

The other apporach is to write the UI input into a separete xml file and have the script read the values from the xml file.  I am not familair with this alst apporach so I need to investigate it.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Feb 26, 2022 Feb 26, 2022

Copy link to clipboard

Copied

I have only used a pref. file in a couple of scripts. As a newb, I found working with a plain text file easier than trying to write and read XML or JSON.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

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...

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

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!

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

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

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 08, 2022 Feb 08, 2022

Copy link to clipboard

Copied

I have not try it yey, but I think it should work.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Feb 26, 2022 Feb 26, 2022

Copy link to clipboard

Copied

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();  
    };

 

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 26, 2022 Feb 26, 2022

Copy link to clipboard

Copied

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

 

 

 

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Feb 26, 2022 Feb 26, 2022

Copy link to clipboard

Copied

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.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 27, 2022 Feb 27, 2022

Copy link to clipboard

Copied

Thanks for making the changes. Can we walk through your example to understand how the preference file interacts with another script?

 

The script generated the following xml code on the desktop

 

<root>
  <presets>
    <preset presetName="Workstation">
      <myCheckBox type="checkbox">false</myCheckBox>
      <myRadio1 type="radiobutton">false</myRadio1>
      <myRadio2 type="radiobutton">true</myRadio2>
      <myEditT type="edittext"><![CDATA[OSX]]></myEditT>
      <mySlider type="slider">25</mySlider>
      <myDropList selecIndex="null" type="dropdownlist"><![CDATA[null]]></myDropList>
    </preset>
  </presets>
</root>

 

How do I read the myRadio1 xml node from another script?

 

var f = new File('~/Desktop/XYZ/xmlTest.xml');
f.open('r');
var xml = new XML( f.read() );
f.close();

//root node

//child node
//myRadio1 node

 

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Feb 27, 2022 Feb 27, 2022

Copy link to clipboard

Copied

My s ript is really designed to be inserted into any script. The UI portion in the script, is just an example. It is replaced with whatever UI design, and it will record those values. Why do you want it read by a second script? It would be possible, but then, I think that you would have to set up an object with named nodes that match the original UI.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 27, 2022 Feb 27, 2022

Copy link to clipboard

Copied

Let me try to clarify how I see the preference file working with an additional script.

The preference file UI allows the user to change the behavior of script1.

Script1 can run function A or function B and by default, runs function A. 

To run function B set the preference file UI button to function B. 

The preference file remembers the last setting. 

Script1 reads the preference file to check which function to run and does not display the preference UI when checking.

To change the function in script1 open the separate preference file and choose function A or B

 

Do you think this approach makes sense?

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Feb 27, 2022 Feb 27, 2022

Copy link to clipboard

Copied

That makes sense. So would you want to set up two different preferences with multiple variables, or just a select A or B option? And yes, that can be done, as I did that with a script that I used to use at work.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 27, 2022 Feb 27, 2022

Copy link to clipboard

Copied

I apologize for my lack of understanding. What is the difference between two differnt preferences with multiple variables and the A or B option?

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Feb 27, 2022 Feb 27, 2022

Copy link to clipboard

Copied

Ok, here are some options on how you can handle this:

 

A or B option: the ui comes up and you can select A or B (or whatever you want to call it) The code for thes two options are hard coded into you production script. The UI just stores which option you want - no other variables are stored. You really don't need an XML for this - just a CSV file will work.

 

Last saved default:

With this option, someone opens the UI makes changes to a variety of different controls (checkboxes, sliders, etc) and the values are stored in the XML. Then you run your production script. It reads the XML file and uses the last saved default values from the XML.

 

Saved preferences:

With this, you open the UI, make changes to the controls and then save those controls as difference preferences that you can then have your production script call. So say you have one preference file called routine A, which loads a set of values that you use often. Then you might have routine B that stores another set of values that you use at a different time. You can then either hard code your production script to only select one of the routines, or you can open the ui select one of the saved preferences and then store those as the default to be used by your production script.

 

Currently, the script that I posted, just stores preferences, and when you select a saved preference, it will change the values in the UI, in that script. To open those values from another script would require some modification.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Feb 27, 2022 Feb 27, 2022

Copy link to clipboard

Copied

Thanks for explaining the options. I think the Saved preferences option sounds the best but is probably the most complex approach. The Last saved default option sounds good and is probably easier. To be honest, I’m not sure how to code the last saved default option. A sample code would be very useful.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines