ShowTable of Contents
The purpose of this document is to provide some best practices for developing custom visualizations for both Custom Controls and Native Controls in Domino Designer.
Concept
The main motivation for giving a Custom Control a custom visualization is to aid in the development of applications that use that control. Concept:
You should be able to add controls from the controls palette as well as data from the data palette to the source tab of the XPages editor with the same behavior as adding them to the design tab. You should not be able to generate invalid source.
Supported Methods Of Adding Controls:
There are a number of different ways to add controls to an XPage, all of which are supported in the source editor in the same way that they are supported in the design editor
- Standard drag and drop from the controls palette with the mouse
- Placing the cursor at any location (or selecting a section of code) within the source editor and double clicking a control in the controls palette
- Placing the cursor at any location within the source editor (or selecting a section of code) and using the "Create" menu to insert a control
Supported Methods Of Adding Data:==
- Standard drag and drop from the data palette with the mouse
Drag and Drop behavior for all Controls:
Some basic behavior is the same for all controls regardless of their type. This is when you drop a control to whitespace in the source editor. Whitespace in this context means any blank lines within the xp:view tag and that are not within the opening and closing tags of any other controls.
- If you drop any control to whitespace in the source editor, the control should be created on that line.
- If you select multiple lines of whitespace in the source editor, and use the create menu to add a control (or double click in the controls palette), the control should be dropped to upper most line of whitespace that is selected.
- If you select any section of source code in the source editor which begins with some whitespace (the whitespace can span any number of lines), and use the create menu to add a control (or double click in the controls palette), the control should be dropped to top most line of whitespace that is selected.
Determining the Target Control
If you are not dropping to whitespace, then you must be dropping to another control. Before going into the drop behavior of the various controls, it is important to know what the editor considers your target control to be. The "target control" is the control that you are trying to add another control to. In simple terms, the target control is the control that contains the caret when no source is selected, or the upper most selected control in any source selection. When we deal with selection, we always use the uppermost control in the selection as the target control.
More specifically:
- If you drop to the beginning tag, body or ending tag of a control, that control will be the target control. This is equivalent to placing the caret anywhere inside a controls tag structure.
In this example, you are dropping to an Edit Box control, so that is the target control
In this example the caret is within the tag structure of an Edit Box control, so that is the target control.
- If you select any part of a control in source (so highlight any part of the start tag, body or end tag, or combination of the three, where one or more characters are selected) or select an entire control in source (highlight the entire start tag, body and end tag) that control will be the target control.
In this example, an Edit Box control is partially selected, so that is the target control.
- If you select multiple controls in the source tab (so highlight the entire start tags, body and end tags of multiple controls), the top most selected control will be the target control. This is also true for partial selection of the uppermost control. Even if you only have the very last '>' character of the ending tag of the uppermost control selected, that will be the target control.
In this example, despite the caret location, the uppermost selected control is the Edit Box control, so that will be the target control.
Types of Controls
There are essentially two different types of controls that can be added to an XPage. Those that allow other controls to be added as child controls and those that don't. For example, you cannot drop a button control into an edit box control, but you can drop a button control into a panel control. We refer to controls that do not accept other controls as children as Core Controls, and those to do accept children as Container Controls.
Dragging and Dropping to Core Controls
Core controls have the simplest drop scenarios. They do not allow other controls to be dropped into them. All the controls that reside within the Core Controls drawer of the Controls Palette are considered Core Controls, with the exception of the Link Control. Although the link control is listed as a core control, it can have children, so it is possible to drop into the link control in source. Therefore it is handled in the same way as a container control.
- If your target control is a core control, then the dropped control should be created on the line directly above the target control.
Dragging and Dropping to Container Controls
From here on Container Controls will refer to all the controls in the container control drawer of the controls palette, as well as the Link Control.
Container controls are more complex than core controls. They have two main use cases, where the container control is empty and does not already have child controls, and where the container control does already contain child controls and we are adding more.
Empty Container Controls
- If your target control is an empty container control, the dropped control should be created as a child of the target control.
- If you drop any control to a blank line within the body of a container control, the control will be created on that line.
Non-Empty Container Controls
The rules for determining the target control for any drop still apply to non-empty container controls, but with some further caveats. This is to try to make it a little easier to add child controls to the top and bottom of a container control
- If you drop any control to the starting tag of a container control, the control will be created as the first child of the target control. So if you were dropping a button to a panel that already contained a checkbox, the button would be added above the checkbox control.
- If you drop any control to the ending tag of a container control, the control will be created as the last child of the target control. So if you were dropping a button to a panel that already contained a checkbox, the button would be added below the checkbox control.
- If you select an entire target control in source (highlight the entire start tag, body and end tag) and use the create menu to insert a control (or double click in the controls palette), the control should be created as the top level child of the container control. So if you were dropping a button to a panel that already contained a checkbox, the button would be added above the checkbox control.
- If you select any part of the closing tag of a container control in source and use the create menu to add a control (or double click in the controls palette), the control will be added as the last child of the target control. So if you were dropping a button to a panel that already contained a checkbox, the button would be added below the checkbox control.
- If you select any part of the starting tag of a container control in source and use the create menu to add a control (or double click in the controls palette), the control will be added as the first child of the target control. So if you were dropping a button to a panel that already contained a checkbox, the button would be added above the checkbox control.
- If you select any part of the starting tag of a container control in source as well as any part of the body of the control and use the create menu to add a control (or double click in the controls palette), the control will be added as the first child of the target control. So if you were dropping a button to a panel that already contained a checkbox, the button would be added above the checkbox control.
Custom Container Control Behavior
Some of the container controls have custom behavior, described here.
Table Control
When you drop a table to the source editor it will create a structure similar to this
<xp:table>
<xp:tr>
<xp:td></xp:td>
</xp:tr>
</xp:table>
where the xp:tr tags represent rows and xp:td tags represent cells. You can only drop into cells in a table. Rows cannot accept children that are not <xp:td> tags and do not accept drop commands. So for the drop to source behavior, you cannot drop children to the table tag or the table row tags, so they act as core controls, but you can drop to the table cell tag, so it acts as a container control.
The selection rules from above hold true and work like this.
- If you try to drop to the xp:td tag using any of the container control conditions from above, the control will be added as a child of the xp:td tag as expected.
- If you try to drop to the xp:tr tag, it does no accept a drop, so we move up and check the table tag. It too won't accept drop, so we move up, in this case to the view tag (could be any container control parent, like a panel as well) which can accept a drop, so the control will be dropped directly above the table tag.
- If you try to drop on the xp:table tag, the control will be dropped directly above the table control.
View Control
When you drop a view panel you should get a structure similar to this
}
}
You cannot drop into a viewPanel, or a viewColumn or a viewColumnHeader. So the entire view panel will act as nested Core Controls. So for example if you tried to drop a control onto the viewColumnHeader tag, it would not accept the drop, so we would try to drop to the viewColumn. It wouldn't accept drop either so we would try dropping to the viewPanel, which wouldn't accept the drop, so the control would be dropped just above the starting viewPanel tag.
Data Table
When you drop a data table to a page and add a column to it. (This can only be done in the design editor) you get a structure like this.
}
}
So for a simple dataTable, like the one above, the xp:column tag acts as a container control. So you can drag and drop to in all the ways you would expect to be able to drop to a container control. The dataTable tag does no allow drop actions, so it will act as a core control. So if you try to drop to the dataTable tag, it will drop the control above the dataTable.
It gets more complicated when you have to deal with dataTable column headers and footers. The header and footer areas of a dataTable column are not their own tags. There are hidden facets specified for the xp:column tag, So to add a control to the header, you need to wrap the the control in a this.facets tag and then add that as a child of the xp:column tag specifying an xp:key attribute on the control to match the facetName of the hidden facet. So for example, here is a rough example of a dataTable with a span in its header and a button in its footer.
}
}
Dropping to the facets tag first of all, will drop up. It will not accept a drop itself, so it will look to its parent, the column, which does accept drop so the control will be added right above the facets tag, inside the column tag.
Dropping to the column tag will never generate the this.facets tag, and will never add a control to the header or footer. You would have to set up the controls in the header and footer either manually in source, or through the Design editor.
But once the header and footer children are created, they act as you would expect. So in this case, we have a span for the header. The span control is a container control, so a user could drag and drop new controls into the span tag using all the same rules as earlier in this document.
We have a button in the footer though, which is a Core Control and does not accept drop actions. So if you try to drop onto the button, it will search up, try to drop on the facets tag, which it can't, search up again, will find that it can drop to the column tag, so will drop the control right above the facets tag, inside the column tag.
Tabbed Panel
The tabbed panel is a special case. It is quite a simple control really. It has a structure like this
}
}
The tabPanel tags are container controls and act exactly as you would expect them to given the rules above.
You cannot drop inside a tabbedPanel tag, so for the most part it acts as a Core Control. So if you were to try to drop to its start tag, it would drop the control above the tabbedPanel etc.. as you would expect.
However the tabbed panel has custom drop behavior if you try to drop to its closing tag. Instead of dropping out of the tabbedPanel control and putting the new control above the xp:tabbedPanel tag, it will add the control as the last child of the last tabPanel child of the tabbedPanel control.
So for example if you were to try to drop a button on the closing </xp:tabbedPanel> tag
This behavior is allowed for this control only, because of the restricted nature of the tabbed panel tag structure.
Dragging and Dropping to Custom Controls
Custom controls are a special case as you cannot drop into a custom control by default. You can only drop into a custom control if it has a facet specified (an editable area control added to it). And there are two different types of factes, those that have a facetName and those that don't. If a custom control has a facet with a facetName, that facet can contain one child control only. If the facet does not have a facet name, it can contain any number of child controls. Any custom control can have any number of both types of facets.
Custom controls with a facet could also then have another custom control added to it that has a facet, giving nested facets.
A custom control, may contain another custom control which contains a facet, in which case we have a facet nested to 2 levels. You cannot drop to facets nested to 2 levels.
By default if you were to drop to a custom control it would have acted like a Core Control regardless of any facets and you would have not been able to drop into it.
However, seeing as custom controls and facets are so widely used, we have implemented some support for this.
Take the example a custom control (cc1) on an XPage.
}
}
If the drop is allowed into a facet in the custom control, the control is always appended as the last child of the custom control. Even if you drop on the start tag, the new control will always be added as the last child.
As mentioned before, a custom control can have different types of facets, and we have no way of knowing which one was the intended drop target. So an order of preference is used to select a facet to drop to.
- If the custom control has only one valid facet, then use that one, regardless of its type.
- If the custom control has both facets with facetNames and without, we use the facet without the facetName as the target.
- If the custom control has no valid facets to drop to, we don't allow drop, and the control will be added above the custom control tag.
- If the target control has multiple facets with facetNames, the drop action will target the first one that is found that can be dropped to. So for example if you had a custom control that contained 3 Editable Areas with facetNames "facet_1, facet_2, facet_3" (in that order in the custom control), the first drop would drop to facet_1, the next drop we would drop to facet_2 .... and so on. Once all three facets have been filled, any further controls dropped to the custom control will be dropped out and placed above the custom control.
Dragging and Dropping from the Data Palette
You can drag and drop view and document data from the data palette into the source of an XPage. It should have all the same capabilities as dropping into the design editor.
- Dragging and dropping a domino view data source to whitespace in the source editor should drop the selected data elements in the data palette to the selected line in the source editor (drop a view containing view columns bound to the selected data sources in the data palette)
- Dragging and dropping a domino view data source to a control that accepts data (an editBox for example) should set the data binding on that element to be the dropped data source.
- Dragging and dropping a domino view data source to a control that accepts data (an editBox for example) and that already has a data binding set on it (document or view), should reset the data on that control to be the newly dropped data source
- Dragging and dropping a domino view data source onto a control that does not allow data to be set on it, should drop the selected data sources in the data palette directly above the target control in the source editor.
- Dragging and dropping a domino document data source to whitespace in the source editor should drop the selected data elements in the data palette to the selected line in the source editor (drops a table containing an inputText control bound to the data source and with a convertor to set the data type of the inputText... exactly as it would do dropping to the design editor).
- Dragging and dropping a domino document data source to a control that accepts data (an editBox for example) should set the data binding on that element to be the dropped data source.
- Dragging and dropping a domino document data source to a control that accepts data (an editBox for example) and that already has a data binding set on it (document or view), should reset the data binding on that control to be the newly dropped data source
- Dragging and dropping a domino document data source onto a control that does not allow data to be set on it, should drop the selected data source in the data palette directly above the target control in the source editor.
After all, once a Custom Control has been completed, the details of it construction are largely irrelevant, especially if the controls consumer is not its original developer. They do not affect the operations of the control, only how they appear in XPages and other Custom Controls during development.
Custom visualizations are more of a necessity when developing native controls. Native Controls require a custom visualization, or they will render as unknown controls in the XPages/Custom Controls editor. Giving these controls a custom visualization allows you to control how they render as well as their behavior in the XPages/Custom Controls editor.
Custom Controls
Lets take the example of the ccTagCloud Custom Control within the "Discussion - Notes & Web" template that ships with Domino Designer.
The ccTagCloud Custom Control represents a tag cloud control. As you will see the tag cloud Custom Control is essentially a series of nested panels containing a repeat control that will render a number of link controls inside a span control.
This type of control could clearly be reused in any number of applications and by any number of potential application developers. As well styled as this control may be at runtime, during development, this Custom Control will look nothing like a real tag cloud.
Here is how it would look on an XPage with no custom visualization specified.
To aid any potential developer in utilizing this control, the solution was to simply provide a custom visualization that renders an image of the control running on a server in place of the Custom Controls design as would normally be shown. (Ignore where it says "tagCloud for null" for now. It will be explained later on).
Specifying the Custom visualization
Custom Control custom visualizations are specified in the "Design Definition" properties panel (displayed when editing a Custom Control). The custom markup specified in the Design Definition panel must be valid XSP markup. What this means, is that essentially it must be the complete source of any valid XPage or Custom Control.
Designing the Custom visualization
As previously stated, the markup for the custom visualization must be valid XSP markup. The easiest way to create valid XSP markup is to use the XPages/Custom Control editor. To do this you will need to create a new XPage or Custom Control. For the most part, it is best to create a new Custom Control, especially when working with Native Controls (I will explain why later).
Once you have your temporary Custom Control created, you can use the controls palette to drag and drop controls and create a more user friendly representation of your Custom Control. At this stage, you only need to worry about how it looks and not with whether it would actually work. So for the ccTagCloud Custom Control, we would just need to drop an image on the temporary Custom Control.
When you are happy with the design, switch to the source tab and copy the entire contents of the page.
Switch back to your original Custom Control and paste this into its design definition panel.
Your Custom Control (In this case, the ccTagCloud Custom Control) will now appear with your new user friendly representation across Designer. Like so:
Beyond the basic case
As you might imagine a custom visualization often needs to be more complicated than what can be accomplished using the method above alone. For example if instead of using an image to represent the tagCloud, you may want to build a complete representation of the tagCloud for translation purposes etc.. Here is an example of some XSP source for a Custom Control that will look similar to the tagCloud image.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:panel
style="height:191.0px;width:176.0px;border-color:rgb(255,255,255);background-color:rgb(248,248,248)">
<xp:section id="section1"
style="border-color:rgb(255,255,255)">
      
<xp:span style="font-weight:bold">Top 25 Tags</xp:span>
</xp:section>
<xp:image url="/ccTagClould_slider.JPG" id="image1"
style="width:175.0px">
</xp:image>
<xp:label value="Agenda" id="label1"
style="color:rgb(14,78,112);font-size:10pt;font-weight:bold">
</xp:label>
<xp:label value="Cloud" id="label22"
style="font-size:10pt;color:rgb(14,78,112);font-weight:bold">
</xp:label>
<xp:label value="Communities" id="label2"
style="font-size:9pt;color:rgb(150,209,241);font-weight:bold">
</xp:label>
<xp:label value="Connections" id="label3"
style="font-weight:bold;color:rgb(150,209,241);font-size:9pt">
</xp:label>
<xp:label value="Greeting" id="label4"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="Lotusphere Admin" id="label5"
style="color:rgb(14,78,112);font-size:10pt;font-weight:bold">
</xp:label>
<xp:label value="Lotusphere" id="label6"
style="font-size:12pt;color:rgb(14,78,112);font-weight:bold">
</xp:label>
<xp:label value="Notes" id="label7"
style="color:rgb(150,209,241);font-weight:bold;font-size:9pt">
</xp:label>
<xp:label value="Overlay" id="label8"
style="font-size:9pt;color:rgb(150,209,241);font-weight:bold">
</xp:label>
<xp:label value="Schedule" id="label9"
style="color:rgb(14,78,112);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="Scheduler" id="label10"
style="font-size:10pt;color:rgb(14,78,112);font-weight:bold">
</xp:label>
<xp:label value="Session" id="label11"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="Sessions" id="label12"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="Tag" id="label13"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="help" id="label14"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="iNotes" id="label15"
style="font-weight:bold;color:rgb(14,78,112);font-size:9pt">
</xp:label>
<xp:label value="iPhone" id="label16"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="issl" id="label17"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="lotus" id="label18"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="solutions" id="label19"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="development" id="label20"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
<xp:label value="lab" id="label21"
style="color:rgb(150,209,241);font-size:9pt;font-weight:bold">
</xp:label>
</xp:panel>
</xp:view>
Here is how it looks at design time
Scriptlet Tags
You can see that design is built using no more than a section control with some text in it, followed by an image for the slider and a series of styled labels for the tags. This works fine, but it is quite tedious having to create all those labels manually. This can be overcome by using embedded JavaScript. The custom visualization framework has a JavaScript preprocessor, which allows JavaScript embedded in the custom markup to be executed before the markup is rendered in the XPages/Custom Control editor. The preprocessor only allows JavaScript to be used, it does not support the use of any Java code.
JavaScript can be embedded by surrounding it with scriptlet tags (<%.....%>). When working with scriplet tags, it is always best to work in the source editor of the temporary Custom Control. If you attempt to add scriptlet tags to the design editor, they will look fine at design time, but are being encoded into the source editor. So <% in the design editor is being turned into <% in the source editor for example. This will not work as custom markup when you copy and paste the source of the temporary Custom Control later on.
What that means for us in this case, is that instead of creating 21 individual labels, we can just create one and wrap it in a JavaScript for loop so that it is repeated 21 times. Like this.
<%for (var x=0;x<21;x++){%>
<xp:label value="Label"id="label23"></xp:label>
<%}%>
Labels are not required to have ids, but many other controls are, and those ids must be unique. And remember, the markup to be visualized must be valid after the JavaScript has been executed. So for many controls, in your custom visualization code, you will have to generate those unique ids yourself. For the most part it is probably best to just use the incrementing variable in the for loop as the id. To accomplish this you can use the expression scriptlet tags (<%=...%> to add the result of a JavaScript expression to the custom markup. So in this case to add a unique id to all the labels in our visualization we could do this
<%for (var x=0;x<21;x++){%>
<xp:label value="Label"id=<%='Label'+x%>"></xp:label>
<%}%>
As you could clearly see the previous examples did not deal with the cases of each of the labels having a different value or style attribute. But using the same techniques, here is some code that creates a comparable visualization.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:panel
style="height:191.0px;width:176.0px;border-color:rgb(255,255,255);background-color:rgb(248,248,248)">
<xp:section id="section1"
style="border-color:rgb(255,255,255)">
      
<xp:span style="font-weight:bold">Top 25 Tags</xp:span>
</xp:section>
<xp:image url="/ccTagClould_slider.JPG" id="image1"
style="width:175.0px">
</xp:image>
<%
//the array of labels to use
var labelArray = ["Agenda","Cloud","Communities","Connections",
"Greeting","Lotusphere Admin","Lotusphere","Notes","Overlay","Schedule",
"Scheduler","Session","Sessions","Tag","help","iNotes","iPhone","issl",
"lotus","solutions","development","lab"];
//This function will randomly return one of the four styles uses in the visualization
function getRandomStyle(){
var rand = Math.floor(Math.random()*4);
if(rand==0){
return("font-size:9pt;color:rgb(150,209,241);font-weight:bold");
}
if(rand==1){
return("font-size:9pt;color:rgb(14,78,112);font-weight:bold");
}
if(rand==2){
return("font-size:10pt;color:rgb(14,78,112);font-weight:bold");
}
if(rand==3){
return("font-size:12pt;color:rgb(14,78,112);font-weight:bold");
}
}
for (var x=0;x<labelArray.length;x++){%>
<xp:label value="<%=labelArray[x]%>" id="<%='Label'+x%>" style="<%=getRandomStyle()%>"></xp:label>
<%}%>
</xp:panel>
</xp:view>
Note: In Domino Designer v8.5.2 you may get a validation error saying "Invalid control id" when you add this source to the Design Definition panel of a Custom Control.
This is being caused by the computed id for the labels ( id="<%='Label'+x%>" ). It is safe to ignore these error in this case if you see it. It is being caused by a bug in Designer (SPR# GOKE87ES2J).
At Design time, given this custom markup, the ccTagCloud Custom Control would render like this:
Accessing Custom Properties
The tagCloud control needs to be bound to a view when it is added to an XPage/Custom Control, using the viewName custom property found on the "Custom Properties" property panel for the control ( The viewName custom property is specified in the "Property Definition" property panel for the ccTagCloud Custom Control). So it is possible to have more than one tagCloud on an XPage/Custom Control that are bound to different views. As you can see in the ccTagCloudGroup Custom Control, also from the "Discussion - Notes & Web" template that ships with Domino Designer. For development purposes, it is important to know which view a tagCloud is bound to. To be able to do this, we will need access to the attributes on the ccTagCloud Custom Control. Access to the custom properties on a Custom Control are available using "this." notation.
So for example. In the ccTagCloud custom markup, we could add
<xp:panel>
tagCloud for <%=this.viewName %>
</xp:panel>
We could also use a label control for this, or even <p> tags etc... Giving us a final Custom Markup of
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:panel
style="height:191.0px;width:176.0px;border-color:rgb(255,255,255);background-color:rgb(248,248,248)">
<xp:section id="section1"
style="border-color:rgb(255,255,255)">
      
<xp:span style="font-weight:bold">Top 25 Tags</xp:span>
</xp:section>
<xp:image url="/ccTagClould_slider.JPG" id="image1"
style="width:175.0px">
</xp:image>
<%
//the array of labels to use
var labelArray = ["Agenda","Cloud","Communities","Connections",
"Greeting","Lotusphere Admin","Lotusphere","Notes","Overlay","Schedule",
"Scheduler","Session","Sessions","Tag","help","iNotes","iPhone","issl",
"lotus","solutions","development","lab"];
//This function will randomly return one of the four styles uses in the visualization
function getRandomStyle(){
var rand = Math.floor(Math.random()*4);
if(rand==0){
return("font-size:9pt;color:rgb(150,209,241);font-weight:bold");
}
if(rand==1){
return("font-size:9pt;color:rgb(14,78,112);font-weight:bold");
}
if(rand==2){
return("font-size:10pt;color:rgb(14,78,112);font-weight:bold");
}
if(rand==3){
return("font-size:12pt;color:rgb(14,78,112);font-weight:bold");
}
}
for (var x=0;x<labelArray.length;x++){%>
<xp:label value="<%=labelArray[x]%>" id="<%='Label'+x%>" style="<%=getRandomStyle()%>"></xp:label>
<%}%>
<xp:panel>
tagCloud for <%=this.viewName %>
</xp:panel>
</xp:panel>
</xp:view>
Note: In Domino Designer v8.5.2 you may see a NullPointerException
This is being caused by <%=this.viewName %>. It is safe to ignore these error in this case if you see it. It is being caused by a bug in Designer (SPR# MKEE86XGY5).
This will display the value of the viewName attribute below the tagCloud visualization. Here is how it would display on an XPage/Custom Control where the ccTagCloud control is bound to a view named view1
Facets, Callbacks and Editable Areas
For Custom Controls that contain "Editable Areas", it is important that we enable users to create custom visualizations that still allow those editable areas to be used.
For those of you unfamiliar with the term, an "Editable Area" is a control that can be placed on a Custom Control that allows users of that Custom Control to contribute their own content to it. It essentially provides a area within a Custom Control that a user can drop a control or other controls to once the Custom Control has been placed on an XPage/Custom Control. The control(s) will render in the location of the Editable Area in the Custom Control. You may see these controls referred to as "Editable Areas", "Callbacks" or "Facets". "Editable Area" is the title given to the control in the Controls Palette. When you drop an "Editable Area" onto a Custom Control, it creates a callback element (xp:callback tag) in the source of the page. A facet is an area within a control that has the ability to render another control inside of it. You may see references to facets unrelated to Custom Controls as some Core/Container Controls also use them. The xp:callback tag represents a facet in a Custom Control. There are two different types of facets. Those that have a facetName and those that don't. The facetName is specified as an attribute on the xp:callback control.
Facets that have a facetName are by far the most common type. They allow one control only to be added to them. A simple example of using a facet is the Data Table control. If you drop a Data Table to an XPage/Custom Control, you will see two columns in the dataTable, each with a header, a body and a footer. The header and the footer are actually facet areas. The header has the facetName "header" and the footer has the facetName "footer". The body is a standard content area, so any controls dropped to the body will simply become children of that column element.
If you add some text to the header, body and footer, will see how the source changes. You should be left with something like this:
<xp:dataTable id="dataTable1" rows="30">
<xp:column id="column1">
I am the body
<xp:this.facets>
<xp:span xp:key="footer">I am a footer</xp:span>
<xp:span xp:key="header">I am a header</xp:span>
</xp:this.facets></xp:column>
<xp:column id="column2"></xp:column>
</xp:dataTable>
It should look like this at design time
Looking at the first column, you can see that the text in the body, is just a child of the column tag. Elements that are to be placed in a facet, must have an xp:key attribute set on them, where the value of the xp:key attribute matches the facetName of the facet it is to appear in. So in this case for the header the xp:key attribute is set to "header" and for the footer it is set to "footer". It does not matter what order the elements are added, provided that their xp:key attribute matches the facetName of the facet, that is where they will appear both at design time and run time. Any control that specifies an xp:key attribute must be wrapped in an <xp:this.facets> tag to tell the parent control that it is being put in a facet.
For Custom Controls, a facet is far more easily recognizable. Take the placeBar Custom Control for example (From the "Discussion - Notes & Web" template that ships with Domino Designer). It contains an "Editable Area" with a facetName of "Buttons". If you add the placeBar Custom Control to an XPage/Custom Control it should render like this:
You can see the facet clearly renders as a green circle with the facetName beside it. An end user can drop any single control to that facet area. Of course, if they chose to drop a container control, like a Panel, they can then add further controls as children of that.
Facets that do not have a facetName specified exist only for Custom Controls and Native Controls (Note: They can only be used for Visualization purposes with Native Controls. xp:callback controls with no facet_name will not be used at runtime for Native Controls). They allow a user to drop multiple controls into them. Controls that will then act as children of that Custom Control/Native Control. So if you were to add two "Editable Areas" to a Custom Control, neither of which had facetNames specified, any control that is later added to one of those facets, would ultimately display in both (The same is true if you had two "Editable Area" controls with the same facetName specified. Anything designated to display in one, would display in both!). Controls added to facets that do not specify a facetName, do not need an xp:key attribute, and as such do not need to be wrapped in a <this.facets> tag. Here is how the placeBar Custom Control would render if it did not have a facetName specified on its callback control.
To enable facets to work with custom visualizations, we allow custom markup to contain callback controls. Provided the custom markup contains a callback control that matches the one from the original Custom Control markup, users should be able to interact with it that same way as if no custom markup was provided. Lets take an example of building a very simple custom visualization for the placeBar Custom Control. Again we start with a temporary Custom Control. Facets are the reason we start from a Custom Control and not an XPage. Editable Areas only appear on the palette when we are editing Custom Controls.
So for the placeBar visualization, we can just drop a label and change it to say "Place Bar Title" and then drop an Editable Area and set its facetName to be Buttons.
You way want to copy and paste the source of the callback control from the actual Custom Control markup to the temporary Custom Control, to be sure it matches exactly. The source should look like this.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:label value="Place Bar Title" id="label1"></xp:label>
<xp:br></xp:br>
<xp:callback facetName="Buttons" id="callback1"></xp:callback>
</xp:view>
Using that markup for the custom visualization of the placeBar Custom Control, it will now display like this at design time
You can see the facet has rendered exactly as it did before and will work in exactly the same way as it did before.
It is very important that the source of the callback controls in the custom visualization match exactly their source in the original Custom Control markup. The custom markup will allow you to add any facetName you wish, or you could add facets that do not have facetNames. Those facets will look and act just like any facet that were really in the Custom Control, but if the xp:key attribute a user adds to an element in the facet does not match the real facetName, or no xp:key attribute is specified, the element the user added will not render at runtime. Similarly, if a user specifies an xp:key attribute on an element and the facet has no facetName, the element will not render at runtime.
Things to remember
-Don't add scriplet tags to the design editor. They will be encoded in the source editor, which is not valid as custom markup.
-Some controls need to have unique ids. Make sure your custom markup will have unique ids after any JavaScript has executed.
-Always ensure the facets in any custom visualization match exactly the facets in the original Custom Control markup. Using facets in Custom Controls rendering that don't exist in the Custom Control can cause embedded control not to render at runtime.
One last caveat
If your Custom Control is going to be used across multiple databases, be sure not to use images that may not be resources in other dbs. Any images that cannot be found will render as an unknown image. Similarly if you are using other Custom Controls or including XPages in a custom visualization, ensure they will be available to all end users as this may break the rendering. Users will see this error if any tags in the custom visualization cannot be resolved (This includes, using tag libraries an end user may not have available to them, or including Custom Controls that a user may not have available to them).
Any included XPage will appear blank if it cannot be resolved.
Native Controls
Almost everything that applied to Custom Controls also applies to Native Controls. The major different is how the custom visualization for an Native Control is specified. There is no Design Definition panel for an Native Control, so the custom markup must be specified in the "Component Definition" for the Control in the xsp-config file for your Control Library.
If you have been working with Native Controls, then for the purposes of this document, we are assuming that you already know how to implement and include a Native Control Library.
See http://www-10.lotus.com/ldd/ddwiki.nsf/dx/Master_Table_of_Contents_for_XPages_Extensibility_APIs_Developer_Guide
Specifying the Custom visualization
The markup for the custom visualization of an Native Control, needs to be specified with <render-markup> tags in the xsp-config file for your Control Library.
Firstly, you will need to locate the xsp-config file that contains the Component Definition for the Control you would like to add a custom visualization to. Once you have the Component Definition, you will need to add <render-markup></render-markup> tags like this.
0
Lets take the example of a simple custom visualization
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:label value="Label" id="label1"></xp:label>
</xp:view>
You cannot just add this markup as it is to the <render-markup></render-markup> tags, as the tags in the custom visualization would act as child tags of the render markup, invalidating the xsp-config file. The custom markup must be encoded first. All that really means is that all '&' symbols need to be replaced by "&", all '<' symbols need to be replaced by "<" and all '>' symbols need to be replaced by ">". So given the custom markup above, your component definition would need to look like this:
<component>
<component-extension>
<designer-extension>
<render-markup>
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:label value="Label" id="label1"></xp:label>
</xp:view>
</render-markup>
</designer-extension>
</component-extension>
</component>
You could use "Find/Replace All" to generate this from the custom markup, but that can be difficult to maintain and there is an easier way. This is the second reason it is better to use temporary custom controls to build custom visualizations than a temporary XPage or a text file etc... Simply design the temporary custom controls as you would have done before.
Switch to the source tab, copy the entire contents of the page and paste it into the Design Definition property panel.
In the same way that you have a xsp-config file for you Native Control Library, every custom control has to have its own xsp-config file also. Once you save your temporary custom control, the encoded contents of the Design Definition panel are saved into the xsp-config file for that Custom Control. You can copy and paste the <render-markup></render-markup> tags directly out of the temporary custom controls xsp-config file and into your Native Controls Component Definition. The xsp-config files for the custom controls in an Application, do not show up in the Applications Navigator, so you will need to use another view to access them. The easiest view that I've found to use is the General -> Navigator view. To open it, go to Window -> Show Eclipse Views -> Other... and select the General -> Navigator view.
Open the nsf in the General Navigator that contains your custom control, and expand the CustomControls folder. You will find an xsp and xsp-config file for each custom controls in your application. Open the xsp-config file for your temporary custom control. There you will find the <render-markup></render-markup> tags complete with the encoded contents that you added to the Design Definition property panel, ready to be copy and pasted to the Component Definition of your native control.
Using Images in Native Control Visualizations
Normally when we use images on XPages/Custom Controls, those images must be in the Resources/Images folder within the Application. When developing custom visualizations for native controls, that contain images, you cannot expect an end users Application to contain those images.
So for native Controls, we assume any images that are being referenced are coming from within the jar that contain the control. However any image that are referenced from within the jar must be on the classpath. The easiest way to accomplish this is to create an icons folder within the 'src' directory of your native controls plugin and store any images there.
These images can then be easily referenced. For example a custom visualization that just adds an image to the page would have a render-markup like this
<render-markup><?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:image url="/icons/testImage.JPG" id="image1"></xp:image>
</xp:view>
</render-markup>
Things to remember
Be careful of using native controls in custom visualizations that are from other native control libraries. Any end users will have to have access to every control used, or else the visualizations will break. This also holds true for any new controls that are added to the Controls Palette in Designer in future releases. Your native control visualizations will only be compatible with Designer builds that contain those new controls.
|