Helper: ConfigHelper (easier config item handling)

ConfigHelper:
A tiny class which helps creating script config items, their default values and descriptions.

  • it helps to prevent errors (because you don't have to make sure item-name and description-map entry match)
  • it saves time (because you need to type less code and changes are done more quickly)
  • it looks nicer (I think it's capable of hiding some irritative syntax and commands)

Usage:

  • Put the code-snippet below somewhere in your script. I suggest putting it directly *intourlTmpthe OnInit() function, as that's the only place it's going to be used (it's a just local function/class/object then).
	function ConfigHelper(data){ //v1.2
		var t=this; t.d=data; t.c=data.config; t.cd=DOpus.Create.Map();
		t.add=function(name, val, des){ t.l={n:name,ln:name.
			toLowerCase()}; return t.val(val).des(des);}
		t.des=function(des){ if (!des) return t; if (t.cd.empty)
			t.d.config_desc=t.cd; t.cd(t.l.n)=des; return t;}
		t.val=function(val){ var l=t.l; if (l.v!==l.x&&typeof l.v=="object")
			l.v.push_back(val);else l.v=t.c[l.n]=val;return t;}
		t.trn=function(){return t.des(t("script.config."+t.l.ln));}
	}
  • After that, create an instance of the ConfigHelper while passing OnScriptInitData:
	var cfg = new ConfigHelper( OnScriptInitData );

Methods:

  • add() - adds a config item (value and description can be specified as well if desired)
  • val() - sets the default value, if it's a new empty vector, following calls to val() add items to it
  • des() - sets the description
  • trn() - fetches and sets a language specific description (you need the translator to use this one)

  • The methods val(), des() and trn() always operate on the last item added by add(), so don't mix them up. o)

    Demo-Config:


Cya, tbone

Download:

2 Likes

Updated to v1.2:

  • maximum level of compactness reached, 5 lines less! o)
  • removed support for early DO v11 releases
  • replaced deprecated methods and outdated approaches with current standards
  • error fix (occured if OnInitData was not called just "data")
  • added trn() method for fetching translations (translator class needed)

@aussieboykie
Thanks for noticing the usage of deprecated methods!
I used this oportunity to reshape and enhance it a bit, I hope it fits even better. o)

tbone, thanks very much for this machinery, which I've found pretty straightforward to adapt. There's one detail I can't work out, however.

QUESTION: The items in the "Edit Configuration' panel come out in alphabetical order, rather than in the order in which they appear in the script. I eventually discovered that oDlg.sort = false turns off alphabetical sorting in a dialogue, but I can't work out any analogous command to turn off alphabetical sorting in the "Edit Configuration' panel.

Thanks. o) You can't change the order in which the config items appear. There's no way to influence this from the scripting side, despite adding items with a numbered prefix. I did this for the OverrideFormats addin e.g. It might end up looking quite ok, but it needs lot's of manual tweaking.

Thanks for this clarification, tbone. So there's no Cfg.sort = false as there is with dialogues, and it's back to numbered lines, which are only a pain if you forget things, which I keep doing. Actually, you can leave gaps in the numbering.

Interesting, I've just hit the wretched MyString.split (",") problem, whose details StackOverflow explained to me after I had become totally confused about what a script was doing. You'd think that coding would be like Pure Mathematics, but in fact it's much more like Chemistry, with endless exceptions and special cases and forbidden moves every time you turn around.

Now I do have a problem. The previous time I used this code, I only had functions to deal with. But this time I have columns as well, and I want the configuration to give the names of the columns as well as populating the columns. Before I began using any of this machinery, I had naively configured the addin by putting lines of data right at the start of the addin, up above function OnInit (initData), so that it was available to every function. But if I use this configuration machinery instead:

  • Where do I put what bits of code so that the configuration can give the names of the columns? (This may not be possible.)

  • Where do I put what bits of code so that the new columns are populated, but without the script having to read in that code again for every item in the lister? (Again, this may not be possible.)

Maybe in this situation the best solution is to leave the data where it is at the top of the script, and let the user edit the configuration by raw editing of these data lines, as is done with button scripts.

Could you give an example how to use trn()? I suppose it needs a language code.

Oh my goodness! This saves me soooo much time!!! Thank you!!

What drives me nuts as someone who is new to scripting for DOpus (as well as in general, a basic programmer) is the lack of explanations in the manual how to do things and examples. Lots of examples. Also it needs consistency. It's like the whole manual just throw stuff at your face and hoped that you just makes sense of it. Anyway, with this, I don't need to suffer trying to add config options and it looks much cleaner too. Once again, thanks!

Perhaps you've overlooked the Example Scripts section of the manual.

Actually I have seen it. What I meant is I wanted to add config options for the script add-in that I'm learning to write right now. I want to know how to add them yet they're no examples that uses it in there so I have to look around in the forums to find them. Since I'm writing it in JScript, I also have to make sure the examples I find are the same as well.

There are also some consistency issues. In some of the examples, what type of script they are are mentioned in the descriptions while others are not and only are indicated in the top of the example scripts and finally some are not indicated at all anywhere so you have to look at the script itself closer to see the language structures to know that it's either vbs or JScript.

Hi,
thanks @tbone for this great piece of code. But i could need some help: I dont get how a mulit option dropdown menu really works.

cfg.add("Mapstyle", DOpus.Create.Vector(), "Mapstyle. A = Aerial, R = Roads, 3D = Satellite + 3D.0" ).val(0).val("3D").val("A").val("R");

I want to use the values supplied by val() in the code later. When i dont do .val(0), the option in the settings is a textbox with the three values, each in a seperate row. When i use .val(0), it is a dropdown (which i want it to be) but the chosen value i can access via Script.config["Mapstyle"], the returned value is 0, which is nonse for me since i want it to be one of the string values.
Can somebody help me? Thanks.

This is out of scope of this helper I think, it helps creating the config items, it can't do a thing about what DO returns for its script config items. But you can help yourself with another little helper.. o) I called it IndexedTexts(). To make this more fool proof, we create "constants" for the actual text values, since repeating human readable text in code is not optimal.

//global scope
var MAPSTYLES = new IndexedTexts();
var MAPSTYLE_AERIAL = "Aerial";
var MAPSTYLE_ROAD = "Road";
var MAPSTYLE_3D = "3D";

function IndexedTexts() {
	t = this; t.byText = {}; t.byIndex = [];
	t.add = function(text) { t.byText[text] = t.byIndex.length; return t.byIndex.push(text)-1;	}
	t.indexOf = function(text) { return t.byText[text]; }
	t.textOf = function(index) { return t.byIndex[index]; }
}
//OnInit() scope
cfg.add("MapStyle", DOpus.Create.Vector(), "Desired map style..").
        val(0).val(MAPSTYLES.add(MAPSTYLE_AERIAL)).val(MAPSTYLES.add(MAPSTYLE_ROAD)).val(MAPSTYLES.add(MAPSTYLE_3D));
//anywhere scope
if (Script.config["MapStyle"] == MAPSTYLES.indexOf(MAPSTYLE_AERIAL)) {
	//do things..
}
var chosenMapStyleIndex = Script.config["MapStyle"]
var chosenMapStyleText = MAPSTYLES.textOf(chosenMapStyleIndex); // "Aerial" == MAPSTYLE_AERIAL
//demo for easy testing in DO CLI e.g.:
function IndexedTexts() {
	t = this; t.byText = {}; t.byIndex = [];
	t.add = function(text) { t.byText[text] = t.byIndex.length; return t.byIndex.push(text)-1;	}
	t.indexOf = function(text) { return t.byText[text]; }
	t.textOf = function(index) { return t.byIndex[index]; }
}

var MAPSTYLES = new IndexedTexts();
DOpus.Output("Index 1st add:" + MAPSTYLES.add("Aerial") );
DOpus.Output("Index 2nd add:" + MAPSTYLES.add("Road") );
DOpus.Output("Index 3rd add:" + MAPSTYLES.add("3D") );
DOpus.Output("");
DOpus.Output("Get index of 'Aerial' :" + MAPSTYLES.indexOf("Aerial"));
DOpus.Output("Get index of '3D'     :" + MAPSTYLES.indexOf("3D"));
DOpus.Output("Get text of index 0   :" + MAPSTYLES.textOf(0));
DOpus.Output("Get text of index 2   :" + MAPSTYLES.textOf(2));
DOpus.Output("");
DOpus.Output("All texts: " + MAPSTYLES.byIndex);
//output of demo
Index 1st add:0
Index 2nd add:1
Index 3rd add:2

Get index of 'Aerial' :0
Get index of '3D'     :2
Get text of index 0   :Aerial
Get text of index 2   :3D

All texts: Aerial,Road,3D

Ah thanks for this eye opener and a new solution. Somehow I didnt think about the returned value as an index :man_facepalming: I changed my approach of using config helper for my script to using parameters for the command but I think there still might be someone using this new approach :slight_smile:

FYI I've added config_groups support to the builder

inc_cfg.js.txt (1.6 KB)

Oha, I did not realize there were config groups now as well, it seems I fail to keep up with the DO evolution! o)
I will update the initial post with your enhancement at some point! Thank you! o)