10 Replies Latest reply on Jul 18, 2012 3:02 AM by lfryc

    Bootstrap plugin architecture

    lfryc

      Hi guys,

       

      I would like to discuss the plugin architecture for new component suites.

       

      We have started prototyping JavaScript Event Bridge (https://issues.jboss.org/browse/RFSBOX-9), but it would be nice to brain-storm several concerns before diving further.

       

      These are the high-level concerns what we have to have in mind:

       

      • component initialization
      • component destroy
      • AJAX update
      • calling user function
      • client/server state synchronization

       

       

      Additionally, we need to consider what model we will use as the base:

       

      • RichFaces - Event, BaseComponent
      • jQuery UI Widget Factory
      • any other?
        • 1. Re: Bootstrap plugin architecture
          lfryc

          Okay, let's start with brain-storming, why we actually need components based on widget model.

           

          RichFaces is highly based on JSF AJAX, which basically serves as engine which replaces parts of the DOM (partial-update).

          That brings us to the lifecycle of the component - the component is initialized and destroyed each time it is replaced in the DOM.

           

          Some of bootstrap components are CSS-only, which means we can just replace the DOM and don't need to care about lifecycle of component.

          But when you start to tie custom events to the component, the component turns into stateful widget and in that case you need to manage its lifecycle.

           

          ----

           

          Sadly, lot of components requires to hook into DOM events to provide high-level functionality or allow user-defined callbacks.

          • 2. Re: Bootstrap plugin architecture
            lfryc

            #Idea 1 - decoupled event registration

            --------------------------------------------------

             

            Bootstrap components aren't stateful - their eventing model works on binding event handlers to body element,  e.g.:

             

            $('body').on('click.collapse.data-api', '[data-toggle=collapse]'

             

            That's why it's enough to attach data-* attribute to make the component react on DOM events.

             

            ----

             

            Additionally, we can do the same when listening for high-level (custom) events like hide from collapse's API:

             

            $(body).on('shown', function() {...})
            

             

            To take this approach further, we can add event bridge, which would listen for all bootstrap's custom events and call the appropriate event handlers, like:

             

            <a class="accordion-toggle" onshown="behavior_or_user_provided_event_handler" />
            

             

            This could actually lead into overhead with eventing.

             

            ----

             

            The second option is to register event callbacks during generic boorstrap component initialization:

             

            <a class="accordion-toggle bs-event" onshown="behavior_or_user_provided_event_handler" />
            

             

            and during initialization, we can register appropriate listener to specific element with class bs-event

            then when destroying, we can unregister it.

            • 3. Re: Bootstrap plugin architecture
              lfryc

              #Idea 2 - component initialization

              ---------------------------------------------

               

              We have discussed component initialization on-dom-ready. We can use JavaScriptService which is similar to <h:outputScript target="body" /> - it renders the script on the end of the body - and it renders it just once. This approach follows Yahoo's web app performance recommendations.

               

              We could initialize all components in one pass through the DOM:

               

              $.each(".bs-event", function() {
                   ....
              });
              

               

              #Idea 3 - component destruction

              -------------------------------------------

              destruction would be done similarly to initialization

               

              RichFaces provides hook in form of cleanComponent, which does both, cleanData and then custom destroy method.

              We could improve it and write own destruction for specific elements (similar to construction ^).

               

               

              #Idea 4 - component re-initialization after AJAX

              --------------------------------------------------------------

              This would require new hook in oncomplete event, where all the updated sub-tree will be re-initialized.

              • 4. Re: Bootstrap plugin architecture
                lfryc

                I have prototyped the ideas above ^ on sample of accordionGroup

                • 5. Re: Bootstrap plugin architecture
                  lfryc

                  The problem comes in case of jQuery plugins and RichFaces client-side API:

                   

                  the traditional client-side API for all RichFaces components is:

                   

                  #{rich:component('id')}.someFunction('paramValue');
                  

                   

                  or using behavior

                   

                  <rich:componentControl target="id" operation="someFunction">
                        <f:param value="paramValue" />
                  </rich:componentControl>
                  

                   

                  which both generates same JavaScript call:

                   

                  RichFaces.$(document.getElementById('clientId')).someFunction('paramValue');
                  

                   

                   

                  ----

                   

                  The jQuery plugins (including BootStrap plugins) has slightly different API:

                   

                  $('#clientId').pluginName('someFunction', 'paramValue');
                  

                   

                  in case of accordionGroup:

                   

                  $('#clientId_body').collapse('toggle');
                  

                   

                  ----

                   

                  Two issues there:

                   

                  • the component root (with #clientId) is not the element for which the plugin was initiated (it is #clientId_body)
                  • the call needs to contain the name of the plugin: collapse

                   

                  ----

                   

                  We could certainly use BootStrap-specific control component:

                   

                   

                  <b:control target="id" operation="toggle" />
                  

                   

                  or we could use auxiliary object bound to the component root as in the case of all other RichFaces components

                  (this would bring another state to the component, which needs to be handled).

                  • 6. Re: Bootstrap plugin architecture
                    lfryc

                    The last concerns is server/client state synchronization.

                     

                    Plugins needs to set current value to the input (it could be auxiliary one) each time the value is changed.

                     

                    All form inputs are then collected and their values are sent in AJAX/regular request.

                    • 7. Re: Bootstrap plugin architecture
                      bleathem

                      Lukas,

                       

                      This is a great start to the discussion - it's unfortunate that the forum software isn't going to be well suited to replying to this multi-topic thread.  Perhaps we should start an jira issue for each sub-topic, and carry on the discussion there?

                      • 8. Re: Bootstrap plugin architecture
                        lfryc

                        Hey Brian, good point, I will add those subtasks to the JIRA.

                        • 9. Re: Bootstrap plugin architecture
                          bleathem

                          Not a comment on the JSF event bridge, but rather on the jQuery architecture approach as a whole:

                           

                          I spent the afternoon reading about the jQuery UI widget factory.  It provides a "standard approach" for building stateful jQuery plugins, and removes a lot of the boiler-plate javascript for creating/destroying/updating of widgets.  Also it provides a nice mechanism for dealing with events / handlers + observers (something which we will do a lot of).  The bootstrap js approach is rather an open-slate in this regard (although I do like their data-* approach for plugin configuration).

                           

                          OTOH I'm sold on twitter Bootstrap / LESS for style and themes.

                           

                          One constraint I'm wrestling with is the idea that we have to commit our new widgets back upstream.  If we create new widgets using Bootstrap styles/CSS names, but write the plugins using the widget factory approach, then we will have no project willing to accept our components upstream.

                           

                          OTOH, I don't know how realistic it is that our new widgets will actually be accepted upstream, at least not in a timely manner.   For a "big" project like jQuery UI or twitter Bootstrap to accept our widget, it would have to be an incredibly popular widget, used by a lot of people.  That kind of thing takes time.  So we can expect to be maintaining these widgets for a long time ourselves. 

                           

                          So perhaps it is viable to develop jQuery plugins with the jQuery UI widget factory targetting the Bootstrap CSS.

                          • 10. Re: Bootstrap plugin architecture
                            lfryc

                            jQuery UI Bootstrap is kind of project to start with then:

                            http://addyosmani.github.com/jquery-ui-bootstrap/