Cascading configuration, Verne style sheets, Cascading Verne configuration style sheets, Verne CSS… however you wish to say it (generally pronounced "cess"), configuration style sheets are a way of pushing configuration down into descendant locations within the service form, which come in to play when supporting the last option mentioned in the reuse vs. complexity paradigm.
- XML structure
- stylesheets Element
- stylesheet Element
- selector Element
- Modifier child elements
- Behaviour limitations
- CSS selectors:
- Service Form Item (SFI) attributes and classes
- SFI XML examples
- SFI CSS Selector examples
- Cascading configuration examples
XML structure
Cascading configuration rules are defined using the following XML structure:
<stylesheet name="myStyleSheet">
<selector selector="someSelector">
<selector selector="some-other-selector">
<visible value="false"/>
...
</selector>
...
</selector>
...
</stylesheet>
They can also be stand alone configuration outside of any specific form, form fragment etc. so be considered against any service form. In this case the style sheet is simply wrapped in a stylesheets elements such as:
<stylesheets>
<!-- Any of the usual style sheet configuration can go here -->
...
</stylesheets>
stylesheets Element
The stylesheets element can only appear at the configuration root (i.e. it can’t be nested other any other configuration element) and only serves to hold stylesheet elements for application-wide stylesheet rules that are run against any service or form in the application.
| Attribute | Details | Description |
|---|---|---|
| name | required; string | A name for the stylesheets. Doesn’t service a purpose other than identifying it. |
stylesheet Element
The stylesheet element can appear as a child of the stylesheets for application-wide cascading configuration rules, or as the child of any other XML element. You can put them at the form root, or within any other element (box, repeater, record, attribute, etc.) so they only apply to a specific portion of the SFI tree (self and descendants from the element it’s a child of). You can also have style sheet selectors defined further down the SFI tree "overwrite" ones higher up the tree (or application-wide ones) if they target the same SFIs.
| Attribute | Details | Description |
|---|---|---|
| name | required; string | A name for the stylesheet. Doesn’t service a purpose other than identifying it. |
selector Element
The selector element is used to identify the SFI or items to target. The selector element can then contain either more selector elements to target additional SFIs and/or modifier child elements (see below) to apply changes to the targeted SFIs.
| Attribute | Details | Description |
|---|---|---|
| selector | required; string | A CSS selector string which targets one or more SFIs. |
Modifier child elements
To apply changes to the selected SFIs you configure modifier elements as a child of the selector element. All selected SFIs will then have that modifier applied. This section outlines the different modifiers available:
| Element name | Description | Attributes | Examples |
|---|---|---|---|
| visible | Sets the SFI’s visibility attribute | value: required; boolean | <visible value=”true”/><visible value=”false”/> |
| mandatory | Sets the SFI’s mandatory attribute | value: required; boolean | <mandatory value=”true”/><mandatory value=”false”/> |
| readOnly | Sets the SFI’s readOnly attribute | value: required; boolean | <readOnly value=”true”/><readOnly value=”false”/> |
| textKey | Adds/replaces an SFI’s text key element | type: required; stringkey: required; stringgroup: optional; string | <textKey type=”label” key=”myText.key.label”/><textKey type=”help” key=”myHelp.textKey”/><textKey type=”singleline” key=”some.other.text.key”/> |
| widget | Sets an SFI’s widget attribute | value: required; boolean | <widget value=”dateOnly”/><widget value=”table”/> |
| value | Adds/replaces a value child element to an SFI | name: required; stringvalue: optional; stringgroup: optional; string type: optional; string (used by Magellan only) | <value name=”myKey” value=”true”/><value name=”suppress-validation” value=”true”/><value name=”repeaterNoAdd” value=”true”/> |
| displayOptions | Adds a display option to an SFI | value: required; string | <displayOptions value=”option1″/><displayOptions value=”primary”/> |
| webServiceName | Sets the SFI’s webServiceName attribute | value: required; string | <webServiceName value=”webServiceName”/><webServiceName value=”directors”/> |
| rule | Adds rule configuration to an SFI | scope: optional; stringtype: optional; stringreference: optional; stringresourceName: optional; stringmethodName: optional; stringgroup: optional; string | <rule scope=”view-tree-initialise-complete” reference=”my.coolRule”/><rule scope=”instantiate” type=”groovy”>viewNode.setAttributeValueIfEmpty(‘blah’)</rule><rule scope=”validate” methodName=”doX” resourceName=”rules/myRule.groovy”/><rule scope=”*” methodName=”doY” resourceName=”rules/myRule.groovy”>{ “arg1”: “val1”, “arg2”: “${arg2Param}” }</rule> |
Behaviour limitations
Because they are applied as part of the service form, they only apply to the SFI layer defined by the XML. In other words, they do not consider the view tree and associated data, or changes made to nodes based on rules being run. Cascading configuration all happens before the view tree is built and it is not aware of the view tree or view nodes at all.
Just to be clear, Cascading configuration using stylesheet CSS selectors and modifiers alters the service form XML. This service form is used at runtime, but can be considered static XML (even though it is generated by Verne) for the purposes of understanding. For example, the following static XML configuration:
Note: some wrapper XML elements have been omitted for brevity.
<!-- Form config snippet -->
<record domain="SolarSystem">
<stylesheet name="sheet1">
<selector selector="[attributeName=Population]">
<visible value="false"/>
</selector>
</stylesheet>
<component:Planet/>
</record>
<-- Planet component snippet -->
<component name="Planet">
<parameter name="textKeyPrefix" default="component.planet"/>
<record domain="Planet">
<attribute attribute="Name" textKeyPrefix="${textKeyPrefix}.name"/>
<attribute attribute="Diameter" textKeyPrefix="${textKeyPrefix}.diameter"/>
<attribute attribute="Population" textKeyPrefix="${textKeyPrefix}.population"/>
</record>
</component>
Would result in the following generated service form XML configuration (which can be viewed in Magellan) used by the running application (notice how visible=false is now on the Population attribute):
<!-- Form config snippet -->
<record domain="SolarSystem">
<stylesheet name="sheet1">
<selector selector="[attributeName=Population]">
<visible value="false"/>
</selector>
</stylesheet>
<component name="Planet">
<parameter name="textKeyPrefix" default="component.planet"/>
<record domain="Planet">
<attribute attribute="Name" textKeyPrefix="${textKeyPrefix}.name"/>
<attribute attribute="Diameter" textKeyPrefix="${textKeyPrefix}.diameter"/>
<attribute attribute="Population" textKeyPrefix="${textKeyPrefix}.population" visible="false"/>
</record>
</component>
</record>
As you can see from this example, Cascading configuration allows you to alter the SFI tree used at runtime, but has no other runtime knowledge or impact. It does not know about view nodes.
CSS selectors
The selector attribute uses the CSS selector syntax to target the relevant SFI(s). This section outlines the options available for selecting various nodes and the CSS selector syntax to use. Note that the usual CSS selectors options and syntax applies and will not be covered here (e.g. the ">" separator to indicate a direct child), but rather this section focuses on what type and attribute properties are made available for CSS selection for various view node types. But first a brief introduction to the CSS selector syntax:
CSS selectors look at the XML structure, the SFI tree in this case, and allow you to match on any SFI element using the following pattern, where any portion is optional and you can have more than one of anything after the element-type:
element-type[attribute-name=attribute-value].class-name
So the following are all valid examples of this format:
box // element-type only
[shortCode=aBox] // one attribute name and value match only
.aBox // class name match only
box[shortCode=aBox].aBox // all three
[shortCode=aBox][attribute2=value2] // multiple attribute matches
.aBox.class2 // multiple class matches
Additionally, you can have nested selectors, which are multiple selectors each separated by a space. When you do this, each selector going from left to right must match on at least one SFI before processing the next selector (to the right), with each new selector only considering all descendants from the currently selected SFI. Take the following simple example consisting of three nested selectors (i.e. separated by spaces):
box record attribute // first matches all boxes, then looks for records within those boxes, and finally all attributes within those records
SFI attributes and classes
Now that we know the basics of selecting SFIs using the CSS selector syntax, let’s dive in to what element type, attributes and class values apply to the different SFIs so you know what you can target. The class is an attribute like any other, but is given special meaning in terms of CSS selection and you can refer to it using the . shortcut notation. In other words, instead of having a selector of [class=aBox] you can use .aBox (this will also match on any word within the class if the class has spaces in it). Similarly for the id attribute, you can use the # shortcut syntax,
| SFI type | Attributes | Class | CSS selector examples |
|---|---|---|---|
| All | id – the full SFI item codeshortCode – the SFI short codewidget – the SFI widget attribute*displayOptions – the SFI display options*Note: The SFI widget attribute value must be explicitly defined to be used as a selector i.e.<box shortCode=”aBox”/>: cannot target using widget CSS selector<box shortCode=”aBox” widget=”box”/>: can target using widget | SFI short code | [id=myForm.aBox]#myForm\.aBox[shortCode=aBox].aBox[widget=box][widget=dateOnly][displayOptions=do][displayOptions~=do2] |
| Root SFI | As per All plus:formCode – the form codeserviceCode – the service codeserviceMode – the service mode | As per All plus:form-code-[formCode]service-code-[serviceCode]service-mode-[serviceMode]service-mode-[lowercase serviceMode] | [formCode=myForm].form-code-myForm[serviceCode=mySvc].service-code-mySvc[serviceMode=Create].service-mode-Create.service-mode-create |
| Record | As per All plus:domainName – the record domain name | As per All plus:[domainName]domain-[domainName] | [domainName=MyDomain].MyDomain.domain-MyDomainrecordrecord[domainName=MyDomain]record.myDomainrecord.domain-myDomain |
| Attribute | As per All plus:attributeName – the attribute name | As per All plus:[attributeName]attribute-[attributeName] | [attributeName=MyAttribute].MyAttribute.attribute-MyAttributeattributeattribute[attributeName=MyAttribute]attribute.myAttributeattribute.attribute-myAttribute |
SFI XML examples
Given the above table, the following is an example of SFI details relevant to CSS selection, indicating what elements, attributes and class names you could match CSS selectors against for difference SFI types:
<!-- Attribute SFI -->
<attribute
id="7a1daac3e687e218"
shortCode="attr1"
attributeName="Attribute1"
widget="w1"
displayOptions="d1 d2"
class="attr1 Attribute1 attribute-Attribute1"/>
<!-- Record SFI -->
<record
shortCode="Address"
domainName="Address"
widget="w1"
displayOptions="do1 do2"
class="Address domain domain-Address"/>
<!-- Box SFI -->
<box
shortCode="box1"
widget="w1"
displayOptions="do1 do2"
class="box1"/>
<!-- Top level (root) SFI used by the mySvc 'Create' mode service -->
<record
shortCode="myForm"
domainName="Company"
widget="w1"
displayOptions="do1 do2"
formCode="myForm"
serviceCode="mySvc"
serviceMode="Create"
class="myForm domain domain-Company form-code-myForm service-code-mySvc service-mode-Create service-mode-create"/>
SFI CSS Selector examples
| Selector | SFIs matched |
|---|---|
| .Something | Any SFI with a short code or attribute name or record domain name of Something |
| [domainName=Planet].planetDetails | Any records with a Planet domain and planetDetails shortCode |
| record[domainName=Planet].planetDetails | As above (record type is redundant since only records have domainName attributes) |
| [domainName=IndividualDirector] [domainName=IndividualName] | Any IndividualName records that are within an IndividualDirector record |
| [domainName=IndividualDirector] > [domainName=IndividualName] | Any IndividualName records that are the direct child of an IndividualDirector record |
| box.banana [attributeName=Attr1] | Any Attr1 attributes within a box with a shortCode of banana |
| box.banana .attribute-Attr1 | As above or any SFI with a shortCode of attribute-Attr1 within a box with a shortCode of banana |
| [formCode=planetDetails] .Attr2 | Any SFI within the planetDetails form that has a shortCode of Attr2 or Attr2 attributes |
| .form-code-planetDetails .Attr2 | As above or any SFI within an SFI with a shortCode of form-code-planetDetails that has a shortCode of Attr2 or Attr2 attributes |
| record[displayOptions=do1\\ do2\\ do3] | Any records with the displayOptions exactly matching “do1 do2 do3” |
| record[displayOptions=do2] | Any records with the displayOptions exactly matching “do2” |
| record[displayOptions~=do2] | Any records with a display option of do2 |
| [serviceMode=Change] [domainName=IndividualName] attribute | Any attributes within IndividualName records for a service with a mode Change |
Cascading Configuration Examples
<stylesheets>
<stylesheet name="appCodeSheet">
<selector selector="[serviceMode=Change] repeater.planets">
<value name="repeaterNoDelete" value="true"/>
</selector>
</stylesheet>
</stylesheets>
<serviceFormItems>
<record shortCode="myForm" domain="SolarSystem">
<stylesheet name="myFormSheet">
<selector selector="repeater.planets">
<selector selector="[domainName=Planet] [attributeName=Population]">
<visible value="true"/>
<value name="suppressValidation" value="true"/>
<rule scope="instantiate" reference="planet.earth.population.defaultValue"/>
</selector>
</selector>
</stylesheet>
<repeater shortCode="planets" textKeyPrefix="repeater.planets">
<record domain="Planet">
<attribute attribute="Name" textKeyPrefix="planet"/>
<box shortCode="details">
<stylesheet name="planetDetailsSheet">
<selector selector="[attributeName=Diameter]">
<rule scope="validate" reference="planet.mars.diameter.validate"/>
</selector>
</stylesheet>
<include fragment="planet/details"/>
</box>
</record>
</repeater>
</record>
</serviceFormItems>

