The 210 documentation is not yet available on the user site (we are in the grindingly-slow process of converting that site to drupal).
The 208 documentation is generally accurate, though there have been changes in the XLSX content, most notably the changes to the display… columns on the survey, choices and settings sheets. These are now display.prompt.text, display.hint.text, display.title.text, and display.prompt.image, etc. These changes were made to enable better support for translations. The exampleForm shows a trivial use of translations. Translations for the strings displayed in the built-in widgets are provided via the framework form.
At the internals and web-programmer level, the up-to-date documentation is here: Tool Suite Javascript framework and formDef.json (Survey) format · getodk/getodk Wiki · GitHub
In answer to your question, there is no join function. However, the full power of javascript and the jquery.js ($.xxx) and underscore.js (_.xxx) libraries are available to you. The calculate column is wrapped and evaluated as a javascript function:
function() {
return (YOUR_CALCULATE_COLUMN_CONTENT_HERE);
}
You can write your own code to perform a join via defining and invoking an anonymous function in your calculate. Here is an example:
(function() {
var result = "";
_.each(data('valueListField'), function(element) {
result = result + ", " + element;
});
return result.substring(2);
}) ()
This defines a function and then invokes it. The available accessor functions within a calculates expression are the following:
data(fieldName) -- retrieve the value stored under this fieldName
Usage: data('myField')
metadata(instanceMetadataFieldName) -- retrieve value stored under this name
Usage: metadata('_group_modify')
selected(promptValue, qValue) -- test whether qValue occurs within a select-multiple
Usage: selected(data('mySelectMultipleField'),'myChoiceDataValue')
countSelected(promptValue) -- count the number of selections in a select-multiple
Usage: countSelected(data('mySelectMultipleField'))
equivalent(promptValue1, promptValue2, ...) -- test if values are equivalent
Usage: equivalent(data('promptA'), data('promptB'))
not(conditional) -- negate a condition ( equivalent to !(conditional) )
Usage: not(data('fieldA') === data('fieldB'))
now() -- return the current time
isFinalized() -- return whether or not the current row is finalized
assign(fieldName, value) -- store value in fieldName and return value.
Usage: (8 + assign('myField', 5))*10
These formulas are also available, but are generally not useful in calculates. They are used within template helper functions (…/system/survey/js/handlebarsHelpers.js).
getCurrentLocale() -- return the currently-active locale
localize(locale, displayProperty) -- localize the given display.xxx text
Usage: localize(getCurrentLocale(), display.hint)
width(string) -- determine the rendered width of a string
expandFormDirRelativeUrlPath(content) -- return url for a file within the form directory.
Additionally, you can also reference the opendatakit object within these functions (system/survey/js/opendatakit.js).