One of the great things about subclasses is that you can encapsulate lots of XHTML markup in one, and then reuse the markup very easily.
To demonstrate this, we're going to tackle one of the holy grails of web design (according to some): rounded corners on panels in web browser.
Here is the (short version) of the HTML markup defining the new panel:
<j:module targetNamespace="urn:example"> <j:control name="RoundedPanel" base="Container"> <j:property name="text" type="string" /> <j:defaults> <div class="contentWrapper"> -- lots of HTML -- <div class="content"> <!-- header and content here --> <h1><j:Label text="#param(text)"/></h1> <j:Placeholder useParam="content"/> </div> -- lots of HTML -- </div><!-- //contentWrapper --> </j:defaults> </j:control> </j:module>
As with the previous subclassing example, the control is within a <j:module> section. All control definitions must live within <module>s.
A <module> can define multiple controls and other datatypes. In this case we just have the RoundedPanel. (See Jitsu Data Language for more on datatypes).
The first two lines of the control definition are:
<j:control name="RoundedPanel" base="Container"> <j:property name="text" type="string"/>
The first line tells the Jitsu compiler to create a new control type called RoundedPanel, to make it a subclass of the Container control (a generic container of children and HTML).
The second line adds a property called "text" to the panel class. This means that when you use the control you'll be able to write:
<app:RoundedPanel text="Text goes here" ...
or:
<app:RoundedPanel text="#bind(some.path.here)" ...
and the property value will be known to the control.
Now we specify the default properties of the rounded panel:
<j:defaults> <div class="contentWrapper"> -- lots of HTML -- <div class="content"> <!-- header and content here --> <h1><j:Label text="#param(text)"/></h1> <j:ParamPlaceholder/> </div> -- lots of HTML -- </div><!-- //contentWrapper --> </j:defaults>
Within the markup of the defaults property, you'll see two new constructs, #param, and <ParamPlaceholder>.
#param is used when specifying a value on an inline property. Note that this is a general runtime expression part, so you can combine this with bindings, resource retrieval, even javascript expressions.
<Placeholder> allows you to specify where to insert a collection of controls into an existing control, that were specified as parameters. The name of a placeholder's useParam attribute must match one of the param properties on the control.
Here is a usage of the control defined above:
<app:RoundedPanel text="First panel" style="width: 200px"> <div>Here is some content. This text appears in a rounded corner box.</div> </app:RoundedPanel>
The text property value has been specified inline. The content property, which replaces the Placeholder, is declared inline for convenience. To be more explicit, one could also have written
<app:RoundedPanel text="First panel" style="width: 200px"> <content> <div>Here is some content. This text appears in a rounded corner box.</div> </content> </app:RoundedPanel>
While more verbose, this latter form is required when a control offers more than one ParamPlaceholder.
If you really like a control, you can move the control definition into a separate .xml file, and then include the control on multiple pages with a <j:using> directive.