How Widgets Work

Introduction described the modes of operation of widgets and outlined how widgets can be associated with domain definitions. The widget developer will benefit from a deeper understanding of this process and of its dynamics.

As explained in the previous chapter, widgets are selected and invoked automatically by the system depending on the type of data and mode of operation of a field. In UIM, each FIELD is associated with data using SOURCE and/or TARGET connections. The system identifies the type of the data based on the domain definition of the server interface property named on those connections. The domain definition for the TARGET connection is preferred over that of the SOURCE connection. The mode is determined by the presence or absence of the TARGET connection; if a TARGET connection is present, the edit mode is used; if only a SOURCE connection is present the view mode is used.

A configuration file associates the widgets' renderer plug-in classes with domain definitions, so that, for any given type of data and mode of operation, the same renderer plug-in class is invoked on every page to present that data with the appropriate HTML mark-up. A widget's renderer plug-in class can identify itself as either a view-renderer for the view mode or an edit-renderer for the edit mode, but not both, so a separate renderer plug-in class is required for each mode. The configuration allows one edit-renderer plug-in class and one view-renderer plug-in class to be associated with each domain definition. If the developer changes the configuration file so that a custom widget's renderer plug-in class is associated with a domain definition, then every time a field in that mode with a connection to data in that domain is presented on any page, the custom renderer plug-in class will be used. Thus, the developer can produce any desired custom HTML mark-up to present the data of any UIM FIELD and see that applied consistently across the application.

The same widget is often used for many different types of data in a given mode. For example, the application presents the majority of view-only data using a single widget that simply inserts the text representation of that data into the HTML without any HTML element mark-up. Only where the presentation is more specialized are specialized widgets applied.

The CDEJ invokes widgets in the course of transforming a UIM page to HTML. For widgets associated with UIM FIELD elements, this always happens at run-time. During the rendering of the page, the CDEJ constructs a Field object from the information defined in the UIM. Using this information, it consults the domain configuration to select the appropriate widget's renderer plug-in and then passes the Field object to the renderer plug-in along with an empty DOM DocumentFragment object. Using the information provided by the Field object, the renderer plug-in uses the DOM Core API to create the DOM nodes representing the required HTML and field value and adds these nodes to the DocumentFragment object. When the renderer plug-in returns, the CDEJ will take the now populated DocumentFragment object, serialize it to a HTML text stream, and add this to the stream being returned to the web browser. By this method, any HTML content can be produced by the renderer plug-in class.

The developer can implement a widget such that multiple renderer classes are used together to achieve a presentation requirement. The CDEJ first invokes a single renderer plug-in class based on its association with a domain definition. That renderer class can then delegate the rendering of elements of its output to other renderer classes. The first renderer can create empty DOM DocumentFragment objects of its own and pass them on to the other renderers. These renderers will populate the fragments with HTML nodes and the first renderer can add the contents of those fragments to its own before returning control to the CDEJ. Combining renderer classes together into such a rendering cascade simplifies the individual renderer classes and maximizes the potential to reuse these classes in other combinations to realize new custom widgets. Examples of this process will be presented in later chapters of this guide.

The configuration file, identified in the previous section, that associates renderer plug-in classes with domain definitions is subject to the same type of component-order-based merging as most other configuration files in the Cúram client application. In simple terms, the CDEJ default domain configuration is loaded first. Then the domain configurations defined (if at all) in each of the application's components are loaded in order from the lowest priority component to the highest priority component. Each configuration can replace elements of the the configuration that has been loaded before, so the last configuration is the one that has the most control. The actual configuration process is a little more complex than this simplified explanation and is explained in full in Configuring Renderers. Crucially, the configuration defined in the application is given more weight than that defined in the CDEJ, so it is possible for the developer to customize anything. However, there are limits on what customizations are supported within the Cúram application and that are described at the relevant points in this guide.

When a custom widget controls most of the page content, it is often the case that much of the output of the widget relates to laying out other page content in the correct manner. The view-renderer and edit-renderer plug-in types that are associated with domain definitions are used to renderer fields that are bound to data. However, page layout is often unrelated to any data. Another type of plug-in, the component-renderer, can be used to perform these layout operations. These plug-ins are associated with styles, not domain definitions, and can be invoked by the domain-specific renderers when necessary. Styles and component-renderer plug-ins are covered in Tying Widgets Together in a Cascade.