329 Lotus blogs updated hourly. Who will post next? Home | Downloads | Events | Jobs | Twitter | Bookmarks | Pods | Blogs | Search | myPL | About 
 
Latest 7 Posts
locating XPage components with XspQuery
Sun, Apr 14th 2013 247
your how is not your what
Wed, Apr 3rd 2013 357
Developer2013 and IamLUG
Mon, Apr 1st 2013 196
my new favorite quote
Sat, Mar 23rd 2013 328
Taking the scary out of Java in XPages: fixing the API
Thu, Mar 21st 2013 236
Taking the scary out of Java in XPages: knowing the entry points
Sat, Mar 2nd 2013 408
Taking the scary out of Java in XPages: Prologue
Tue, Feb 26th 2013 349
Top 10
I have seen the future, and it is phabulous
Sat, Dec 8th 2012 677
SSJS is a crutch
Fri, Feb 22nd 2013 672
the next step in the journey
Wed, Jan 9th 2013 646
org.openntf.xsp.extlib
Mon, Jan 21st 2013 533
Needle in the Stack Part 2: talk to data, not to components
Thu, Jan 17th 2013 432
Passthru vs. component - my perspective
Sat, Feb 16th 2013 416
Taking the scary out of Java in XPages: knowing the entry points
Sat, Mar 2nd 2013 408
your how is not your what
Wed, Apr 3rd 2013 357
Taking the scary out of Java in XPages: Prologue
Tue, Feb 26th 2013 349
fasten your seat belt, Dorothy
Thu, Oct 11th 2012 328


extending XspInputText to add placeholder support
Tim Tripcony    

Last week, Jake called attention to the usability flaw in web forms that specify a default value for fields but clear that value on focus without checking first to see if the field's value has since been changed from the default. He included a code example demonstrating a way to perform such a check, ensuring that a user's input will not be programmatically deleted if they later return to the same field.

A couple readers proposed an alternate approach: using the "placeholder" attribute as described in the HTML5 specification. Browsers that support this attribute display the value of the attribute within the field when the field has no value - even if it used to - but at a lower opacity. Hence, the user is given a visual indication that this text provides a hint for what to enter in the field, not a value that is already assigned to the field. In other words, the behavior is quite similar to the way the Lotus Notes client renders the "Field Hint" property for a field on a Form element: the only significant difference is that, upon exiting a Notes field, the hint does not reappear, even if the field is still (or again) empty; as previously mentioned, browsers that support the placeholder attribute will again display its value when the focus leaves the field if that field has no value. Browsers that do not support this attribute simply ignore it, so users of those browsers will not see the hint, but will also not encounter errors. This is a great example of "progressive enhancement": users of older or less standards-compliant browsers can still use all of the site's functionality, but as those users upgrade / replace their browser, they have a richer experience without any additional effort on your part.

Yesterday, Tommy posted a demonstration of using hidden inputs to glean the values of "passthru" input tags, which allows him to specify HTML5 attributes on the passthru tags. He created a custom control that allows this technique to be reusable.

The remainder of this post will demonstrate how to create an extension to the native Edit Box component to add support for HTML5 attributes like placeholder.

The good news, for those of you who are currently unable to upgrade to 8.5.2 or to install component extension libraries (or both), is that this technique requires neither: this extension can be implemented in 8.5.1 (in all likelihood, even 8.5.0), and the instructions that follow assume you will be implementing them in "single-NSF" mode. If you'd rather deploy such an extension as part of a component library, IBM has included documentation for how to bundle the files you're about to see into such a library in the Extension Library project on OpenNTF.

Step 1: defining the component

Every extension component is defined by, at a minimum, one Java class that specifies the properties and methods of the component. Let's take a look at such a class:

  1. package com.timtripcony.xsp.component.html5;
  2.  
  3. import javax.faces.context.FacesContext;
  4. import javax.faces.el.ValueBinding;
  5. import com.ibm.xsp.component.xp.XspInputText;
  6.  
  7. public class Html5InputText extends XspInputText {
  8.  private String _placeHolder;
  9.  
  10.  public Html5InputText() {
  11.  
  12.  }
  13.  
  14.  public String getPlaceholder() {
  15.   if (null != this._placeHolder) {
  16.    return this._placeHolder;
  17.   }
  18.   ValueBinding _vb = getValueBinding("placeholder");
  19.   if (_vb != null) {
  20.    return (java.lang.String) _vb.getValue(getFacesContext());
  21.   } else {
  22.    return null;
  23.   }
  24.  }
  25.  
  26.  public void setPlaceholder( String _placeHolder) {
  27.   this._placeHolder = _placeHolder;
  28.  }
  29.  
  30.  public String getRendererType() {
  31.   return "com.timtripcony.xsp.Html5Input";
  32.  }
  33.  
  34.  public void restoreState(FacesContext _context, Object _state) {
  35.   Object _values[] = (Object[]) _state;
  36.   super.restoreState(_context, _values[0]);
  37.   this._placeHolder = (String) _values[1];
  38.  }
  39.  
  40.  public Object saveState(FacesContext _context) {
  41.   Object _values[] = new Object[2];
  42.   _values[0] = super.saveState(_context);
  43.   _values[1] = getPlaceholder();
  44.   return _values;
  45.  }
  46.  
  47. }
  48.  


As you can see, our class declaration states that we're extending XspInputText. This is the Java class associated with the native Edit Box component. Hence, by extending that class, we're declaring that we want something that inherits all of its functionality but will have certain additional characteristics of its own.

In this example, we're really just looking to add one additional attribute: placeholder. So we declare a private String to store it, and a "getter" and "setter" method to, respectively, change and retrieve a value for the attribute. The syntax of the getter may look a bit odd, but this follows the exact syntax IBM uses whenever they define a getter for a component attribute. What this syntax essentially does is allows the attribute to support both dynamic and static values; in the case of placeholder, this will allow the attribute to be evaluated correctly whether we use EL or just type in a value.

In addition to providing a getter and setter, we want the value of the attribute to be maintained across requests (for example, if a partial refresh event targets this component or one that contains it). We do this by overriding the saveState and restoreState methods of the parent class. In saveState, we create a generic Object array, call the saveState method as it is defined in the parent class and store the result in the first index of the array, and then store any additional properties we want to maintain in additional indices... since we're only adding one additional property, we only need one additional index. In restoreState, we reverse the process: we pass the first index of the restored array to the parent method, then retrieve the placeholder from the second index. In deep component hierarchies, then, the serialized version of each component becomes a nested array of arrays, which seems complicated to maintain, except that in each class we only have to worry about the properties defined at that level. This state serialization concept is what allows the XPage runtime (as of 8.5.2) flexibility regarding the performance priorities for each application: speed, scalability, or a "happy medium".

One last note about the component class: strictly speaking, the rendererType attribute should be handled in precisely the same way as the placeholder (i.e. private String, getter/setter, and state management), but as an explanation of providing support for multiple renderers is best left for another day, this example simply hardcodes a single renderer ID.

Step 2: defining a renderer

Now that we've defined what this component is, we'll define what it should look like.

  1. package com.timtripcony.xsp.renderkit.html_basic;
  2.  
  3. import java.io.IOException;
  4. import javax.faces.component.UIInput;
  5. import javax.faces.context.FacesContext;
  6. import javax.faces.context.ResponseWriter;
  7. import com.ibm.commons.util.StringUtil;
  8. import com.ibm.xsp.renderkit.html_basic.InputTextRenderer;
  9. import com.timtripcony.xsp.component.html5.Html5InputText;
  10.  
  11. public class Html5InputTextRenderer extends InputTextRenderer {
  12.  
  13.  protected void writeTagHtmlAttributes(FacesContext context,
  14.    UIInput component, ResponseWriter writer, String inputValue)
  15.    throws IOException {
  16.   super.writeTagHtmlAttributes(context, component, writer, inputValue);
  17.   Html5InputText html5Component = (Html5InputText) component;
  18.   String placeHolder = html5Component.getPlaceholder();
  19.   if (StringUtil.isNotEmpty(placeHolder)) {
  20.    writer.writeAttribute("placeholder", placeHolder, "placeholder");
  21.   }
  22.  }
  23.  
  24. }


This bit is even easier than defining the component itself. As before, there's already a class that does almost everything we want, so we just extend it to add the new functionality. In this case, we're extending InputTextRenderer, which already includes all of the logic for turning a standard Edit Box into HTML: writing out attributes, binding events, and so forth. Hence, all we need to do is override the writeTagHtmlAttributes method. We start by calling the parent method, which writes all of the standard attributes. Then we determine whether the placeholder attribute has a value and, if it does, write that value to the tag being rendered. That's it.

Step 3: telling Designer the component exists

Finally, we need to alert Designer (and the XPage runtime) to the existence of our new control. This is done by creating one XML file and modifying another.

Create a file with a .xsp-config extension. The actual filename is arbitrary; as long as the file extension is correct, the filename does not matter. Furthermore, you can theoretically place this file anywhere within the NSF folder structure and Designer will find it. However, I recommend placing these files in /WebContent/WEB-INF. Since the file we'll soon be modifying is already there, it just makes things easier to keep track of.

Since I'm bumping up against the 32KB summary limit, I've posted the example xsp-config file as a separate page. The namespace URI and prefix are, again, arbitrary, as long as the relationship between the two is maintained. For instance, you could actually add your own components to the xp or xc namespace, as long as you specify the same URI that IBM does, but please, please don't. That would ultimately just cause confusion. In this example, I'm defining "html5" as the prefix, so I thought it fitting to use the URL of the HTML5 spec as the namespace URI. Hopefully, most of the remaining contents of the file are self-explanatory, but I specifically want to call attention to the base-component-type tag. This tells Designer that this component supports all of the properties an Edit Box supports, in addition to the new property it defines. There are all manner of additional items that can be defined in this file, but, again... another day.

Once we've saved this file, Designer immediately knows this component exists, so we can add one to our page; once we do, and select it, the All Properties pane will allow us to set a value for the placeholder attribute. In the Source pane, it will look a little something like this:

<html5:inputText id="myInputText" placeholder="Hello World!"></html5:inputText>


Finally, open up the faces-config.xml file in /WebContent/WEB-INF, and add the following lines:

<render-kit>
 <renderer>
  <component-family>javax.faces.Input</component-family>
  <renderer-type>com.timtripcony.xsp.Html5Input</renderer-type>
  <renderer-class>com.timtripcony.xsp.renderkit.html_basic.Html5InputTextRenderer</renderer-class>
 </renderer>
</render-kit>


This associates any component with the rendererType we hardcoded in Step 1 with the renderer we defined in Step 2. Whenever the runtime needs to render the component we've defined, it now knows to use our renderer.

So that's all there is to it. I realize this probably seems like a lot of work just to get an XPage to add a few additional characters to the HTML output, but once you've gotten used to defining components, creating a new one only takes a few minutes. Furthermore, when you want to add properties to a component you've already defined, all you have to do is tweak the corresponding files. For instance, you could take this example component and add support for additional attributes with just a few lines of code. Given the alternatives, such as waiting for IBM to add the features you want in a subsequent release, or simply settling for what has already shipped, it's well worth the extra effort... especially when you start writing components that don't even exist out of the box.



---------------------
http://xmage.gbs.com/blog.nsf/d6plinks/TTRY-8BH4ZZ
Nov 24, 2010
203 hits



Recent Blog Posts
247


locating XPage components with XspQuery
Sun, Apr 14th 2013 12:00a   Tim Tripcony
Several years ago, I wrote a utility Java class designed to make it easy to search for components within the current XPage instance based on various criteria. I've found it enormously useful, and, apparently, so has Keith Strickland, because he added it to org.openntf.xsp.extlib, complete with a few refinements. As an example of how you might use this, examine the following line of code: List requiredFields = new XspQuery() .addInstanceOf(UIInput.class) .addEquals("required", true) .loc [read] Keywords: ldd lotus dojo java javascript openntf oracle server
357


your how is not your what
Wed, Apr 3rd 2013 11:36a   Tim Tripcony
I've noticed a pattern emerging when I'm asked for help with XPages. Here's a representative conversation: "I'm trying to do [X] and it's not working. How can I do that?" "What are you trying to accomplish?" "I already told you. I'm trying to do [X]." "No, that's how you're trying to do it. What are you trying to do?" For example, replace "[X]" with "reach into a repeat control from outside it" (since this has become the most frequent topic I'm asked about [read] Keywords: xpages application
196


Developer2013 and IamLUG
Mon, Apr 1st 2013 7:33a   Tim Tripcony
I will be presenting at two upcoming conferences, Developer2013 and IamLUG. Developer2013 will be held at the MGM Grand in Las Vegas April 30 to May 2, and is organized by THE VIEW. I will be presenting the following sessions: Doing more with less code in XPages "Work smarter, not harder." We're all expected to, but are rarely told how. In XPages, however, we have many opportunities to do precisely that. This session will equip you with techniques for writing less code to achieve th [read] Keywords: domino lotus notes notes client xpages application applications desktop development facebook interface laptop linkedin mobile twitter
328


my new favorite quote
Sat, Mar 23rd 2013 5:20p   Tim Tripcony
"We go about our daily lives understanding almost nothing of the world. We give little thought to the machinery that generates the sunlight that makes life possible, to the gravity that glues us to an earth that would otherwise send us spinning off into space, or the atoms of which we are made and on whose stability we fundamentally depend. Except for children (who don’t know enough not to ask the important questions), few of us spend much time wondering why nature is the way it is; where the [read] Keywords: wiki
236


Taking the scary out of Java in XPages: fixing the API
Thu, Mar 21st 2013 4:00a   Tim Tripcony
Suppose you had a motivation to learn a new spoken language. As an example, let's imagine that you live in the U.S., but your job requires you to occasionally visit Paris, so you've decided to learn French. But you're not planning to move there, just spend a week there every couple months. So you don't want to learn the entire language, just enough to facilitate basic interaction whenever you're there. So you briefly considered taking a semester-long course at a local community college, but [read] Keywords: domino ibm lotus lotusscript notes xpages application best practice community css database google java openntf oracle twitter wiki
408


Taking the scary out of Java in XPages: knowing the entry points
Sat, Mar 2nd 2013 3:02a   Tim Tripcony
Before we dive in to this first topic, I should mention Declan's series, "XPage Java Roots". Declan has been shifting more of his code to Java, so just as he did with his epic "Learning XPages" series, where he documented his initial experiences with XPages itself, he is now documenting his experience of learning how to take advantage of Java in XPage development. It's a safe bet that this series will be a very useful reference, so whether or not my own perspective on this topic prov [read] Keywords: admin agent domino ibm lotus lotusscript notes script library xpages application applications database development eclipse interface java javascript oracle server wiki xml




349


Taking the scary out of Java in XPages: Prologue
Tue, Feb 26th 2013 9:50p   Tim Tripcony
The discussion following my last post made stark the need for greater availability of information that makes the nature of Java more accessible to Domino developers. Credit for the title of this post goes to Declan, who is considering writing a series of blog posts on this topic. I will be doing the same; hopefully there will be a fair amount of duplication. As David Leedy is fond of stating, it's a good thing when several people share the same information, because that makes it easier for the [read] Keywords: domino xpages application java
672


SSJS is a crutch
Fri, Feb 22nd 2013 10:50p   Tim Tripcony
I've been debating for quite a while whether I should write this post. It obviously makes a potentially controversial statement. A fellow developer who knew I was drafting it put my hesitance into perspective: "you really want to be that guy?" This was my response: I want to be the guy who saves people pain. But sometimes to do that, you have to tell your friend if she wants to stop being punched in the face, she needs to leave the guy who keeps punching her in the face. This post is ju [read] Keywords: agent domino formula language ibm lotus lotusscript notes xpages applications development java javascript openntf wiki
416


Passthru vs. component - my perspective
Sat, Feb 16th 2013 9:40p   Tim Tripcony
Paul Withers posted a thorough article explaining the differences between namespaced XPage components (e.g. ) and their corresponding passthru elements (e.g. ), providing numerous examples of what actually happens when these objects are constructed. I've always heard (and often repeated) that passthru elements are more efficiently processed than their namespaced equivalents, so Paul's post inspired me to offer my own perspective. Simply put, there's practically no difference... but there a [read] Keywords: acl domino xpages application development properties security
533


org.openntf.xsp.extlib
Mon, Jan 21st 2013 5:20a   Tim Tripcony
About 18 months ago, I created an OpenNTF project called Community Control Library. The fundamental reason for creating the project was my belief that the single factor keeping the Domino community from realizing the true potential of the platform is the assumption that the XPages Extension Library is the extension library, not an extension library. Let's briefly revisit its history: IBM starts an internal project, code named "Porus" (in reference to the Greek / Roman god of plenty), inte [read] Keywords: domino ibm notes policies xpages application applications best practice community development openntf wiki




Created and Maintained by Yancy Lent - About - Blog Submission - Suggestions - Change Log - Blog Widget - Advertising - Mobile Edition