This article covers a Bloomreach Experience Manager version 11. There's an updated version available that covers our most recent release.

YUI Layout Based Wireframes

Introduction and History

Web applications tend to have UI requirements that exceed what is currently possible with plain CSS, especially when in need of supporting a broad range of browsers including 'the older' ones.

For example, your application should always use the full available viewport, AKA a 100% fluid layout in which widgets know how much width/height is available for them to render in and resize when asked to, without bringing the browser UI thread to a complete halt. 

Moreover, certain elements in the UI should be resizable by a user, and when he/she logs in the next day, these elements should still have the new size, without affecting the other users of the system. Ah, and it would also be nice to be able to nest wireframes.

Did I mention that doing this in CSS is hard? Or even better, (cross-browser) CSS is hard? 

So, no CSS only solution possible, skip to Javascript. At the time we started working on a rich UI, most javascript libraries (YUI, JQuery, MooTools, etc) offered some form of layout management for fluid web applications and the YUI Layout Manager seemed to be the most mature, feature rich implementation, backup by giant YAHOO and gift-wrapped with lot's of documentation and examples. It also natively supports nested layouts, resizing of wireframe elements and the possibility to render scrollbars when applicable.

A short introduction into YUI layouts.

A layout or wireframe is a structured block containing five units, top, right, bottom, left and center (see http://yui.github.io/yui2/docs/yui_2.9.0_full/layout/#wireframe). The center unit is always present and fills up the space not occupied by it's neighboring units. The other units have pre-defined initial width/height constraints that are managed by the framework.

A wireframe can either be added to the body-element and take up the full viewport, or be added to an existing element with custom width and height properties. In both cases a resize of the viewport will cause the wireframe to resize itself and all nested wireframes within the new given boundaries.

Every wireframe and unit has a corresponding element in the DOM. This element is identified by it's id attribute which should be known at render time. Because of this requirement and the fact we are working in a composite environment where we want to be able to re-use components without having to worry about id clashes in the DOM, we have added the concept of the YuiId, which is applied to all elements that require a lookup by @id inside the layout framework.

What is a YuiId?

A YuiId allows for transparent elementById resolution. It can either reference an element directly by it's @id value (normal getElementById), or reference an element by it's @yui:id value, which is only valid within the context of an ancestor @id value.

The first case is probably clear for every web-developer, just a simple getElementById. Not re-useable in the same DOM, but if that is not a requirement, your fine. The second one is a bit more difficult to explain, so I'll give an example. Let's say we have an AjaxPanel containing the following html.

<div wicket:id="root">
  <div class="container"
    <div yui:id="top">[ Top unit ]</div>
  </div>
</div>

Wicket will generate and id value for the root element, so it might become " rootAA". Now, if we want to create a YuiId that references the 'Top unit' div element, it will get the value " rootAA:top". When the AjaxPanel is reused on a different place in the DOM, the YuiId might have changed to " rootZZ:top", which will still resolve to the correct top element without id clashes. For this, we have added a custom getElement function:

 YAHOO.hippo.Dom.resolveElement(YuiId);

which lives in the YUI ' hippodom' module.

Rendering wireframes

When a wireframe is rendered, it will create a new node structure inside it's root-element, representing the new wireframe and it's unit containers. It will than move the elements representing the units into their new container elements.

For example: (our wireframe root element is identified by id 'root' and contains two units: top and center.

<div id="root">
  <div id="top">[ Top ]</div>
  <div id="center">[ Center ]</div>
</div>

After the wireframe has rendered it will look something like (this is a slimmed down version of the real deal for the sake of readability)

<div id="root" class="yui-layout">
  <div class="yui-layout-doc">
    <div class="yui-layout-unit yui-layout-unit-top">
      ..
        <div id="top">[ Top ]</div>
      ..
    </div>
    <div class="yui-layout-unit yui-layout-unit-center">
      ..
        <div id="center">[ Center ]</div>
      ..
    </div>
  </div>
</div>

In the above example, the dots are actual elements added by YUI used for handling size, scrollbars, borders, etc.

To integrate the YUI layouts into Wicket, we have added a clientside manager component that handles the lifecycle, rendering and resizing of the wireframe structure.
For more info see the inline documentation in layoutmanager-debug.js

Configuration

Below is a configuration and HTML example:

<sv:node sv:name="application">  
  <sv:property sv:name="jcr:primaryType" sv:type="Name">
    <sv:value>frontend:plugin</sv:value>
  </sv:property>
  <sv:property sv:name="plugin.class" sv:type="String">
    <sv:value>org.hippoecm.frontend.plugins.cms.Main</sv:value>
  </sv:property>
  <sv:property sv:name="wicket.id" sv:type="String">
    <sv:value>service.main</sv:value>
  </sv:property>
  <sv:property sv:name="wicket.behavior" sv:type="String">
    <sv:value>service.behavior.main.layout</sv:value>
  </sv:property>
  <sv:property sv:name="wicket.extensions" sv:type="String">
    <sv:value>extension.top</sv:value>
    <sv:value>extension.center</sv:value>
  </sv:property>
  <sv:property sv:name="extension.top" sv:type="String">
    <sv:value>service.application.top</sv:value>
  </sv:property>
  <sv:property sv:name="extension.navigator" sv:type="String">
    <sv:value>service.application.center</sv:value>
  </sv:property>
</sv:node>
<sv:node sv:name="mainLayout">
  <sv:property sv:name="jcr:primaryType" sv:type="Name">
    <sv:value>frontend:plugin</sv:value>
  </sv:property>
  <sv:property sv:name="plugin.class" sv:type="String">
    <sv:value>
      org.hippoecm.frontend.plugins.yui.layout.WireframePlugin
    </sv:value>
  </sv:property>
  <sv:property sv:name="behavior.id" sv:type="String">
    <sv:value>service.behavior.main.layout</sv:value>
  </sv:property>
  <sv:property sv:name="units" sv:type="String">
    <sv:value>left</sv:value>
    <sv:value>center</sv:value>
  </sv:property>
  <sv:node sv:name="yui.config">
    <sv:property sv:name="jcr:primaryType" sv:type="Name">
      <sv:value>frontend:pluginconfig</sv:value>
    </sv:property>
    <sv:property sv:name="center" sv:type="String">
      <sv:value>id=main-center,body=main-center-body,minWidth=400</sv:value>
    </sv:property>
    <sv:property sv:name="left" sv:type="String">
      <sv:value>
        id=main-left,body=main-left-body,resize=true,minWidth=300,width=400
      </sv:value>
    </sv:property>
  </sv:node>
</sv:node>
<html xmlns:wicket="http://wicket.apache.org/"
      xmlns:yui="http://www.hippoecm.org/frontend/yui">
  <wicket:panel>
    <div wicket:id="main">
      <div yui:id="main-left">
        <div yui:id="main-left-body">
          <div wicket:id="extension.left">[Left unit]</div>
        </div>
      </div>
      <div yui:id="main-center">
        <div yui:id="main-center-body">
          <div wicket:id="extension.center">[Center unit]</div>
        </div>
      </div>
    </div>
  </wicket:panel>
</html>
Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?