Friday, September 30, 2011

Thinking about jQuery-UI. Rendering buttons as is with Tapestry5.

Have you ever use a nice js library called jQuery-UI on your applications? Yes, it is realy easy to make some draft markup and then create all needed widgets using this library. For example:


This example will render button, submit and link and then will create ui-button widgets from it using js. As result we will see three pretty-styled buttons. But is everything clear in this example? Let's make some changes that will emulate slow page rendering.


As result we have three unstyled buttons that then flashes to jquery-ui styles(look). Is it so pretty now? And do you think such behavior is correct or you agree with opinion that all page elements should be rendered as is from the beginning? And if you have chosen the second variant let's continue.

To prevent content flashing we should render all elements as if they was generated by jquey scripts with all needed stuff for this. So, let's look on generated by jquery button styles. It's end markup looks like this:


This is not all variants of button markup but if we will research it deeper we can mark next things:
  • All visible components have styles like 'ui-button ui-widget ui-state-default ui-corner-all'
  • All such components have style that describes their type, e.g. 'ui-button-text-only', 'ui-button-text-icons', etc.
  • All such components have inner span for their text that have style 'ui-button-text'
  • All such components if they have primary icon have inner span for it that have style 'ui-button-icon-primary ui-icon'
  • All such components if they have secondary icon have inner span for it that have style 'ui-button-icon-secondary ui-icon'
  • Submit button doesn't have any inner content
  • Checkboxes and radios are hidden by style 'ui-helper-hidden-accessible' and all previous rules are applyed to their labels
So, our goal is to apply all this rules while rendering markup for jquery buttons. As I use Tapestry5 as front-end framework for my applications I will use examples within it, but a good programmer can do the same using different framework or programming language.
The next example demonsrates the easiest way to implement this:


This way is easy, but it can be improved to not duplicate all this stuff for every button and tapestry features can help us to do this. There is a nice mechanism in t5 that intercepts elements rendering called MarkupWriterListener. We just need to implement our custom listener and enable it before needed component will be rendered. We can place this logic in t5 component or mixin. My variant of such component:


So we wiil just need to wrap our links, buttons, etc... with this component and it will do the other job for us:


Ok, we have rendered all our components with all needed stuff for correct styling. But what will happen when we call $(".ui-button").button()? It is awful, all styles are broken.
  • Icons was removed
  • Label was wrapped by span twice
  • Checkboxes and radios was created from its labels
To solve this, we just need to create buttons "correctly". I have created script for this:


The whole example code are placed here.
The live demo.

No comments:

Post a Comment