Imperative Programming In CSS

Posted on by Chris Warburton

In the past week I’ve been doing the worst form of Web development ever conceived. That’s right, HTML emails. I’m doing this on SalesForce, which provides a horrendous mishmash of custom languages for templating and the like. It’s not been a pleasant experience, as my Identi.ca stati will attest to.

One problem which produced an interesting solution was adding a column to a table, conditional that at least one of its cells is non-empty. Here’s the gist of the problem, using SalesForce’s markup and templating languages (called “VisualForce”) but with made-up function names:

<apex:variable var="showThird"
               value="{!anyHasField(Source, "Field_3")}" />
<table>
  <tr>
    <th>Field 1</th>
    <th>Field 2</th>
    <apex:outputPanel rendered="{!showThird}">
      <th>Field 3</th>
    </apex:outputPanel>
    <th>Field 4</th>
  </tr>
  <apex:repeat var="thisElement" value="{!Source.elements}">
    <tr>
      <td>{!thisElement.Field_1}</td>
      <td>{!thisElement.Field_2}</td>
      <apex:outputPanel rendered="{!showThird}">
        <td>{!thisElement.Field_3}</td>
      </apex:outputPanel>
      <td>{!thisElement.Field_4}</td>
    </tr>
  </apex:repeat>
</table>

Some things to note: - apex is the namespace for most of VisualForce’s elements. - variable assigns the contents of its value attribute to the name in its var attribute. Unfortunately this is a wannabe-imperative construct with bizarre scoping behaviour, rather than a nice, pure “let” construct :( - outputPanel allows us to wrap a block of markup. It will only be included in the output if its rendered attribute is true. - repeat will output its contents once for each element of the collection given in the value attribute. Each element is accessible in its copy via the name given in the var attribute. - Source is just an object which contains the data we need. Source.elements means what you would expect in Java (look up the elements field of the Source object). - VisualForce uses a non-XML templating language as well as XML. Expressions in this language start with {! and end with }. I have absolutely no idea why they don’t just define more XML elements. - It’s acceptable (actually, it’s required) to nest quotes when using the templating language inside an attribute, as you can see in the value of the showThird variable.

The problem with the above code is that the set of functions we can use is incredibly limited. The anyHasField function doesn’t exist, I just made it up to get across the problem. How can we get the behaviour we want, given these massive restrictions?

This kind of problem is encountered all of the time when programming. The usual solution is to assume that all of the fields are empty, and change our mind if we see a non-empty field. Imperatively this looks like the following:

showThird := FALSE
FOR EACH Source.elements AS thisElement:
  IF nonempty(thisElement.Field_3):
    showThird := TRUE
  ENDIF
ENDFOR

We can squash this down a little by noticing that the IF branch has the same behaviour as Boolean OR:

showThird := FALSE
FOR EACH Source.elements AS thisElement:
  showThird := showThird OR nonempty(thisElement.Field_3)
ENDFOR

However, VisualForce is not an imperative language. Once we define a variable, we cannot redefine it without producing undefined behaviour (“nasal demons”).

Of course, I’m a proponent of immutable variables, so this isn’t a problem. We can get the same behaviour by folding over Source.elements:

showThird = foldl folder False Source.elements
folder result thisElement = result || nonempty (thisElement.Field_3)

Unfortunately we can’t express our own functions (like folder above) in VisualForce, and it certainly doesn’t provide the primitives we would need (composition and fold). So, what do?

The solution I’ve come up with is to use the original imperative solution, but in a language which allows us to re-assign variables. Which language? Cascading Style Sheets (CSS). The elegance of using CSS for the imperative logic is that we have direct control over the display of the elements; our boolean variable is the display property of the elements, with block as true and hidden as false. This way, we don’t need an additional conversion step like IF showThird THEN block ELSE hidden. This isn’t exactly the same as the original example, since the markup is always included, but it has the same effect and that’s all we care about.

We generate our markup as follows:

<table>
  <tr>
    <th>Field 1</th>
    <th>Field 2</th>
    <th class="third">Field 3</th>
    <th>Field 4</th>
  </tr>
  <apex:repeat var="thisElement" value="{!Source.elements}">
    <tr>
      <td>{!thisElement.Field_1}</td>
      <td>{!thisElement.Field_2}</td>
      <td class="third">{!thisElement.Field_3}</td>
      <td>{!thisElement.Field_4}</td>
    </tr>
  </apex:repeat>
</table>

Now we can generate our CSS:

.third {
  display: hidden;
}

<apex:repeat var="thisElement" value="{!Source.elements}">
  <apex:outputPanel rendered="{!nonempty(thisElement.Field_3)}">
    th.third {
      display: block;
    }
    td.third {
      display: block;
    }
  </apex:outputPanel>
</apex:repeat>

The first block is always included. It sets elements with the third class to hidden. This is equivalent to our showThird := FALSE line.

We then loop over all elements, and for any with a non-empty Field_3 we include a block which sets table headings and cells with the third class to visible.

CSS selectors follow a precedence rule, where more-specific selectors will override less-specific ones. We use this precedence to emulate an imperative language; we treat the selector specificity like a line number in BASIC! td.third and th.third are more specific than .third, so they ‘run afterwards’. By including these conditionally, we’re using an if-condition in our meta-language to emulate an if-condition in our object language (CSS). These blocks may be included many times, but that’s perfectly acceptable and results in the same behaviour as a single inclusion.