Support for generic placeholders and table build.

In placeholder and table build actions, you can define function variables and their value ranges. The values themselves are not determined until the placeholder (or table) is used in an InDesign® document: When selecting them in the document, function variables and their value ranges are displayed in the Placeholder Options panel, and the Table Build panel, respectively.

A table manages title, colors and prices of products. To use these values in a placeholder, you used to have to perform three almost identical actions, that only differed in the name of the product attribute (title, color, price). Using function variables, you can now define just one action and signify to the outside world that it uses function variables (and which values are valid). The value that is actually used can then be specified in the InDesign® document, when using a placeholder with that action there.

The screenshot shows gKeyName waiting for input: title, color or price?

The definitions of function variables are only used by the panels Placeholder Options and Table Build, where the variables and their accepted values are displayed. Variable values are stored directly on the placeholder (or the table), within the document. When executing the actions (load, table build, ...), the configured values are used. The function variable definitions are then no longer needed and no longer affect action execution.

Older comet versions that do not support this feature cannot execute actions with function variabels and will not recognize their definitions as valid syntax.

Warning: function variables work counter to the concept of individually updated placeholders. This problem is easy to solve: continue using multiple distinct placeholders, but make them all use the same load action.

The possible values can be selected in the dropdowns in the Value column. The selection 'Custom' requires an input in the column Custom Value. To do that, Triple Click the column.

If a variable has more than 30 values to choose from (we have heard of up to 2,000 (sic!) values), you should talk to your IT about user experiance. Regardless of your IT, a dialog instead of the dropdown will automatically appear when clicked:

This list can be easily narrowed down to a manageable length using the Value search field. Additionally you can reorder the list with DragAndDrop and with ALT+arrow keys. Maybe this creates a better overview. With a click on the word Value you can restore the original sorting.

Double clicking a list entry will take this value. By clicking 'Okay' the first selected (or first) entry of the list is used as value.

Currently, function variables can be used in the following places:

The syntax for defining function variables is the same for cScript and direct statements (xmlquery, SQL):

#pragma var "name" "defaultValue" {"alternative_value"}

"#pragma var" is the mandatory leading directive. The second string contains the default value and is required too. This may be followed by any number of alternative values.

Each variable definition has to be placed on its own line at the beginning of a script.
Line breaks are not allowed in a definition!
Reserved symbols such as gFrame, gDocument or documentID must not be redefined.

The "name" can be chosen freely, as long as it matches the following syntactical rules:

Reserved symbols cannot be used as names.

The name is followed by a list of accepted values, each in quotes, and separated by spaces. The first value in the list is the default value. This value is used when the placeholder or table cell does not specify a value for the variable. Quotes inside the value have to be escaped using a leading backslash \.

Example: Variable name: "gLanguage", accepted values:"de", "en", "fr".
#pragma var "gLanguage" "de" "en" "fr"
Example: Variable name: "gGreeting", accepted values: "Hello", "Hey there" und "Welcome".
#pragma var "gGreeting" "Hello" "Hey there" "Welcome"
Example: Variable name: "gSize", accepted values: "5 cm", "5"" (5 inches).
#pragma var "gSize" "5 cm" "5\""

You can also specify an action ID to fill the list of accepted values with. The syntax for this is as follows:

#pragma var "variableName" "##actionID"

Here, "variableName" is to be replaced with the name of the variable, and "actionID" with the numerical ID of the desired action. The actions need to be defined with ClassID 55 for placeholders and 56 for table cells, respectively and must be written in cScript.

The action is executed each time the placeholder is displayed in the panel Placeholder Options. When loading, synchronising and writing back the placeholder, the action is no longer necessary. The prerequisite is that a value has been assigned to the variable in the placeholder - in other words, the Synchronised state () is shown in the panel. Non-synchronised function variables will execute the action every time the placeholder is loaded! Non-synchronised function variables with value actions are only useful if the first value that the action calculates can change again and again.

The following global variables are available in the actions:

Name Data type Description
Function variables in placeholders (panel Placeholder Options)
gAvailableValues StringList The list to be filled with values
gPlaceholderID int ID of the placeholder
gCallingActionID int ID of the action that called this action
gVariableName char[] Name of the function variable used in the script
gVariableDisplayName char[] Display name of the function variable
Function variables on table cells for the table module (panel Table Composition)
gAvailableValues StringList The list to be filled with values
gCallingActionID int ID of the action that called this action
gVariableName char[] Name of the function variable used in the script
gVariableDisplayName char[] Display name of the function variable
gTable Table The active table
gRow int The row number within the table
gColumn int The column number within the table

Example 1:

#pragma var "gLanguage" "##333"

In action 333:

int main()
{
	stringlist::insert(gAvailableValues, "de", -1);
	stringlist::insert(gAvailableValues, "en", -1);
	stringlist::insert(gAvailableValues, "fr", -1);

	return 0;
}

You can combine loading the values with an action with constant values. The values generated by the action are automatically inserted in the corresponding place in the list.

Example 2:

#pragma var "gLanguage" "de" "en" "##333"

If you would like a value to start with two pound signs, use a backslash to escape this syntax.

Example 3:

#pragma var "gLanguage" "de" "en" "\##frFR"

You can nest list filling actions, such that one action calls another one. If an action provides a value starting with two pound signs, this is interpreted as a call to another dynamic definition.

Example 1:

In a placeholder load action:

#pragma var "gLanguage" "##111"

int main()
{ // Do nothing. We only care about the available values of the function variable return 0; }

In action 111:

int main()
{
	stringlist::insert(gAvailableValues, "de", -1);
	stringlist::insert(gAvailableValues, "en", -1);
	stringlist::insert(gAvailableValues, "##222", -1);
	stringlist::insert(gAvailableValues, "fr", -1);
		
	return 0;
}

In action 222:

int main()
{
	stringlist::insert(gAvailableValues, "jp", -1);
	stringlist::insert(gAvailableValues, "dk", -1);
		
	return 0;
}

Make sure you are not creating an infinite loop. This would quickly cause InDesign® to crash.

Function variables do not necessarily have to be defined in your scripts or statements as described above. You can also provide an Action ID, corresponding to a cScript which then defines the function variables and their values. The statement associated with this action has to be written in cScript, and use ClassID 57 for placeholders, or 58 for table cells!

Use scripts for calculating variables and values sparingly! Since not only the values but also the variables themselves can change with each call, these scripts (in contrast to scripts that only calculate lists of values) must also be executed each time a placeholder is loaded, checked (To Do list) and written back. This can lead to considerable performance losses!

The syntax for this definitions is as follows:

#pragma var "##123"

Where 123 should be replaced with the Action ID you would like to use for the dynamic definition. All strings placed after it are ignored!

The following global variables are available in these actions:

Name Data type Description
Function variables in placeholders (panel Placeholder Options)
gFuncVars IDTypeList The list of function variables to be filled
gPlaceholderID int ID of the placeholder
gCallingActionID int ID of the action that called this action
Function variables on table cells for the table module (panel Table Composition)
gCallingActionID int ID of the action that called this action
gTable Table The active table
gRow int The row number within the table
gColumn int The column number within the table

The action has to fill a list of type idtypelist with the name gFuncVars with the names of the function variables and their respective accepted values, like shown in the following code snippet:

(1, 0, 0, "Variablen1Name")   // Definition of first variable with ID 1, 0, 0
(1, 1, 0, "Variable1Value1")  // Value 1 with ID 1, 1, 0
(1, 2, 0, "Variable1Value2")  // Value 2 with ID 1, 2, 0
(1, 3, 0, "Variable1Value2")  // Value 2 with ID 1, 2, 0

(2, 0, 0, "Variablen2Name")
(2, 1, 0, "Variable2Value2")

:
:

The first value of the ID is unique per variable, the second is either 0 for the variable name, or the index of the accepted value. The order of names and values does not matter - though values without a matching variable name are ignored.

Example 1:

In a placeholder load action:

#pragma var "##333"

int main()
{
	// Do nothing. We only care about the available values of the function variable
	return 0;
}

In action 333:

int main()
{
	// Defining the variable "gFruits"
	idtypelist::insert(gFuncVars, -1, 1, 0, 0, "gFruits");
	idtypelist::insert(gFuncVars, -1, 1, 1, 0, "apples");
	idtypelist::insert(gFuncVars, -1, 1, 2, 0, "pears");
	idtypelist::insert(gFuncVars, -1, 1, 3, 0, "bananas");
	
	return 0;
}

Like actions generating lists of available values, dynamic definitions can be nested. If an action inserts a variable with the double pund sign syntax, this is interpreted as a call to another dynamic definition. Function variables are inserted into the drop down menu according to the order of the definitios.

Example 1:

In a placeholder load action:

#pragma var "##333"

int main()
{
	// Do nothing. We only care about the available values of the function variable

	return 0;
}

In action 333:

int main()
{
	// Defining the variable "gFruits"
	idtypelist::insert(gFuncVars, -1, 1, 0, 0, "gFruits");
	idtypelist::insert(gFuncVars, -1, 1, 1, 0, "apples");
	idtypelist::insert(gFuncVars, -1, 1, 2, 0, "pears");
	idtypelist::insert(gFuncVars, -1, 1, 3, 0, "bananas");
		
	// Calling an additional dynamic definition with ID 444
	idtypelist::insert(gFuncVars, -1, 2, 0, 0, "##444"); 

	return 0;
}

In action 444:

int main()
{ 
	// Defining the variable "gTea"
	idtypelist::insert(gFuncVars, -1, 1, 0, 0, "gTea")
	idtypelist::insert(gFuncVars, -1, 1, 1, 0, "mint")
	idtypelist::insert(gFuncVars, -1, 1, 2, 0, "ginger")

	return 0;
}

The IDs of entries to gFuncVars only have to be unique within the script.

Again, make sure not to create infinte loops. This quickly causes InDesign® to crash.

You may want to have the values shown in the drop down menu (see Configuration - 'Variable Values') differ from the values used in the actual cScript code or statement, for example when you need numerical values with clear semantic meaning, such as Yes and No corresponding to 1 and 0, respectively. Name and value are separated by a double slash (//). The name is localized using the cScript function translate before making its way to the display.

Generell syntax for named values of function variables. The name parts (here name1, name2, ...) of the values are translated automatically into the current InDesign® language.

#pragma var "variableName" "value1//name1" "value2/name2" ...

Example:

The variable variableName may take on the values 0 and 1, which will be displayed as Yes and No (or Ja/Nein, oui/non). The localization info for this particular text is delivered with the plugins.

#pragma var "variableName" "1//yes" "0//no"

If you want one of the values to contain a double slash, you can escape this syntax with a backslash.

Example:

#pragma var "gTableware" "Plates\//Cups"

This is best shown using an example.

Let us start with a very straightforward load script:

#pragma var "variableName" "##456"

int main ()
{
	wlog ("", "(%s)\n",variableName);
	
	return 0;
}

After placing a placeholder with this script into the document, action 456 will run when you click it, and the Placeholder Options will be populated with a list of values. A value selected here is stored in the document.

You will note that the script does not declare the variable variableName. It cannot, since the variable is defined by the load process, which inserts the following line before executing the scripts:

char variableName [] = "Your choice";

Now the placeholder can go ahead, and, in this case, fill the log.

Warning ALL function variables are of type char[]. If you need values of type int or float, you will have to convert them using val or fval. Also note that the string values must not be modified!

Example 1

#include "internal/types.h"

#pragma var "gLanguage//Language" "de//German" "en//English" "fr//French"
#pragma var "gAttributeTable//Table" "comet_attribute"

int main()
{
	DBC 		dbc 	= sql::dbconnection();
	Query 		qu 		= sql::query(dbc);
	int 		id;

	query::send(qu, "select id from ");
	query::send(qu, gAttributeTable);
	query::send(qu, " where keyname = ? and infoobject_id = ? and lang = ? and active = 1 order by sort ");

	query::input(qu, kString, "Edition");
	query::input(qu, kString, gRootTableRecordStringID);
	query::input(qu, kString, gLanguage);

	query::output(qu, kInt, &id);

	query::exec(qu);
	while (query::fetch(qu))
	{
		idtypelist::append(gProducts, 1, 0, 0, itoa(id));
	}
	query::close(qu);

	return 0;
}

Additionally, two global variables of type StringList are provided in cScript: gFuncVarNames and gFuncVarValues, which can hold the variable names and their values. The variable names are always the actual names, not the display names.

Example 2:

#include "internal/types.h"
	
#pragma var "gColor//Color" "red//Red" "green//Green" "blue//Blue"
#pragma var "gSize//Size" "small//Small" "medium//Medium" "large//Large"
				
int main()
{
	int 	i 				= 0;
	int 	funcvarCount 	= StringList::length(gFuncVarNames);
	
	wlog("", "Funcvar count: %d\n", funcvarCount);
	
	for (i = 0; i < funcvarCount; i++)
	{
		wlog("", 
			"Funcvar : name: %s, value: %s\n",
			StringList::get(gFuncVarNames, i),
			StringList::get(gFuncVarValues, i)):
	}

	return 0; 
}

Example 2 logfile output with default values:
Funcvar count: 2
Funcvar name: gColor ; Funcvar value: red
Funcvar name: gSize ; Funcvar value: small

The lists gFuncVarNames and gFuncVarValues mentioned above are not available in direct statements.

In an (SQL/xmlquery) statement, variables must be surrounded with angled brackets. They are automatically surrounded with quotation marks. If this is undesirable, use the following syntax:

<*Unquoted_variableName>

Example 1:

#pragma var "gLanguage" "de" "en" "fr"

select value_string 
from comet_attribute 
where 	keyname = 'Titel' 
		and infoobject_id = <StringID> 
		and lang = <gLanguage>
		and active = 1

Example 2:

#pragma var "gLanguage" "de" "en" "fr"
select value_string 
from comet_attribute 
where 	keyname = 'Titel' 
		and infoobject_id = <StringID> 
		and lang = '<*Unquoted_gLanguage>'
		and active = 1 

Function variables are used in TaggedText inside the tag as triples. The definition is introduced with the functionvariables keyword, and the triples follow in single quotes. Each triple consists of variable name, value and action type, each enclosed in double quotes.

Example:

<w2: 
	30,
	0, 0, 0, '',
	definition 3 1 30 0 -1 0 0 6 0 0,
	infos1 '', infos2 '',
	prefix '', prefixifempty '', postfix '', postfixifempty '',
	created '20170622154717', modified '20170622115641',
	rules '',
	functionvariables 
		'"decimalPlaceCharacter" ";" "1" 
		"formatString" "%s" "1"'
>
AAA
<w2:>

In this example, the tagged text of a text frame was exported. The text "AAA" has a placeholder that defines two function variables:

  1. Variable name: decimalPlaceCharacter, Value: ; (Semicolon), Action Type: 1 (Load action)
  2. Variable name: formatString, Value: %s, Action Type: 1 (Load action)

From table cells, function variables are used in tagged text as part of the <w2Cell> tag. The syntax is very similar to that of text placeholders, but here you are introduced by the CellFunctionVariables keyword. The rest of the syntax is the same as for text placeholders. The values for the action membership are as follows:

Example:

<CellStart:1,1
	<w2Cell: 
		ColActionID=2000
		ColMany=0
		ColGroup=''
		ColGroupPrefix1=''
		ColGroupPrefixN=''
		ColID1=0 ColID2=0 ColID3=0 ColIDString=''
		RowActionID=0
		RowMany=0
		RowGroup=''
		RowGroupPrefix1=''
		RowGroupPrefixN=''
		RowID1=0 RowID2=0 RowID3=0 RowIDString=''
		Groups=''
		ContentType=0
		ContentTypeEntry=0
		ContentMap1=0
		ContentMap2=0
		ContentMap3=0
		ContentMap4=0
		Preprocess='' Postprocess=''
		IdentMappings=''
		ContentID1=0 ContentID2=0 ContentID3=0 ContentIDString=''
		ColFirstLast=0 RowFirstLast=0
		ColOmitActionID=0 RowOmitActionID=0
		RepeatContent=0 ColBlockSize=1 RowBlockSize=1
		CellID1=30600005 CellID2=577563520 CellID3=0 CellIDString=''
		ColParentID1=0 ColParentID2=0 ColParentID3=0 ColParentIDString=''
		RowParentID1=0 RowParentID2=0 RowParentID3=0 RowParentIDString=''
		ReservedString2='' ReservedString3=''
		CellFunctionVariables='
			"gUser" "Leo" "3"
			"gTable" "comet_config" "3"'
		ReservedID21=0 ReservedID22=0 ReservedID23=0 ReservedID2String=''
		ReservedID31=0 ReservedID32=0 ReservedID33=0 ReservedID3String=''
		ReservedID41=0 ReservedID42=0 ReservedID43=0 ReservedID4String=''
		ReservedLong4=0 ReservedLong5=0 ReservedLong6=0
	>
>

In this example, two function variables are defined for the cell:

  1. Variable name: gUser, Value: Leo, Action type: 3 (Copy Column, Insert action)
  2. Variable name: gTable, Value: comet_config, Action type: 3 (Copy Column, Insert action)

The configuration of function variables takes place in the corresponding panels (see Availibility). The panels contain lists showing the currently defined variables:

Icon Description

Synchronized:

The cell or placeholder has a value specified for this variable.

Only defined by actions:

The cell or placeholder does not have a value specified for this variable. The default value for that variable is used instead (or the empty string, if none is defined). Upon the next change, the selected value is stored on the cell or placeholder.

Not defined by actions:

This variable is defined for the cell or placeholder, but not by the action. It will not have any effects, and will be discarded with the next change.

The display depends on the currently selected placeholder or table cell, as well as the configured actions.