Sunday, December 29, 2013

Multi-Column Sort in Backbone Collections

Amongst the features that I wish Backbone implemented a little more fully is collection sorting. Its great that it can accommodate several approached (like the attribute name or a function) so you can implement more complex sorting schemes. However, sorting a set of data is probably fairly well defined and, in most cases, will be a combination of one or more columns in either ascending or descending order. Generally, one column is enough so the built-in string variation is sufficient and easy to use. However, that will only give you ascending order. If you want descending order, you'll need a sorting function to reverse the comparison. A generalized version of that function might look like this:


   comparator: function(a, b) {

      var a = a.get( this.sortColumn ),
          b = b.get( this.sortColumn );

      if ( a == b ) return 0;

      if ( this.sortDirection == 'asc' ) {
         return a > b;
      } else {
         return a < b;
      }
   }



That's great for one column, but what if you want several columns to be considered in the sorting?

Sunday, December 22, 2013

Using Bootstrap Dropdown Buttons as a Form Select Box


The Bootstrap Button Dropdown is a nice control that can be customized to do a variety of tasks above and beyond what a normal select box can achieve. You're not limited by presenting a list of options to the user in the menu. You can add additional functionality to the menu like a search box and other logic. However, by default, the Button Dropdown is really just a menu of actions not really designed to represent a selected data value. Wiring up the control to behave like a select box is not too difficult. A little Javascript is necessary to handle a selection and change the label on the button:

<div class="btn-group btn-input clearfix">
  <button type="button" class="btn btn-default dropdown-toggle form-control" data-toggle="dropdown">
    <span data-bind="label">Select One</span> <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu">
    <li><a href="#">Item 1</a></li>
    <li><a href="#">Another item</a></li>
    <li><a href="#">This is a longer item that will not fit properly</a></li>
  </ul>
</div>


Using that markup will enable the built-in dropdown widget so the menu will open when the button is clicked. In addition to that default behavior, add a listener for click events in the menu:

   $( document.body ).on( 'click', '.dropdown-menu li', function( event ) {

      var $target = $( event.currentTarget );

      $target.closest( '.btn-group' )
         .find( '[data-bind="label"]' ).text( $target.text() )
            .end()
         .children( '.dropdown-toggle' ).dropdown( 'toggle' );

      return false;

   });


When an item is selected, this code will change the button label and hide the menu. Now we have a select box, however, the styling on Dropdown Button does not match the styling on other form controls. When the text in the button is too short, the button shrinks to fit. When that text is too long, the button expands outside the bounds of its parent:



A and B represent the default behavior. C and D show what happens if you simply add a .form-control class to the button. And E and F illustrate the desired behavior after adding some additional styles to the .btn-group class and contents of the button (the text and caret spans):

.btn-input {
   display: block;
}

.btn-input .btn.form-control {
    text-align: left;
}

.btn-input .btn.form-control span:first-child {
   left: 10px;
   overflow: hidden;
   position: absolute;
   right: 25px;
}

.btn-input .btn.form-control .caret {
   margin-top: -1px;
   position: absolute;
   right: 10px;
   top: 50%;
}



The two main difficulties I faced making this work properly was the display: inline-block on the .btn-group and the overflow of the text inside the button. The most significant change in the styles is using absolute positioning inside the button to align the label and caret to better control their size and position. I placed this example in a jsFiddle if you'd like to experiment with it more. If these modified controls are contained inside a grid cell, they will probably work pretty well. Other use cases may require additional tweaks to make functional.

Sunday, December 15, 2013

Working with Variable Height CSS Floats in Responsive Layouts

The Bootstrap grid system is a great toolkit for constructing fluid, responsive page layouts. Typically, you place enough .col-* elements into a .row parent so the total of the column sizes equals 12. However, nothing prevents you from adding as many columns to a row parent as you'd like. They will simply flow to the next row after reaching the sizing of 12. I was curious if I could use one row parent and layout out a 3 column grid of Bootstrap panels with equal width that would simply flow to the next row every 3 panels. The problem I encountered was while each panel my be equal width, it is not equal height. Using CSS floats to layout the content with variable height elements results in the content not necessarily wrapping to the beginning of the next row. Instead, they could float right below the last element on the previous row or anywhere else depending on the height of the previous elements:



Sunday, December 8, 2013

Working with CSS-Only Height Transitions and Content Styling

For some reason working with height in HTML is a challenge. DIVs conveniently fill their parent's width, but height is a different story. Adding a transition to the height becomes even more challenging and has caused me some recent grief. Even after finding a solution, I was still not completely happy with the result and spent some additional time finding a reasonable approach to make the content look correct in both the collapsed and expanded states.

As part of the solution, I'd like to limit the amount of Javascript to only what is necessary to toggle classes on the element that should be expanded/collapsed. Everything else will be defined via CSS to create the animation and style the content:

   $( '.expandable .toggle' ).click(function( e ) {

      var $target = $(this),
          $exp = $target.closest( '.expandable' );

      $target.toggleClass( 'dropup' );
      $exp.toggleClass( 'in' );

      return false;
   });


The code assumes there is a base class expandable assigned to element(s) that should change size and, contained within those elements, is some kind of toggle element to allow the user to switch between the expanded and collapsed views. Now we need to figure out what styles need to be defined to make it work.

What doesn't work

Trying to transition between an explicit height and auto will not work:

.expandable-bad {
   height: 48px;
   overflow: hidden;
   transition: height 0.55s ease-in-out 0s;
}

.expandable-bad.in {
   height: auto;
}


Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.


While the boxes do expand/collapse, there is no smooth transition between those states. Percentages only work inside a parent with a fixed height. However, I may not know how tall the content will be fully expanded and don't want to assume one height. I could calculate the height on each box, but if I'm going to stick to my goal of not using Javascript to calculate anything, I'll have to find an alternative CSS-only solution.

What does work

Instead of height, we can use max-height to solve our problem:

.expandable {
   max-height: 48px;
   overflow: hidden;
   transition: max-height 0.55s ease-in-out 0s;
}

.expandable.in {
   max-height: 1000px;
}




This mimics auto height because, if the height is not needed, the container will not be sized to the specified height. It will only be constrained once it reaches the defined maximum. Fortunately, this style can also be animated with a CSS transition so this looks like a viable solution as long as you don't exceed the defined maximum. The only thing you do need to know with this approach is how tall the content should start. If you're trying to fit a certain number of lines of text, you'll have to do some work to find the correct value.

Better clipping

Notice how the text doesn't hide until it reaches the border of the container? It would be nice if it would clip with the matching 15px top padding while in the collapsed state. The best way I found to achieve this is to use the :after pseudo-element to add and style content to cover the bottom text. As an extra visual cue, I added an ellipsis to the clipping box to signify there is more content in the box. However, once I do that, I need it to hide when the content is expanded so I'll add a transition to match the one defined in the expandable class:


/* add to existing expandable */
.expandable {
   position: relative;
   ...
}

.more:after {
   background-color: #FFFFFF;
   bottom: 0;
   content: "...";
   display: block;
   height: 15px;
   padding-bottom: 10px;
   position: absolute;
   width: 100%;
   transition: bottom 0.55s ease-in-out 0s;
}

.more.in:after {
   bottom: -25px;
}


This isn't a necessary addition to the height transition. But I think it makes the collapsed content look better:



I've been trying to use transitions whenever possible. Sometimes you have to be a little creative to make them work, but overall, they can reduce the amount of code required to create the effect.

Monday, December 2, 2013

Dynamic Collapsible Menus Based on Page Scroll Position

Navigation menus can eat up page real estate pretty quickly. While the user is interacting with the navigation, it makes sense to use the space necessary to allow them to make a selection. However, once they start to scroll into the content of the page, that navigation bar can become a nuisance. A lot of sites have started using the scroll position of the page as an indicator that the user has stop navigating and is now focused on the page content. As the scroll occurs, the navigation bar collapses into a compact representation of the menus that still allow navigating, but provide either less options or less verbose labeling. Google+ is good examples of a site that employs this technique and I was interested in creating a similar effect myself.

I decided to start with my jQuery UI Scrollable widget to monitor a certain element to determine when to toggle between the full and collapsed navigation menu. The full example presented here is one of the Scrollable widget's demo pages. The reason I chose this route is because the widget conveniently triggers one event when a target element is inside or outside the defined view port:

Friday, November 22, 2013

Formatting Dates with Moment as Backbone Computed Fields

I've gotten a little sloppy lately with my templates. Instead of formatting my dates outside of the template, I've been using Moment in the template to render different representations of the date value. The practice itself is really not the best approach. There's a good change you'll show the same value several times which requires redundant moment.format() calls. Additionally, it adds more code to a template when less is really a better choice. And finally, Moment 2.4.0 has started the process of deprecating the global scope reference in favor of defining it via an AMD library like RequireJS.

So the goal is to go from the less desirable:


   <%= moment( when ).format( 'MM/DD/YYYY' ) %>



To a value that has been already computed in the model:


   <%= when_fmt_short %>



My first thought was to just tie into the change event on a date field when initializing the model and write a function to generate all the different formats I might want to use:


var myModel = Backbone.Model.extend({

   defaults: {

      when: null,

   },

   initialize: function() {

      this.on( 'change:when', this.formatWhen );
      this.formatWhen();
   },

   formatWhen: function() {

      var val = this.get( 'when' );

      if ( val ) {
         val = moment( val );
         this.set( 'when_fmt_short', val.format('MM/DD/YYYY') );
         this.set( 'when_fmt_long', val.format('MM/DD/YYYY h:mm:ss a') );
         this.set( 'when_fmt_duration_ago', val.fromNow() );
         this.set( 'when_fmt_ellapsed_seconds', moment.duration( moment() - val ).as('seconds') + ' seconds' );
      }
   },

});



This works but the computed fields appear in the JSON payload to the server. If I want to avoid that, I need to overload toJSON to omit those fields from the output. Obviously, once I have several date fields, that's going to get tedious. Clearly, a generic solution that specifically addresses this issue either needed to be built or found. Fortunately, alexanderbeletsky/backbone-computedfields provides a nice extension to the model to describe computed field formats and dependencies. It then does the work to wire everything up and maintain that data:


var MomentModel = Backbone.Model.extend({

   defaults: {
      when: null
   },

   // Describe your computed fields
   computed: {

      when_fmt_short: {
          depends: ['when'],
          get: function ( fields ) {
              return moment( fields.when ).format( 'MM/DD/YYYY' );
          },
          toJSON: false
      },
   },
   
   // Wire everything up by attaching an instance of ComputedFields
   initialize: function () {
      this.computedFields = new Backbone.ComputedFields( this );
   },

});



The toJSON option determines whether the computed value will be included in the JSON payload. This solved the problem with sending it to the server. However, now the value would not be available when rendering the template in my view. While I could pass the model to the template and use the model.get() function everywhere, its not the option I prefer to use. ComputedFields provides a solution to avoid this situation by calling toJSON with an options hash that has the key computedFields set to true:


TestView = Backbone.View.extend({

   ...

   render: function() {

      // Since the default is to exclude the computed fields from the JSON payload,
      // make sure to pass an option to force them into the object for rendering in
      // the view:

      this.$el.html( this.template( this.model.toJSON({ computedFields: true }) ) );

      return this;
   },
   
   ...

});



I've posted a simple example in my sandbox that simply creates several formats and renders them to a basic template. While the computed fields are not limited to dates, they are the primary type of field I need to format. Next in line are probably number formats like currency. By using a consistent solution like Backbone.ComputedFields, these necessary formatting steps can be made easier to maintain and reusable across multiple templates while avoiding the use of the global scope moment function.

Monday, November 18, 2013

jQueryUI WaitButton Integrated with Twitter Bootstrap Styles

A few months ago, I wrote about a button widget that contained a spinner to indicate the user clicked and an action was being performed. At the time, I used the default jQuery UI styling and themes. However, now that I use Bootstrap as my base framework and cherry-pick what I need from jQuery UI, the widget lost all of its visual styling. Since the WaitButton does everything I need, I just have to figure out how to apply styles to it so it matches the button styles in Bootstrap.

I considered using addyosmani/jquery-ui-bootstrap as a solution, but wanted to start with Bootstrap styles and only add the jQuery UI classes required that further enhanced the baseline Bootstrap button. I figured this would make it a bit more resilient to changes in Bootstrap over time. The jQuery UI Button widget has options to show an icon on either the left or right side of the button text. WaitButton makes use of the icon on the left side which, in jQuery UI speak, is known as the primary icon. This content is inside the button tag so needs to be styled in a way to line up properly. .ui-button-icon* and .ui-button-text* are the set of classes involved in aligning this content, however, they can't just be copied into your CSS from the jQuery UI styles. The padding and positioning won't result in a button that matches other Bootstrap buttons. If you were to line them up, the jQuery UI buttons will be taller and wider for the same text. Additionally, Bootstrap offers several colors of buttons which require the animated GIF in the WaitButton to match. I attempted to use a transparent background but it just didn't look good so I created several GIFs (ajaxload.info) with matching backgrounds and created styles to swap the correct GIF into the button based on the btn-* class applied.

I eventually narrowed the set of styles down to these classes with the additions of the WaitButton specific classes to enable swapping the GIFs for different button colors. You can see a demo of the buttons on my sandbox and also download the CSS/GIfs required to adapt the WaitButton widget to work nicely with Bootstrap.

Monday, November 11, 2013

Using Mailgun's Event API to Poll for New Messages

If you've ever tried to write email processing logic, you know dealing with IMAP/POP and MIME are all acronyms you'd like to avoid. Having fought that battle in the past, I really did not want to worry about those details. Instead, I want to send and receive messages without worrying about the underlying mechanisms that enable it. This is where Rackspace's Mailgun solution saves the day. Now, mail can be handled using a simple REST API and their servers abstract all the details of MIME, mail protocols, etc. On top of that functionality comes a lot of other great features like mailing lists, campaign tracking, etc. However, my first goal was to tackle sending/receiving mail. Sending turned out to be quite simple, however, receiving required a little more work.

One of the main components of Mailgun are using various webhooks to notify you in real-time that something has happened. As long as you have a publicly accessible server, you can receive the event and act accordingly. However, utilizing this mechanism to accept a message is not always possible. The alternative approach requires you to look for stored events via the Events API end point, extract the message key, and then call the Messages API end point to retrieve the actual message. When polling the events, you'll need to know if you already processed a message so you know not to attempt to retrieve it again. As a result, you need to keep some state information locally to compare against while reading the events. This data only needs to be retained long enough to be outside of the maximum window that you'll use in the Events API call.

Monday, November 4, 2013

Considerations on Client-Side Javascript Caching Strategies

If you look at any library that implements a type ahead like search widget, you will inevitably see a solution for caching remote search results. Its a problem that pops up just about anywhere that you have a list of data that you'd like to reuse without making another round trip to the server to fetch. Recently, I've been working on several projects which required a variety of caching techniques. I spent some time trying to isolate the commonalities between them so I could reuse parts of the logic and avoid writing a bunch of redundant code. Below, I've tried to highlight the approach I took to solving some of these common problems.

Before anything is cached, you need to make a request to fetch data from the server to start filling that cache. Let's assume you have a text box that the user will type a search string in and, as they type, it triggers the lookup - either in the cache or on the server. Since you'd rather avoid firing multiple concurrent requests to the server while the user is typing, you'd like to employ a method of throttling the search requests. Since I already have Underscore loaded, I prefer to use as much of its functionality as possible before either writing my own solution or looking elsewhere. The library contains several handy "function" functions which essentially wrap functions with enhancements. In the case of the _.throttle() function, it takes a passed in function and wraps it with throttling logic to prevent that function from being fired except after a certain delay has occurred first (or the other way around or both - see the documentation for a full explanation):

   this.fetchData = _.throttle( function( p ) {
   
        /* if search is already in cache */
            /* return cached data set */
        /* else */
            /* $.ajax() to server */
      },
   },
   500,               // Timer in milliseconds
   { leading: false } // Only triggered on the falling edge
);


Monday, October 28, 2013

Using the Ruby Sequel Gem to Build Dynamic Filters

The Ruby Sequel library has become my favorite tool for interacting with relational databases. In my opinion, it has the right blend of abstraction to simplify common database CRUD operations while maintaining plenty of control when you need to perform more complex queries. While powerful, its taken a little time studying the documentation to learn its secrets. There's not a lot of external knowledge available to draw from when you can't figure something out. I know how to write SQL but translating that into the Sequel DSL has been challenging at times. I've spent a lot of time in the Ruby console trying different ways of assembling an equivalent SQL statement with Sequel that I can write in a minute or two in the PostgreSQL console. While Sequel will let you just pass a SQL string to it, when you need to assemble that string with conditional components, it makes less sense. After all, that's what Sequel is doing for you internally. You just have to figure out how to pass in those components so Sequel knows how to build the final SQL.

As a specific problem, consider a simple example where you have a table that has several text columns against which you want to allow a user to perform a search. They can choose to search on one or all of the columns, however, they are bound to the records that they are marked as the "owner" based on their user ID. Here is how the SQL might look if you just wrote it using all four of the possible fields to search:


SELECT * 
FROM my_table
WHERE 
   owner_id = :user_id AND
   ( text_field1 ILIKE '%:search_term%' OR
     text_field2 ILIKE '%:search_term%' OR
     text_field3 ILIKE '%:search_term%' OR
     text_field4 ILIKE '%:search_term%' )



Constraining the user is easy by itself with Sequel:


# userid is set, session or otherwise
DB[:my_table].where( :owner_id => userid )



The problem that arises now is how to AND those like conditions onto the statement. If you simply add an or() function to the end of the prior line (below, "term" is from the query string in the request and is normalized to lower case and enclosed in '%'):

DB[:my_table].
   where( :owner_id => userid ).
   or{ text_field1.ilike( term ) }.
   or{ text_field2.ilike( term ) }



You'd get an SQL statement like this:

SELECT * 
FROM my_table
WHERE 
   owner_id = 100 OR
   text_field1 ILIKE '%foo%'OR
   text_field2 ILIKE '%foo%'



Which will result in either all the owner records or the ones that match "foo". The non-dynamic solution is to use the and() function with a block that combines those conditions using the "|" operator:
DB[:my_table].
   where( :owner_id => userid ).
   and{ text_field1.ilike( term ) | text_field2.ilike( term ) }


Ok, getting closer but this only works if you always want all the text fields to be searched. Early I stated that user can select which fields to include in the search which means these need to be conditionally added to that "and" block. After some studying, I finally found the solution. It took realizing how two different parts of the documentation were related but involves the fact that you can assemble atomic expressions and pass them around to build more complex expressions. The final solution uses a "scope" variable that was provided in the page request and represents an array of fields to search. We can now build an array of expressions and pass that array to Sequel.| to generate the final query:


filters = []
filters.push( Sequel.ilike( :text_field1,  term ) ) if scope.include?( 'text_field1' )
filters.push( Sequel.ilike( :text_field2,  term ) ) if scope.include?( 'text_field2' )
filters.push( Sequel.ilike( :text_field3,  term ) ) if scope.include?( 'text_field3' )
filters.push( Sequel.ilike( :text_field4,  term ) ) if scope.include?( 'text_field4' )

ds = DB[:my_table].where( :owner_id => userid ).and{ Sequel.|( *filters ) }

...



Once I start to connect those dots, it became a lot more clear how to utilize Sequel to dynamically build queries. It sure beats the string concatenations I use to do while still maintaining a reasonable amount of similarity to the SQL syntax. As always, there's probably more than one way to solve a problem. This one met my needs and has been flexible enough to adapt to new requirements. New conditions can simply be added to the existing chain of AND'd conditions or pushed into the OR'd array.

Monday, October 21, 2013

Simulate Bootstrap Focus Effect on Non-Form Controls

While working on the MultiSearch contact demo, I wanted the widget to show the nice blue focus outline like other input boxes that have the Bootstrap form-control class. However, I did not want that effect on the input box used in the search. Instead, I wanted it on the DIV with the panel class which was defining the bounds of the widget. That means both focusing on the input and any interaction inside the panel's bounds should trigger the focus effect. It turns out that managing any clicks inside the widget were pretty easy to handle. However, since there is an input box inside the widget, it has a tab stop which allows a user to use the keyboard to move the focus on and off the input. I was trying really hard to keep this as simple as possible but focus/blur events are inherently difficult since they don't bubble up through the DOM. While jQuery solves this by mapping those events to focusin/out, listening to multiple event types (click and focusin) really caused a lot of headaches.

The solution I eventually settled on uses one click event handler on the MultiSearch widget container and then two handlers on the BODY element to catch click and focusin events. The former is used to turn off the focus when the click occurs outside of the widget and the latter is used to detect tabbing into an element that triggers a focus event. That focusin handler simply triggers a click event on the target so, if the target is inside a MultiSearch widget, it will cause the click handler to fire which enable the focus effect and, if applicable, remove it from another widget.

That's the description of the solution, here's the actual implementation. The MultiSearch widgets markup on the contacts demo looks like this:



There are three of these on the page and each will need the click handler to enable the focus effect. For simplicity, let's assume those three elements are already selected into a variable named $fields. The handler can be bound on that set:


      $fields.on( 'click', function simulateFocus( event ) {

            // $me is the widget container element.
            // $panel is what we want to add/remove the focus styling

            var $me = $( this ),
                $panel = $me.find( '.panel' );

            // Only if focus hasn't already been activated.  We don't need
            // multiple handlers listening to remove the focus class. 
            if ( !$panel.is( '.focus' ) ) {

               $panel.addClass( 'focus' );

               // Several things are happening here:
               //  1) This click event is still bubbling, listen to
               //     click now, and it will be caught before the popover
               //     ever appears.  Deferring it pushes the execution outside
               //     of the current call stack
               //  2) Clicks inside the popover are fine.  Use the $.has() function
               //     to see if any part of the target is or is inside the popover
               //     element.  Only remove if that is not true.
               _.defer( function() {
                  $( document.body ).on( 'click.focus', function( e ) {
                     if ( $me.has( e.target ).length === 0 ) {
                        $panel.removeClass( 'focus' );
                        $( document.body ).off( 'click.focus' );
                     }
                  });
               });
            }

         })


That takes care of everything except the focus event triggered when a user tabs into a field. The simplest solution is to just listen to every focusin event on the page and turn that into a click event on that element:


   $( document.body ).on( 'focusin', 'input, textarea', function( event ) {
      $( event.target ).trigger( 'click' );
   });


As a final note, here are the styles required to enable the effect on the panel class. These are copied from the form-control class:


.panel {
   margin: 0;
   transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s;
}

.panel.focus {
   border-color: #66AFE9;
   box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(102, 175, 233, 0.6);
   outline: 0 none;
}



This example can be easily adapted as needed to turn a panel that contains several elements that, as a group, you want to consider a form control into something that looks like one complete entity when interacting with its content.

Monday, October 14, 2013

Entering Recipients from an Address Book using jQueryUI MultiSearch

This might be one of the most common use cases (apart from entering tags) for this type of widget. Compose an email and start typing someone's name. Yahoo, GMail, all of them will offer suggestions from your address book. Select someone and start typing the next one. You can very quickly build a list of recipients using this UI pattern. GMail goes a step further by enhancing the experience - when you hover over an entered contact, you get a popover box with more details on the contact (a picture, Google+ circles, etc). Creating this type of user experience was one of the design goals I had when working on the MultiSearch widget. While the widget won't just provide all of this functionality, it does make it pretty easy to build.

Overview

Besides wiring up the source data, there's really only two parts you, as the developer, need to do to make this kind of UI work. The MultiSearch widget will handle the typing, searching, and rendering. You need to provide the markup and styling plus a little validation logic. If you're interested in a popover box, you'll need to define that content and some control logic. Here's a summary of the features we're going to build:

  • Searching - As the user types in the contact, we're probably going to search both the name and email. Returned results need to be rendered into a suggestion box. The content should probably include both fields so the user can see what they're matching and pick accordingly.
  • Selected - When an contact is selected, we need to render something into the list of recipients. This can be styled in several ways and probably should account for a contact not found in the address book. If its not found, we should probably ensure its a valid email.
  • Details - Hovering over the list of entered recipients triggers an event that we can render a popover. So far, the widget has been rendering everything for us. However, the only thing the widget provides here is a item select event with the specifics about the contact under the mouse. We'll need to manage the popover and rendering its content based on the the context provided in that event.


Let's walk through each feature and see how it can be implemented. If you want to skip the details and tinker with demo, its one of the examples on the project pages. A link is included to jump to the full source code. If you'd like a break down of the specific areas of functionality, keep reading.

Sunday, October 6, 2013

Removing Markup from UI Widgets to Build Reusable and Flexible Components

I've been quite impressed with the simplicity and flexibility of the Twitter Bootstrap CSS framework. Its becoming the basis of many of the projects I'm starting. Since it does 90% or more of what I need anyways, why start from scratch? That said, the accompanying widget library is not always as robust as I need and I generally have to step outside of the Bootstrap world to find something that provides the required functionality. However, most of those widgets tend to have their own style definitions that don't always play well with Bootstrap. I started moving away from widget libraries like jQuery UI which come with their own CSS framework and have been turning instead to widgets that offer hooks to define the content and styling that is rendered by the widget. This approach makes a lot of sense if you're accustom to a MVC framework where the logic and presentation are generally decoupled to enable easy restructuring and styling to promote reuse and modularization.

Monday, September 30, 2013

Learning to Build a Server with Puppet in (almost) a Day

My development environment is a complete mess. I have multiple versions of various stacks from Ruby to NodeJs and I've run into so many issues trying to keep things compatible that I need to start splitting environments up by project. Its something I knew I would have to do but just didn't want to invest the time setting it up. What I needed was a easy way to spin up a base environment and, by project, describe what the environment should look like. Some research led me to several options like Vagrant, Razor, Capistrano, Chef, and Puppet. Ultimately, I chose to keep it simple by using Puppet in standalone mode to describe the configuration and use a combination of bootstrapping and git to deploy a new environment. As a side benefit, my fellow developers could easily replicate the same environment and these configurations could serve as a basis for building staging/production servers. In theory, the challenge should have been learning the syntax of a Puppet manifest including what modules existed that would do a lot of the work for me. However, as it turns out, I had a lot of problems just getting the puppet command line program to even run. In total, I spent about 3 days building a base VM image, installing the minimum environment to run Puppet, and writing my manifest.

Monday, September 23, 2013

Controlling the Container Element for Backbone Views

I always like when there is more than one way to do the same thing. Flexibility and choice is always good. It can, at times, be confusing which approach to use - especially for beginners. When starting out with Backbone, I spent a considerable amount of time trying to determine the "best-practice" to rendering a view and adding it to the DOM. It was clear in the documentation that more than one method could be used, but after reading through some examples, the following scenario seemed the most common:

Monday, September 16, 2013

Integrating Socket.IO into a BackboneJS Project

There's a lot of opportunities to add real-time features to an application. Since Backbone already has an excellent notification layer built into its models, it seems only natural to apply incoming changes from a Socket.IO connection to a view's bound model or collection. Instead of fetching all the data periodically, the server pushes changes down to your application and you apply them to the data.

As a simple example, suppose our server will emit a "changed" event when something important changes in the data we're displaying. The data sent in the event contains the pertinent record we have in the model/collection. In this case, the model has a few fields and contains a collection of "places" that could be added to as part of the update.

Monday, September 9, 2013

Using SVG Filters to Create Outlines of Shapes

I needed a quick way to add an outline around an SVG shape without having to create one for all the shapes I was using. I knew I could use a filter for a drop shadow effect so figured that there must be something that could make this possible.

I finally found the solution using the dilate operator of the feMorphology filter. This made a copy of the object and expanded out a certain radius. Next, I remapped all the colors so the expanded shape was yellow. I blended that behind the original shape to produce my outline:

Apply it to any shape to create a yellow outline around it:

`


That seemed pretty easy except when you'd like to have more control of the color of the outline. Using the feColorMatrix to remap the input shape's color to a single color that will represent the outline is somewhat difficult. If you want simple primary colors, you're probably fine. Outside of that, and its not as easy.

Tuesday, September 3, 2013

Addressing the Subtle Differences between Socket.IO WebSockets and XHR Polling Transports

I was quite excited to see my game working with WebSockets in my development environment only to be disappointed when I deployed to Heroku and found the Cedar stack does not currently support WebSockets. Once I switched to XHR Polling, I started having some odd issues that took some time to track down the actual problem. Essentially, the game would start and players could interact as expected. After about a minute, players would start showing as leaving the game when they actually did not. This implied that the disconnect event fired on the socket which caused it to update the player record and emit a "left" event. Looking through the logs confirmed the drop so I started looking at the different timeouts and suspected something was not working properly with the "close timeout".

After exhausting that angle, I stared at the logs more and finally noticed that the socket ID being disconnected wasn't actually the one doing the polling. It turned out that if a player refreshed the browser, the socket didn't actually disconnect like it did with WebSockets. Instead, it hung around until the close timeout and then the server dropped it. The problem was that the player had a new active socket and their old one disconnected and subsequently marked them as leaving.

Monday, August 26, 2013

Dynamically Creating Game Rooms using Socket.IO and NodeJS

As I ventured into some real-time work with the browser, it made sense to jump into Socket.IO and see what it had to offer. My primary focus was to build a turn-based game in the browser which allowed 2-4 players to play the game in real-time. I liked Socket.IO because it handles the details of normalizing the mechanism for providing real-time communication in the browser, integrates out-of-the-box with NodeJS and Express, and already contains a "room" feature to isolate messages. I found some quick and dirty examples floating around but nothing that really addressed how to dynamically generate a room and get everyone connected. The approach I ultimately took was a hybrid solution using a handful of traditional REST API end-points to handle registering a new game and other players joining that game and switching to Socket.IO events to manage the game play once the registration phase was complete. In this post, I'm not going to present a full game but, instead, strip down the code samples to what I believe is the basic boilerplate to create a game and coordinate the process of adding players. Along the way, I'll point out some issues related to concurrency and address a few failure scenarios.

Wednesday, August 21, 2013

Create Fly Over Notification Messages with Bootstrap

Twitter Bootstrap provides a very solid foundation for structuring a page. Even if there is not a specific component available in the framework's library, you can usually adapt something to meet your needs. Additionally, the framework establishes patterns that are worth understanding as you construct new types of content. If you look at how a modal dialog is transitioned into the view, you'll notice it uses all CSS3 to perform the animation. It does this by using a "fade" class defining the initial positioning and transition to use. An additional "in" class is defined which contains the final position of the modal box. By toggling the "in" class on and off, you can animate the modal in and out of the visible page. When I wanted to create notifications that would fly into view, I thought I could leverage that concept to do a similar thing. Additionally, the Jumbotron class provided the layout structure I wanted for the content so I figured I would build on that to create my fly over message.

Friday, August 16, 2013

A Walk-Through of the Backbone.Fiber Demo

As a follow up to my post about the Fiber framework, I wanted to step through how the demo was assembled to utilize various features offered in the framework.  My goal was to create a basic, single data source application that explored several different patterns you will encounter when building a SPA.  Even though its read-only, its still a good example of the capabilities and project organization.  While concepts like two-way binding and state management are all possible extensions, the framework itself is not really concerned with how data is bound and rendered but more with how different parts are loaded and work together to create a functional application.  Additionally, I'll touch on how the project is organized to leverage various developer tools.  You can find the source on GitHub and use the live demo here



Monday, August 12, 2013

Building a Modal Progress Bar with Twitter Bootstrap 3

I needed a progress bar to show when loading some data and wanted the screen to block. It sounded like a job for a modal dialog. Bootstrap had both so I tried to combine them to create the desired effect. The idea was to show the modal and then cause the progress bar to animate from 0% to 100%. Bootstrap already has the transition defined in the framework, you just need to change the width to reflect the progress. In my case, I really didn't know the status, I just wanted to make it look like I did. So I created a class that changed the width to 100%. Thinking everything was all set, I tried it out and found it always showed at the 100% point:

See the Pen Bootstrap Modal Progress Bar by bseth99 (@bseth99) on CodePen



Knowing that there are usually issues around elements considered "hidden", I did some digging and found that transitions will not be run on elements with display: "none". Well, I had the show method just before it so it must be some kind of timing issue. I tried adding a setTimeout to force the code to run after the current execution stack completed:

  setTimeout(function() {
    $bar.addClass('animate');
  }, 0);


See the Pen Bootstrap Modal Progress Bar by bseth99 (@bseth99) on CodePen



This worked well, except every few clicks on the button resulted in the progress bar appearing in the final state. So something still wasn't working consistently. I upped the timeout to 10 milliseconds and it "seemed" to work fine. However, I wasn't going to risk it so I decided to really understand what was happening. As it turns out, browsers try to be pretty smart to speed things up so they'll try to batch changes to the DOM before really "committing" them to the DOM. In our case, we're going from display: "none" to display: "block" and then trying to add the animate class. This will get batched into one operation. The 10ms just tried to get outside that window to force a redraw before it was applied. However, this could change or vary between browsers so its probably not a good solution. A better approach is actually quite simple and avoids the setTimeout entirely:

  
  // Force DOM repaint with is()
  $modal.modal('show').is(':visible');
  $bar.addClass('animate');



Because $.is queries the DOM, the browser must render out anything its queued up. I could use anything to trigger it, but checking for ":visible" seemed related to what I was doing so I went with it. Now, the next line can run immediately knowing the progress bar is actually displayed and the transition will occur:

See the Pen Bootstrap Modal Progress Bar by bseth99 (@bseth99) on CodePen

I also fixed the styles to properly show the modal backdrop with a 50% opacity (this is corrected in a later release of Bootstrap 3). Knowing what happens made it easier to understand how to work around it. It looks odd, so a comment is probably good to avoid a friend from removing it and breaking everything, otherwise, this beats the setTimeout approach.

Thursday, August 8, 2013

Managing URL End-Points in Backbone Models and Collections

I had some trouble trying to get my end-points to work properly in Backbone lately. It was further complicated by the fact that what worked in one version stopped working in a newer version. Both the model and collection have a URL property. In theory, you should be able to use different end-points as necessary, however, depending on where you specify it, the behavior is different and, at times, undesirable. I've found that the source for my collection and the source for model are not always the same. In many instances, the collection will use a search API which provides a smaller fieldset but with many filtering options while the model with use an API that includes all the fields and has your normal REST operations. In that situation, you will want to define similar, but not the same URL for the source of the collection and model.

Saturday, August 3, 2013

Extending BackboneJS to Build Better Web Applications

I was reading Cody Lindley's Backbone.js Deconstructed and he pointed out that
... a framework calls your code, while a library is code that you call ...
And makes the statement, given the above definition, that Backbone is simply a library not a framework. That got me thinking about what truly defines a framework. Some people might include development workflow tools, visual components, and, various other helpful technologies. My definition boils down to simply these two concepts: modularization and life-cycle management.

Motivation


Before digging into anything real, I took a step back and tried to reason through what really defines these two concepts and only loosely tie these back to Backbone. I am interested in how these ideas relate to browser-side application development and thinking in terms of larger single page applications. I'm really interested in going beyond "hello world" and todo lists and want to find ways to factor out common functionality. In the context of building data-driven applications, I need to present the data to the user, allow them to interact with it, and then persist any changes along the way without having to write reams of code to accomplish it.

Saturday, July 27, 2013

Avoiding Code in KnockoutJS Data Bindings

I was reviewing some KnockoutJS code that created a dialog box. It had this line for generating the buttons:



Granted, the Knockout documentation recommends using the anonymous function in the click handler, however, once I start seeing Javascript appearing in the template, I get concerned. Back in the day, we'd stuff our HTML full of PHP tags to dynamically render a page. At the time, we didn't really know better (or have another option). Over time, we've evolved to separating the presentation from the logic that binds data and attaches behavior to that content. Today, there's a plethora of templating languages each with their own vernacular and, generally, many programming like qualities. So, while the capability exists to still write code inline in the template, its definitely not considered a best-practice. Given that, my question becomes: How much code is too much?

Tuesday, July 23, 2013

Detecting and Binding to Click Events Outside an Element

Binding to events that occur on a target element is one thing. Binding to the same event when it occurs anywhere but a target element is another. There's plenty of reasons to need to know when, say, a click happens somewhere other than a target element. A concrete example is a drop-down menu. You generally want to hide it if the user clicks somewhere other than the menu. Typically, you might do something like this:


   $('#menu').on('click', function( e ) {
      // process selection
   });
   
   $(document).on('click', function( e ) {
      // hide the menu
   ));


A click in the menu will result in changing the selection and then bubble up to the document to hide the menu. If the click happens outside the menu, only the document click handler executes. Now, let's say the menu has sub menus that only open when you click on its parent. You don't want to hide the menu at that point. In this case, you might just cancel bubbling to prevent the menu from closing:


   $('#menu').on('click', function( e ) {
      // process selection

      // don't bubble to document
      // it should not close yet.
      return false;
   });
   
   $(document).on('click', function( e ) {
      // hide the menu
   ));


This simple example quickly breaks down if you have multiple things that depend on click detection outside of the element.

Saturday, July 20, 2013

Finding a jQuery Tooltip Plugin that Meets Your Needs

The humble little Tooltip has evolved from simply showing a bit of text over the page using the title or alt attribute of a link or image element to something closer to an Infobox or Popover displaying rich, dynamic content enabling user interaction. There are so many libraries that provide tooltip features from the simple hover over text to these interactive information boxes that finding the one that meets your needs while staying small and maintaining consistency with your site can become a daunting task.

I set out to review a few of the more popular libraries out there to see what features they provided and how well they could adapt to the different uses I had in mind on my site. I limited my comparison to jQuery plugins that were either well followed on GitHub or part of another library. In the end, I settled on the following four evaluating them based on these criteria:

  qTip2 jQuery UI PowerTip Bootstrap
Content ***** *** *** ***
Styling ***** *** ** **
Positioning **** ***** ** *
Triggering ***** * **** **
Animation ***** ***** * *
Overall ***** **** *** **


The ratings simply indicate the depth of options available in each category. This means if you just need a basic tooltip, you can stick with PowerTip or Twitter Bootstrap. If you need more functionality and control, you may want to consider qTip or jQuery UI. I spent some time trying to use the various features available in each category and share those results below. I also copied all the demos to my sandbox for easier review and access to the source code.

Friday, July 12, 2013

Detect When a DOM Element is Scrolled into View using jQuery

The browser window can only show so much content before the user has to scroll. Knowing if or when a certain element has scrolled in or out of the visible area on the screen may be useful in certain situations. Not intending to reinvent the wheel or anything, I did some research to see what other libraries existed related to scrolling in the browser:



I'm sure others exist but I thought it was an interesting problem to explore so I set out to build a basic solution that would have the following functionality:

  • Add elements of interest to some global list with configuration options
  • Listen to the window scroll event and check each element to see if its in the viewport
  • When it first enters/leaves trigger an event/callback to allow further processing


Register Elements

First, we need to be able to register the elements we care about so their scroll position can be monitored. We'll use this global list in the scroll event handler later:



This just creates a tracking object which contains state, options, and the target element.

Monitor Scrolling

The next step is to listen for scroll events on the window. We can't listen to the individual items since they won't generate scroll events - the container that scrolls will emit these which means we need to listen to that container element and then check all the registered items to determine if they scrolled in or out of the visible part of the page. However, scrolling can generate a lot of events and probably will cause a performance hit if we are constantly trying to test for the position of all the registered elements. What we need is a way to only process one event per some interval of time. A possible solution is the Underscore throttle function which is a nice way to manage events that may rapidly fire to help boost performance in a situation where it might degrade if the underlying logic ran that frequently. Now, I didn't want a dependency on Underscore in this case so I just implemented a simple version specific to my needs:



Another benefit of this buffer is if the user scrolls quickly past an item, it won't be detected as being in the view.

Check and Fire Events

The checkInView() function referenced above iterates over all the registered elements we're interested in and checks the boundaries of the element against the visible part of the page. When the element was registered, an object was created with a invp key to track the state of the element. False means its not in the visible part of the screen and true means it is. This allows us to track when it changes and to fire the appropriate event:



Create a Plugin

At this point, we have the three parts required to enable the detection and trigger an event. Now, we just need to package it up so its easier to use with jQuery. For testing, I made a quick plugin:



This plugin is lacking the necessary cleanup handling and some other housekeeping but will work well enough for now. Next, we can create some markup:



And use the plugin to monitor the DIVs as they are scrolled:



I dropped this code into jsFiddle as a demo. You'll need to have your console open to see the output.

Next Steps

At this point, this is only a proof-of-concept to hash out the required functionality for a more robust version. Its missing some critical elements:
  • Only detects scrolling up and down not left and right
  • Only can detect elements scrolling in the window, not elements contained inside another element that scrolls
  • The jQuery plugin is lacking teardown logic required to stop monitoring an element and free up memory
In order to get there, some major refactoring is necessary to fill the gaps in functionality. As part of that reimplementation, I'd probably switch to using the jQuery UI widget factory which neatly encapsulates the details of initializing/destroying a jQuery plugin. Additionally, this plugin only detects the positioning and raises an event. It seems that including the ability to animate the scroll position instead of using another library would make sense as well.

I've built a more robust version of this plugin using the jQuery UI widget library as a basis. This enhanced version enables monitoring, querying, or changing the scroll position of an element relative to any scrolling container:

Friday, July 5, 2013

I'm Busy: Enhancing the jQueryUI Button with a Waiting Spinner

The Dojo Toolkit has a convenient BusyButton widget. This seemed like a nice feature to have available in my jQuery UI widget library. The motivation for having the button is two-fold:


  1. Prevent the user from clicking multiple times on a button that performs an action you only want to happen once
  2. Provide visual feedback to the user so they know they did click the button and something is actually happening
The circumstances for using a button like this makes the most sense on AJAX based action like form submissions or searching. The jQuery button fortunately provides a really good base to add this functionality. I wrote a quick prototype to see if my idea would work:

function toggleButton ( $el ) {

   if ( $el.button( 'option', 'disabled' ) ) {
      $el.button( 'enable' );
      $el.button( 'option', 'label', 'Save' );
      $el.button( 'option', 'icons', { primary: null } );
   } else {
      $el.button( 'disable' );
      $el.button( 'option', 'label', 'Saving ...' );
      $el.button( 'option', 'icons', { primary: 'ui-icon-waiting' } );
   }
}

function clickButton () {
   var $el = $(this);

   toggleButton( $el );
   
   /* This probably will be an AJAX-based call  */
   setTimeout(function () {
      toggleButton( $el );
      $el.one( 'click', clickButton );
   }, 2000);
}

$(function () {

   $('.ui-wait-button')
      .button({ disabled: false })
      .one( 'click', clickButton );

});
This code will result in the following button:



The code leverages the existing features of the button widget which allows setting an icon and controlling whether the button appears and acts disabled. I wanted to see how easy it would be to swap my own animated GIF into the spot where an icon would be displayed. Additionally, to ensure only one click is handled, I bound the click event using $.one() instead of $.on(). From there, its just a matter of adding the functionality to perform the action we're going to wait to complete and then reset the state back to the initial state so we can click the button again. In this experiment, I just used setTimeout() to emulate an action that may take a few seconds.

There is a little CSS needed to show the spinner as the icon. By default, the button widget is expecting a class that will position the palette of icons attached by the ui-icon class. Our class needs to replace this image with the animated GIF that represents our spinner:
.ui-wait-button .ui-icon-waiting {
   background-image: url("loading.gif");
   background-position: 0 center;
}

Its important to ensure the background of the spinner is transparent and it will fit in the expected 16px square defined by the theme. My spinner is 16X11 pixels so I had to adjust the positioning a bit to align it properly. You can use a site like ajaxload.info to select from a list of existing spinners and generate one with a transparent background.

Finally, we just need some simple HTML that will represent our button:
  

This approach might be enough for a one-time use scenario, but its not very DRY if you need to have several buttons that will provide a waiting state. Plus, there are some other features that might be better suited if it were built as a jQuery UI widget. By encapsulating it in a widget, I can use an event to signal the waiting state from the click and provide a callback function that the event handler can use to signal the waiting is complete. That function can take several arguments to indicate what to do next. In some situations, it might be desirable to change the label to something other than the original starting label and/or leave the button in the disabled state.

I used the above concept and built an extension to the button widget called WaitButton. I have the code available on GitHub (JS|CSS|GIF) along with some examples. I added two options to the button, waitLabel and waitIcon, which do basically what the name implies. Neither are actually required as the widget will use the default ui-icon-waiting class as the primary icon in the button and the existing label if a waiting label option is not specified. You can define your own class and set waitIcon, override the existing ui-icon-waiting class, or replace the animated GIF (the class loads waitbutton-loading.gif from the images folder). In addition to those options, I added a waiting event that should be used to handle the click from the user and call the done() callback function to signal the processing is complete. Without any arguments, the button will return to the starting state. However, several variations are available:

Default completion - return to the start state
   $('#save')
      .waitbutton({ waitLabel: 'Saving ...' })
      .on( 'buttonwaiting', function ( e, ui ) {
            
            setTimeout(function () { ui.done(); }, 2000);
         });

Return to original label, but leave disabled
   $('#save')
      .waitbutton({ waitLabel: 'Saving ...' })
      .on( 'buttonwaiting', function ( e, ui ) {
            
            setTimeout(function () { ui.done(false); }, 2000);
         });

Change to a different label, but enable the button
   $('#save')
      .waitbutton({ waitLabel: 'Saving ...' })
      .on( 'buttonwaiting', function ( e, ui ) {
            
            setTimeout(function () { ui.done( 'Saved' ); }, 2000);
         });

Change to a different label and leave disabled
   $('#save')
      .waitbutton({ waitLabel: 'Saving ...' })
      .on( 'buttonwaiting', function ( e, ui ) {
            
            setTimeout(function () { ui.done( 'Saved', false ); }, 2000);
         });

The last three require calling waitbutton() on the element to force it back to the initial state. In my demos, I used a reset button to enable that step.

Just a few simple tweaks to the base UI framework and we have a handy button that can provide visual feedback about state and prevent extra clicks from messing up our processing.

Sunday, June 30, 2013

Using Google Maps Drawing Manager to Create User Selectable Areas

Drawing-Manager-Selections

The Google Maps API has been on my list of things to learn for some time now. I recently had an opportunity to dive in and try a few features out. There's a lot of good documentation and small demos available from Google which makes it pretty easy to get started. I decided to create a simple scenario where, given a set of places marked on the map, the user can select a region of interest and list more details about the points inside the selected area.

I started this experiment with the Drawing Tools demo, tweaking it, and adding various different features. There are several pieces needed to make it work:


  1. Create the map and center it

  2. Plot all the points the user can select

  3. Create the DrawingManager, tell it what to draw, and then listen for it to complete drawing that object

  4. Each time a selection is made, find the points inside the area and list them next to the map

  5. Maintain only one selection area. Clear the existing one in drawing more and, as a convenience, make a completed selection draggable/resizable



From that list of goals, I start digging through the documentation and examples looking for what I needed to realize the functionality. Creating the map and DrawingManager was already handled in the demo I started from. However, I didn't want to draw multiple overlays - just a circle. I tweaked the configuration options to only draw circles and not show any controls:



drawingManager = new google.maps.drawing.DrawingManager({

drawingMode: google.maps.drawing.OverlayType.CIRCLE,
drawingControl: false,

circleOptions: {
fillColor: '#ffff00',
fillOpacity: 0.3,
strokeWeight: 1,
clickable: false,
editable: false,
zIndex: 1
}

});



Now, I could only draw circles but there was no limit on how many I could draw. The next step was to listen for when a draw operation completed and track the circle object that was drawn so I could ensure only one was drawn at a time:



google.maps.event.addListener(drawingManager, 'circlecomplete', function( circle ) {
selectedArea = circle;
});



Once I capture the selected region, I know there is something selected. However, I still need to either remove the current circle before drawing a new one or prevent a new circle from being drawn. I attempted the former by listening to the map's click event:



google.maps.event.addListener(map, 'click', function() {

if ( selectedArea ) {
selectedArea.setMap(null);
google.maps.event.clearInstanceListeners(selectedArea);
}

selectedArea = null;
});


But that handler was never called. It seems the DrawingManager was preventing map click events. My solution was to use jQuery to listen for mousedown events on the map container DIV with the same handler function as above:



$('#map-canvas').on('mousedown', function() {
...
});


Now, as the next circle is drawn, the current one is removed from the map.

Before anything can be selected, there needs to be something to select. I created a simple array of points and added them to the map:


var sites = [
{ location: 'Alfond Swimming Pool', lat: 28.5903, lng: -81.3484},
{ location: 'Cahall Sandspur Field', lat: 28.5928, lng: -81.35},
...
];

function plotMarkers () {

$.each( sites, function () {

if ( this.marker ) this.marker.setMap(null);

this.position = new google.maps.LatLng(this.lat, this.lng);

this.marker = new google.maps.Marker({
position: this.position,
map: map,
title: this.location
});

});
}


I saved the LatLng object since I'll need that later to determine if a location is inside the selected area. That process is setup in the DrawingManager's circlecomplete event handler, I'm going to add a function to determine what points fall inside the circle:



google.maps.event.addListener(drawingManager, 'circlecomplete', function( circle ) {

selectedArea = circle;

listSelected();

});



That function uses the Geometry helper function computeDistanceBetween() to take the center of the circle and find the distance to each site on the map to see if its less than the radius of the circle:


function listSelected () {

var r = selectedArea.getRadius(),
c = selectedArea.getCenter();

var inside = $.map( sites, function ( s ) {

var d;

if ( ( (d = google.maps.geometry.spherical.computeDistanceBetween( s.position, c )) <= r ) )
return s.location + ' ('+(Math.round(d/100)/10)+' km)';

});

$('#map-selected').html( inside.sort().join('<br/>') );
}


If it is within the circle, it will be added to the list of locations to display next to the map. As this is a proof of concept, I've made no attempt to make this work with larger sets of data. Clearly, a different strategy would be required to accommodate anything more than a few hundred points. Also, the "extra" information is not exactly that spectacular but it shows the idea.

Right now the map is stuck in edit mode so you can't interact with the it. Every action results in a drawing activity. You can't drag the map around or use the mouse wheel to zoom (just the controls on the map). For now, I decided to toggle the map into interact/select mode by using a button to enable the DrawingManager for creating a selection. Upon drawing the circle, the DrawingManager is disabled and the resulting circle is allowed to be moved and resized. A few changes were needed to enable this feature. First, the circleOptions in the DrawingManager needed to be set:


drawingManager = new google.maps.drawing.DrawingManager({

drawingMode: google.maps.drawing.OverlayType.CIRCLE,
drawingControl: false,

circleOptions: {
fillColor: '#ffff00',
fillOpacity: 0.3,
strokeWeight: 1,
clickable: false,
editable: true,
zIndex: 1
}

});


Setting editable to true allows the circle to be modified after being drawn. Next, I added the button and toggling logic:



$('#map-controls').children().button().click(toggleSelector);

function toggleSelector () {

var $el = $('#map-controls button');

if ( $el.button('option', 'label') == 'Select' ) {

$el.button('option', 'label', 'Interact');
drawingManager.setMap(map);
} else {

$el.button('option', 'label', 'Select');
drawingManager.setMap(null);
}

selecting = !selecting;
}


And added the toggleSelector() function to the circlecomplete event handler so the DrawingManager is disabled after a circle is drawn:


google.maps.event.addListener(drawingManager, 'circlecomplete', function( circle ) {

selectedArea = circle;

google.maps.event.addListener(circle, 'center_changed', listSelected);
google.maps.event.addListener(circle, 'radius_changed', listSelected);

listSelected();
toggleSelector();

});


Additionally, I added listeners to the circle to watch for changes to the circle which may affect the selected region. When that happens, I want listSelected() to be called to rebuild the list of locations inside the selected area.

A working demo is on my sandbox along with complete source. Although relatively simple, the example examines several different features of the Goggle Maps API and how they can be tied together to create an interactive user experience.

Sunday, June 23, 2013

Backbone Router-Friendly jQuery UI Tabs Widget

jquery-ui-tabs-widgetTabs are a basic page layout tool that help organize and separate content. The jQuery UI library provides a fairly feature-rich tabs solution complete with AJAX content loading. I had originally thought I could just drop that widget on my page, setup the links for each tab, and use a Backbone router to manage capturing the tab changes and loading my content into the appropriate tab. However, I quickly discovered that the tabs widget prevented the click event from bubbling up to the point where the browser location would change such that the router would see the change. Upon further review, I realized that I really didn't need a whole lot of elaborate functionality. While the jQUery UI widgets are great, they are designed to provide functionality that may not make sense in a Backbone-based application. In the case of tabs, you are most interested in the layout and not much else. Depending on the use case, you'll probably tie the tabs to routes and then use the Backbone library to handle loading and generating all the content for each tab. Now, you could just listen for the "activate" event from the tab widget and change rewrite the location yourself:


var myTabsView = Backbone.View.extend({

render: function () {

this.$el.html(...);
this.$el.tabs();

return this;
},

events: {
'tabsactivate' : function ( e, ui ) {

var hash = ui.newTab.find('a[href^=#]').attr('href');

if ( location.hash.length == 0 )
location.href += hash;
else if ( location.hash != hash )
location.href = location.href.replace( /#.*$/, hash );

}
}

});


But, somehow, that just seems to defeat the purpose. You're essentially building a router to trigger your router. I thought I'd at least explore what would be necessary to build a basic tabs layout that would provide the same behavior without any intervention from external code. Given that, I decided to build a tabs widget using jQuery UI as a foundation so it would have a similar look-and-feel, leverage the existing framework, and provide flexibility for using it in several contexts.

My markup will look very close the required markup for the jQuery UI tabs widget. I did not make the link between the tab LI element and its panel DIV element based on the HREF/ID attributes. Instead, I assumed the order (and number) would match:



<div id="tab-layout">
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#usage">Usage</a></li>
<li><a href="#example">Example</a></li>
<li><a href="#lorum">Lorum Ipsum</a></li>
</ul>
<div></div>
<div></div>
<div></div>
<div></div>
</div>



Each of those LI/A elements need to look like tabs. I was trying to keep things as simple as possible so I thought I could use a combination of button widgets and a few well place styles to reproduce the look and functionality with as little code as possible. After all, the button widget can style an anchor tag to look almost exactly like a tab. However, again, there's a lot of extra functionality happening in the button widget which wanted to work against me. A button will not keep the active (pushed) state after its clicked. I tried to defeat it, but the widget will attach a single-execute click handler on the document node to remove that state. I just decided that the only reason I wanted the widget was for the styles so just wrote code to replicate the results:



// Generate jQuery UI Button markup on an anchor
// without using a button widget
$el.find('a')
.addClass( 'ui-button ui-widget ui-state-default ui-button-text-only ui-corner-top' )
.each(function () {
var $button = $( this );
$( '<span>' )
.addClass( 'ui-button-text' )
.text( $button.text() )
.appendTo( $button.empty() )
})



The next consideration was to expose a way to both programatically change and retreive the current tab and panel node. This allows the widget to decide what consistitutes the container for a tab panel and nicely encapsulate that part of the design away from the rest of the code. Additionally, in cases where you may not use a router to detect tab changes, I decided to publish both the beforeActivate and activate events just like the existing jQuery UI tabs widget. With those considerations in mind, I organized the widget to cache the tabs and panels DOM nodes, build a consistent object that could be used to represent a tab in both the events and get/set method, and add classes to style the tabs. Here's some of the highlights:




/**
* Listen for clicks, trigger events, and use active to change the tab
*
*/
events: {
'click li' : function ( event ) {

// Get the index amongst the LIs siblings
var idx = $( event.currentTarget ).index(),

// Make normalized objects for the tab we're leaving
// and the tab we're changing to. Don't need to know
// the index of the current tab, the function will figure it
// out.
oTab = this._getTabInfo(),
nTab = this._getTabInfo( idx ),

eventData = {
oldTab: oTab.tab,
oldPanel: oTab.panel,
newTab: nTab.tab,
newPanel: nTab.panel
};

// Provide a way to cancel it
if ( oTab.tab.index != nTab.tab.index &&
this._trigger( 'beforeActivate', event, eventData ) !== false ) {

// Use the setting to change the tab
this.active( idx );
this._trigger( 'activate', event, nTab );
} else {

event.preventDefault();
}

}
},

/**
* Get/Set the current tab. Accepts the index or string match the hash (less #)
*
*/
active: function ( tab ) {

var idx = 0;

if ( arguments.length > 0 ) {

// Resolve the argument type and find the tab
if ( typeof(tab) == 'string' && tab.length > 0 ) {
idx = this.tabs.index( this.tabs.find( '[href=#'+tab+']' ).closest( 'li' ) );
} else if ( typeof(tab) == 'number' && tab >= 0 ) {
idx = tab;
}

this.panels.hide().eq(idx).show();

} else {

return this._getTabInfo();

}
},

/**
* Assemble tab info object from the provided index. No argument means
* to get the current active tab.
*
*/
_getTabInfo: function ( idx ) {

var idx = arguments.length > 0 ? idx : this.tabs.find( 'a.ui-state-active' ).closest( 'li' ).index(),
tab = this.tabs.eq( idx ).find( 'a' );

return {
tab: { index: idx, hash: tab.attr( 'href' ).slice(1), label: tab.text() },
panel: this.panels.eq( idx )
}
}



Now its time to use the widget to build a simple test Backbone app. All this does is create a router for the changing tabs and set each tab with some static content.



$(function () {

var Router = Backbone.Router.extend({

routes: {

"overview" : "showAsText",
"usage" : "showAsCode",
"example" : "showAsCode",
"lorum" : "showAsText"

},

showAsText: function () {
var selected = $('#tab-layout').simpletabs('active');

selected.panel.html($('#tab-'+selected.tab.hash).html());
},

showAsCode: function () {
var selected = $('#tab-layout').simpletabs('active');

selected.panel.html('<pre><code class="prettyprint">'+htmlEncode($('#tab-'+selected.tab.hash).html())+'</code></pre>');

PR.prettyPrint();
}

});


$('#tab-layout').simpletabs();

var router = new Router();
Backbone.history.start();

});



I have a demo setup on my sandbox which has additional usage information. If you're interested in using the widget or want to use it as a starting point, you'll need both the Javascript and CSS files. The widget has no dependencies on Backbone. It only requires jQuery and jQuery UI to work.

Several features are missing that are in the jQuery UI widget which might make sense have available. I did not implement the ARIA attributes to enable screen readers, the keyboard navigation, or the ability to enable/disable individual tabs. Depending on your needs, these features may be desirable. My initial goal was to try to determine what seemed like a minimal setup to provide the tabs functionality.


Now that I have this widget built, I can use it in several different ways that work well in my Backbone apps. It maintains the visual style to match other jQuery UI widgets I use on my pages and keeps the familiar jQuery call interface for creating and managing instances. By keeping it light-weight, it reduces the likelihood that the widget will behave in a way that doesn't work with the functionality I want to build. It seems that the jQuery UI widgets can be a great platform for building application. Sometimes, however, you may need to either tweak an existing component or build something similar to enable them to integrate better with Backbone.