RSpec: Simple Tests to Learn its Behavior

May 12, 2013 Leave a comment

Few people would argue that making it a point to ensure some level of testing is in place to verify that the functionality built works as expected is a bad practice. Size and complexity will typically dictate the testing philosophy used on a project. I tend to balance the effort required to build and maintain the automated tests versus the effort required to manually retest a module when a change is introduced. Fortunately, RSpec has a lot of power available for enabling reuse, readability, and, most importantly, brevity. All good things for developers trying to meet tight deadlines. Generally, I attempt to keep it as simple as possible by carefully orchestrating the basic let()/it() combined with good use of context to build most of my tests. Granted, when I wrote my first test, I was definitely fighting the expected philosophy of RSpec. Once I started to understand the behavior of each of its components, the pieces started falling into place and devising examples became a lot easier. Here’s a few of trials I used to gain more clarity around how the different components work together.

Using context to control scope

Context creates scope for the examples such that let() definition in other contexts can’t interact with the current context:

describe "let() scope" do

   # Visible to both context blocks
   let(:var1) { 3 }

   context "block 1" do
      # Only visible to this block
      let(:var2) { 5 }

      # Error
      specify { var3.should eq(7) }
      # Ok
      specify { var2.should eq(5) }
      specify { var1.should eq(3) }
   end

   context "block 2" do
      # Only visible to this block
      let(:var3) { 7 }

      # Error
      specify { var2.should eq(5) }
      # Ok
      specify { var3.should eq(7) }
      specify { var1.should eq(3) }
   end

end

Running this test results in these failures:


  1) let() scope block 1
     Failure/Error: specify { var3.should eq(7) }
     NameError:
       undefined local variable or method `var3' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0xb6b78ef8>
     # ./spec/test_spec.rb:14

  2) let() scope block 2
     Failure/Error: specify { var2.should eq(5) }
     NameError:
       undefined local variable or method `var2' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_2:0xb6b763d8>
     # ./spec/test_spec.rb:25

Redefine let() value

Define the value once and redefine it as necessary. Context blocks can work with the default or override it to something different for the given context without affecting another context:

describe "let() redefined" do

   let(:var1) { 3 }

   context "block 1" do
      let(:var1) { 5 }

      specify { var1.should eq(5) }
   end

   context "block 2" do
      let(:var1) { 7 }

      specify { var1.should eq(7) }
   end

   # Unaffected by block 1 and 2
   context "block 3" do
      specify { var1.should eq(3) }
   end
end

Cascading usage of let() values

Use previous let() values to define other values in a given context. This enables reuse and readability throughout the different contexts and examples:

describe "let() reuse" do

   let(:var1) { 3 }

   context "block 1" do
      let(:var2) { var1 + 5 }

      specify { var2.should eq(8) }
   end

   context "block 2" do
      let(:var2) { var1 + 7 }

      specify { var2.should eq(10) }
   end

end

Be aware of recursion

Values created by let() are really just methods which will be called when referenced. Trying to define the same value again by referencing itself will cause a recursion error:

describe "let() recusive" do

   let(:var1) { 3 }

   context "block 1" do
      # Fail
      let(:var1) { var1 + 5 }

      specify { var1.should eq(8) }
   end

end

You’ll see something like this. In more complex tests, these might be hard to find. Until it completely clicked what let() was really doing, I didn’t entirely realize what I had done:

  3) let() recusive block 1
     Failure/Error: let(:var1) { var1 + 5 }
     SystemStackError:
       stack level too deep

Obviously, these are quite simple. However, I keep a little scratch pad of simple examples that I can tinker with and try out ideas to see the behavior before trying it out in a larger, more complex test script. Once you start adding in a database environment, application state, etc, it becomes difficult to stay true to the simple principles available in the test suite. Sometimes, going back to basics allows you to see things more clearly and apply them in other contexts.

Categories: Tips & Techniques Tags: , , , ,

Adventures in OAuth for Securing REST API Services

May 7, 2013 1 comment

So you want to build a REST API that the rest of the world can use.  Maybe you have an internal application that can benefit from integrating with your external customers’ and vendors’ systems.  Even if the services you plan to build have no outside users, you may have internal groups that may need to consume these resources.  Clearly, securing these resources are a top priority and using an open standard has its many benefits over creating something proprietary.  However, once you take a precursory glance at OAuth, you realize there’s a lot more to it than some token exchanges and signatures.  In fact, there are more than one version floating around with various different flows depending on the type of entity trying to consume the service.  Feeling overwhelmed, you wonder if maybe just hacking together something that works for your specific solution will be adequate.  However, deep down inside you know it will come back to bite you if you go down that path.  And after all, your a software engineer, this should be in you wheelhouse, right?  So you hunker down and start reading…

Taking a Step Back

After reading a lot of articles, code, RFCs, and specific implementations (Yahoo, Google, Twitter, to name a few), I decided to try to decompose the problem into a few pieces:

  • Access Authorization – This is concerned with controlling access to the resources provided by the API. There are generally two levels of authorization:
    • Client – This level identifies the party authorized to access your services. The only context is the client and there is no user-based data available with this level of access. The purpose of this control is to be able to attach policies to the client with the intention of call limits, usage metering, and restricting the available services.
    • User/Owner – This level enables creating a context to provide access to user-based data. The purpose of this control is to ensure clients can only access user data that the owner of the data has explicitly granted access.  The process of granting/revoking access is not concerned with verifying the user’s identity.
  • Users Authentication – This is the process of verifying the user is actually owner of the data they want to access. Various strategies can be employed to verify the data owner’s identity.  Because it is typically involved in the authorization process, there is some level of coupling required to properly transition between the services and change state.
  • Request Verification – This area is concerned with ensuring that requests are authentic. The goal is to thwart attacks that might allow access to resources to another party than who should have the access.  This process can be difficult to implement since both the client and server libraries must agree on the strategy and it puts more burden on the server to maintain some state on prior requests.

A Closer Look

The next step is to look at existing standards to see how each problem is addressed.  Since OAuth is the predominant standard in use, its a good starting point.  You can argue over specifics of how version 1 or 2 do things better or worse but the primary concern I have is to look at how each area is addressed to try to establish a common denominator among solutions.

Authorization

Here’s a very typical flow for authorizing access to protect owner data.  The primary goal is not to reveal anything about the owner except what’s available through the scope defined in the final access key.  The combination of consumer/owner defines the relationship and level of access.  All the versions of OAuth define a authorization flow to gain access to protected user’s data.  While there are clear differences between flows, the main take-away is that this all boils down to three main steps: Initialize-> Authorize -> Finalize.

OAuth 1.0 Authentication Flow

Authentication

There’s nothing new about validating a user’s identity.  Just about every application does it and various strategies exist to perform this task.  What you end up with depends on the sensitivity of the data your protecting.  Keeping the details of how you protect accounts, manage passwords, and access rights should be neatly tucked away in this service.  It does need to be aware of an authorization request and properly affirming the authentication was successful so that process can continue.

Verification

It is important to verify the authenticity of each request made to your API.  Assuming that all inbound requests are original and not manipulated is naive.  OAuth 1.0 dedicates a large portion of the specification to constructing verifiable requests.  The burden is on the service provider to implement the strategies detailed in the specification.  Even if you chose to use another authorization solution (like OAuth2), adding a signature and nonce/timestamp to the request makes a lot of sense.  Granted, there is definitely some complexity and performance concerns with adding this layer of validation but all the effort in securing the authorization and validating the user’s credentials seems pointless if you don’t check that the requests being processed are even valid.

Putting It All Together

All three of these areas contribute to an overall solution to secure REST API services.  Depending on the version of OAuth you intend to use, the standard will address some, but not all of these areas.  The challenge is to architect a solution that properly distinguishes each mechanism and does overly couple each component to the other.  Additionally, since user interaction is implied in several of these areas, a presentation layer is necessary to enable user input.  In a pure services solution, these components will need to be properly separated to preserve the distinction between the control logic and the presentation.

After segmenting the solution into these different buckets, I’m still faced with realizing both server-side and client-side components to implement the different strategies.  As I’ve reviewed different solutions, most have the presentation is mixed with the services logic.  This has made it difficult to find solutions that can be readily plugged into my environment without compromising the architecture I’m trying to achieve.  My goal is to have this solution sit as an initial layer in front of both the client and server logic so its mostly transparent to the rest of the application but provides a very simple interface that can be used to verify the system is in the correct state for the given context (public vs private access, access scope, etc).  Ensuring that services are distinct from presentation is a top priority.  As a starting point, I’ve identified the following major components that need to be built or integrable off-the-shelf:

Client-side

Browser-based using a BackboneJS framework to consume REST API services and render presentation and manage user interaction.

  • OAuth Authorization Flow Controller – ensures all necessary access tokens are maintained, publishes some events, intercepts requests and adds necessary verification elements.
  • OAuth Adapters – implementation details for specific versions of OAuth and variations found in specific provider’s solutions.
  • URI and Verification Utilities – helper libraries that implement the low-level processing required in an OAuth-based solution.
  • Authentication Controller – implements a login/authorization page for use with both external and internal consumers

Server-side

Use a Ruby-based stack.  Two distinct servers – one to deliver assets to the browser-base client and the other to implement the REST API services.

  • OAuth Provider – expose services to implement the authorization flow
  • Identity/Authentication – expose services to provide user identify verification and information
  • OAuth Verification – rack middleware to verify request authenticity and setup the user context for all downstream handlers
  • Authorization Library – common interface for all service to interact with to manage state and provide information

All of these points are discussions within themselves and different solutions exist that can address each of them.  At this juncture, this is just a rough sketch of the direction that seems to make sense now.  The ultimate solution depends on the available tools and libraries that currently exist and finding an appropriate balance between how coupled the different parts of the solution need to be to retain maintainability and flexibility.

Until then, the adventure continues…

Filtering in Backbone: Let the Model Do the Work

April 28, 2013 Leave a comment

I had previously posted about different approaches to filtering Backbone collections. However, as I spent time trying to solve my problem I kept finding that the solutions did not offer the flexibility I needed. I liked the overall approach but felt that it might be better to decouple the collections of filters from the application of the filters. The solution I arrived at was to move the decision of whether a filter matched into the model. A controller pattern would tie the collection process to the application process to manage the different models and collections involved in the process.

Below is a simple example that illustrates the main points of the pattern:

  • The model contains all the logic to decide if it matches the provided selection criteria
  • There is a source collection that contains all the models that can be selected
  • A second collection is reset with the array of matching models returned by the source’s filter function
  • A controller manages the interactions between the different components

var Team = Backbone.Model.extend({

   defaults: {
      name: '',
      score: 0
   },

   selector: null,

   match: function ( select ) {
      this.selector = select;
      return this.get('score') > select.score;
   }
});

var Teams = = Backbone.Collection.extend({
   model: Team 
});

var selector = { score: 50 },
    source = new Teams([
              { name: 'Rockets', score: 27 },
              { name: 'Colts', score: 67 }, 
              { name: 'Giants', score: 55 } 
       ]),
    selected = new Teams(),
    matcher = function( model ) { return model.match(selector); };

selected.reset( source.filter(matcher) );

What I like about this approach is that the process of applying the filter is very simple and repeatable. The complexity can be deferred to the model which, as long as it understands the contents of the filter arguments, can be designed to test if it matches the selection criteria in whatever way is applicable to the target solution. It also leverages all the built-in functionality already available in Backbone which also reduces the amount of required code to build it. Finally, it has the added benefit of pushing the selector down to each model. This can come in handy later if you’d like to validate a model still matches when its updated or use it to format the attributes during rendering (ie highlighting matching text in a regex search).

Sometimes a bigger, more functional example helps solidify the idea. I built a tiny contact lookup list which has an input box to search all the available attributes in the model. You can filter by name, organization, phone, and email. The definition of the model has slightly more complex matching logic that will look for the provided search text in each of the four columns:


App.Models.Contact = Backbone.Model.extend({

   defaults: {
      display_name: '',
      organization: '',
      primary_email: '',
      primary_phone: ''
   },

   selector: null,

   match: function ( select ) {

      this.selector = select;

      return (
               select.search_text.length == 0 ||
               ( select.search_text.length > 0 &&
                 _.chain(
                   _.values(
                     _.pick(this.attributes, 'display_name', 'organization', 'primary_phone', 'primary_email')
                    )
                  )
                  .any(
                     function( s ) {
                           return s.toLowerCase().indexOf(select.search_text.toLowerCase()) > -1;
                        }
                     )
                  .value()
               )
              );
   }

});

Since this is searching several different columns, I’d like to highlight the search text where it was found in each item so the user can quickly see why it is included in the results. Since the formatting is injecting HTML content into the data, it doesn’t really belong in the model. However, since the model recorded the selector used to find it, the view that renders each item can use it to apply the formatting:

App.Views.ContactItem = Backbone.View.extend({

   template: null,

   tagName: 'ul',
   className: 'ui-list-item',

   initialize: function ( options ) {
      this.template = _.template($('#contact-item').html());
   },

   render: function () {

      this.$el.html(this.template( this.formattedJSON() ));

      this._super();

      return this;
   },

   formattedJSON: function () {

      var item = this.model,
          select = item.selector,
          data = item.toJSON(),
          check = new RegExp( $.ui.autocomplete.escapeRegex(select.search_text), 'i' );;

      if ( select.search_text.length > 0 ) {

         for ( var d in data ) {

            if ( data[d] && check.test(data[d]) ) {

               data[d] = data[d].replace(
                                    new RegExp(
                                        '(?![^&;]+;)(?!<[^<>]*)(' +
                                        $.ui.autocomplete.escapeRegex(select.search_text) +
                                        ')(?![^<>]*>)(?![^&;]+;)', "gi"),
                                        '<span class="ui-search-highlight">$1</span>');
            }
         }
      }

      return data;
   }

});

Now the whole thing can be wired up inside a controller object that will coordinated the views, models, and collections required to make it all work:


App.Controller = Controller.extend({

   filter: null,
   source: null,
   selected: null,

   container: null,

   layoutView: null,
   filterForm: null,
   resultList: null,

   initialize: function ( options ) {
      var options = options || {};

      this.container = options.container || 'body';
   },

   start: function () {

      this.source = new App.Collections.Contacts( localData );
      this.selected = new App.Collections.Contacts();
      this.filter = new Backbone.Model({ search_text: '' });

      this.layoutView = new App.Views.ContactLayout();
      this.filterForm = new App.Views.ContactFilter({ model: this.filter });
      this.resultList = new App.Views.ContactList({ collection: this.selected });

      $(this.container).append( this.layoutView.render().$el );
      this.layoutView.$('.ui-list-options').append( this.filterForm.render().$el );
      this.layoutView.$('.ui-list-content').append( this.resultList.render().$el );

      this.listenTo(this.filter, 'change', this.applyFilters);
   },

   applyFilters: function () {

      var selector = this.filter.toJSON();

      this.selected.reset( this.source.filter(function ( model ) {

            return model.match( selector );

         }));
   }

});

This controller is bit simplified but you can see the different elements of the pattern by keeping it flatten out. The filter is now a simple model that can be bound to an input box. By leveraging some autobinding magic, we can listen for changes to the filter model to trigger the actual filtering on the list.

This example only works with a small set of local data. It can be extended to query a remote data source. In that scenario, the source collection would be setup to fetch from the server under certain conditions to retrieve a larger dataset that can further be filtered locally. You can attach events to the source’s request and sync events to show/hide a wait spinner and rebuild the selected collection after the fetch is complete. The only other consideration worth noting is that the model assumes it will be a member in one filter collection. This might pose a problem is you are using multiple filtering collections that are not mutually exclusive. If that happens, you’d either need to record the context of the filter (which collection it came from) or find an alternative approach.

Programmatic Get/Set of jQuery UI Buttonsets and Checkbox/Radio Group Values

April 20, 2013 Leave a comment

I much prefer the look of a jQuery UI Buttonset over a list of radio buttons. Mixing Buttonsets with groups of check boxes enables a consistent look with easy control over the styling. However, if you need to manipulate the state of the underlying form controls, it becomes a little less clear how to handle that situation.

I’ve never been a fan of the inconsistent interface to getting/setting DOM form elements. jQuery only insulates us slightly from the problem. You can safely say $('input').val() and that will return the contents of the input box if its type is “text”. A check box or radio button don’t work the same way. Calling the val() function on one of these elements won’t tell you if its checked. Instead, it will return the value of the value attribute. The honor of determining the state of the check box or radio button is reserved for the prop() function. Using prop('checked') allows us to determine if a checkbox or radio button is checked. Additionally, jQuery sets up the handy :checked selector to find elements that are checked.

So how does this affect a Buttonset tied to a radio group? Knowing the above will allow you to interact with radio buttons programmatically like the Buttonset widget does internally. Since there is no value() function built in to the Buttonset widget, you have to write your own get/set function. After some trial and error, I found the following worked quite well:

<div id="mygroup">
   <input type="radio" name="mygroup" id="option1" value="1" /><label for="option1">Option 1</label>
   <input type="radio" name="mygroup" id="option2" value="2" /><label for="option2">Option 2</label>
   <input type="radio" name="mygroup" id="option3" value="3" /><label for="option3">Option 3</label>
</div>

The Buttonset widget needs a container element for the inputs it will manage. Additionally, each input needs a label element so the buttons render properly. The input attribute name="mygroup" establishes the radio group so the Buttonset will toggle the state correctly. Creating the Buttonset is easily done by selecting the containing div:

$('#mygroup').buttonset();

By itself, you don’t need to do anything else to interact with the group. However, if you need to manage it from code, you’ll need a get/set function to control it:

function myGroupVal( val ) {

    if ( typeof(val) != 'undefined' ) {
        
         $('#mygroup')
             .find('input')
                 .removeProp('checked')
                     .filter('[value="'+val+'"]')
                     .prop('checked', true)
                     .end()
                 .end()
             .buttonset('refresh');
        
    } else {
        return $('#mygroup').find(':checked').val();
    }
}

When setting the value, the Buttonset requires a refresh so it updates the state of the buttons that represent the underlying radio group. I like to set the value attribute on the individual radio inputs and use that as the actual value of the group.

Here’s a jsFiddle demo that uses an input box and some buttons to get/set the Buttonset.

Buttonset can also be used with check boxes such that more than one item can be selected at a time. The above example assumes only one item can be selected and ensures everything else is unchecked before checking the new item based on the passed value. For check boxes, you could work with an array of values to get/set such that more than one item could be checked at a time. Otherwise, as it stands now, the code will simply mimic a radio group even though the inputs are check boxes (try it).

Patterns for Filtered Collections in Backbone

April 17, 2013 1 comment
Master Collection and Filtered Subsets

Master Collection and Filtered Subsets

Most likely, you’ll have a need to filter the data in a collection. Although there are built-in filtering functions in the Backbone Collection object, they don’t affect the actual collection instance – just return an array of models. If you’re trying to filter the collection to cause a view to render the filtered set, you’ll need to put that array of models in another collection. It doesn’t make sense to reset the collection you filtered, you might want to clear the filter and go back to the original data set.

I’ve been playing with both Backbone Query and Backbone Subset to figure out what approach might work best for building a consistent, repeatable pattern for this problem.

Subset provides an all-in-one solution with the ability to create a Subset object from a source collection, add filters, and bind a view to the filtered collection available in the Subset model. Since the filters are a collection as well, you can bind them into a view and build a UI around them so your list of filtered items will update automatically.

Query doesn’t provide the same framework but does offer a more powerful filtering engine. Combining Subset and Query together would create a fairly powerful tool for extracting subsets of data from a primary source collection.

However, one size doesn’t always fit all. I had a case where the filters I wanted to allow entered from the UI did not map nicely on to the collection in Subset and the filtering logic needed to be implemented as a custom function passed to the Backbone Collection filter() function.

I do think the overall pattern defined by the Subset solution makes sense:

  1. Start with a container model, add a source collection, filter collection, and results collection
  2. Instance the container model with the source collection
  3. Bind the container to a view that will manage the filter and list views
  4. Have the container view instance and render the filter/list views binding in the corresponding collections from the container model
  5. Add appropriate handler logic to listen to filter changes, apply transforms, and filter the source to reset the result collection

The actual querying/filtering implementation depends on you needs. The setup is basically the same. Now you maintain one instance of all your models but can render multiple views of those models based on the application requirements.

Mixing jQuery UI Draggable, Droppable, and Sortable Interaction Widgets

April 9, 2013 Leave a comment

jqueryui-drag-drop-sort

The jQuery UI library provides quite a few useful mouse interaction widgets which make building solutions that need drag/drop functionality significantly easier. Most of them have the ability to integrate cleanly with each other which reduces the amount of “glue” code required to make these interaction work together. I’ve been working with the Sortable widget for some time now to enable my users to rearrange items in a list. One of the challenges I faced was how to design a consistent method of adding/removing items to/from the list via drag/drop interactions and provide meaningful feedback to the user. There are several pieces to making all the interactions work together harmoniously. The setup I’m presenting here takes into account not only the required functionality but also creating consistent styles and visual cues to guide the user’s interaction. There are probably other ways to handle it but this is the solution I’ve found that provides the most flexibility for my intended uses.

My basic approach is to have item instances available in a draggable widget. These can be move into a droppable widget or a sortable widget. Items from the sortable widget can be moved around as usual within the widget but also dragged out onto the droppable widget. When in sorting mode, I want the item to be constrained to the list, however, that would make it impossible to move the item out of the list to the droppable area. My solution was to create an area around the sortable item that is a separate drag area that would enable removing the item from the sortable area. This may not be necessary if you don’t care about constraining the item to the parent list. The item could just be dragged to the droppable area. However, I feel like having the two distinct modes of operation provides more flexibility in the design and an opportunity to provide better feedback to the user about the activity they are performing. The biggest advantage to using a separate draggable is that you can configure it completely different than the sortable’s drag configuration. Because of that flexibility, I went through the effort to find a way to combine the two together. The trick is to do it and not have one interfere with the operation of the other.

To achieve the solution outlined above, I started with the following basic item HTML:


 <div class="item-wrapper">
   <div class="drag-handle"></div>
   <div class="item-container">Item 1</div>
 </div>

Even though the .drag-handle is not a parent of the .item-container, it will be styled to appear that way:

jqueryui-drag-drop-sort-item-html

Technically, this arrangement is not necessary for differentiating the draggable/sortable behaviors. That can easily be achieved with the cancel option in the draggable configuration. However, if you want to toggle class styles when hovering over the different elements, you’ll have the most flexibility with the two elements being siblings instead of parent/child. Both the jQuery.hover() and hoverIntent use mouseenter and mouseleave events to trigger their handlers. These two events differ from the behavior of mouseover/out. Read the discussion in the jQuery Docs for more information. Given that I might use either hovering method to create cues for the user, using the sibling arrangement of the drag handle and item container works best.

The .item-wrapper will be the actual target for all drag operations. The children will be configured to act as handles to initiate the actual dragging. The styling is important to properly position the .drag-handle and .item-container:


.item-wrapper { 
   position: relative; 
   padding: 3px; 
}

.drag-handle { 
   position: absolute; 
   border: 3px solid transparent; 
   left: 0; 
   right: 0; 
   top: 0; 
   bottom: 0; 
}

.item-container { 
   position: relative; 
   text-align: center; 
}

The .item-wrapper has a 3px padding that matches the 3px border of the .drag-handle to create an area around the .item-container that will allow activating the draggable instead of the sortable operation. It will also have hovering events attached appropriately to enable styling visual cues for the user.

The next step is to create containers for each widget where the items can be held and moved around:


<div class="wrapper">

   <h5>Draggable</h5>
   <div class="drag-container ui-corner-all">
      ...
   </div>

   <h5>Droppable</h5>
   <div class="drop-container ui-corner-all">
      ...
   </div>

   <h5>Sortable</h5>
   <div class="sort-container ui-corner-all">
      ...
   </div>

</div>

At any given time, Draggable and Droppable will only have one item and Sortable can have N items. At page load, I setup four items – 3 in the Sortable container (labeled Item 1, Item 2, and Item 3), one in the Draggable container (labeled Item 4), and one in the Droppable container (labeled Empty). When you drag Item 4 from the Draggable and drop it in a valid container (either the Droppable or the Sortable), the item number will increase (so the Sortable/Droppable will now have Item 4 and the Draggable will show Item 5). Playing with the demo might make more sense and help clarify the remaining discussion.

First, we’ll configure the Draggable widget:


   $('.drag-container')
      .find('.item-wrapper').draggable({

         cursor: 'move',
         zIndex: 200,
         opacity: 0.75,
         scroll: false,
         containment: 'window',
         appendTo: document.body,
         helper: 'clone',
         connectToSortable: '.sort-container',
         start: fixHelper

      })

The most important part of this setup is the helper, connectToSortable, and start callback configuration items. The connectToSortable feature allows simple integration with a Sortable widget. You don’t need to do anything other than specify that argument and ensure the helper is equal to “clone”. I discuss the fixHelper() function later with the Sortable setup. I also skipped the hovering cues which I’ll cover later as well.

The droppable is pretty straight forward and just needs to handle the drop event:


   $('.drop-container').droppable({

         hoverClass: 'mx-content-hover',
         drop: function ( e, ui ) {

               $(this).find('.item-container').html( ui.draggable.children('.item-container').html() );

               if ( ui.draggable.parent().is('.drag-container') )
                  $('.drag-container .item-container').html('Item ' + (++items));
               else
                  // Defer removing the item after exiting the current call stack
                  // so the Draggable widget can complete the drag processing
                  setTimeout(function () { ui.draggable.remove(); }, 0);

            }
      });

In this case, it copies the HTML from the source item into the droppable’s item’s HTML. Additionally, it has to determine which container was the source of the drag. If its the Draggable, then the item count needs to be updated. If its the Sortable, then we want to remove the item from the list.

The Sortable configuration is a little more complex since it not only configures the Sortable interaction but also has to attach Draggable widgets to each item in the Sortable container. It has to configure the items both at page initialization and each time a new item is dragged into the list:


$('.sort-container')
      .sortable({

         containment: 'parent',
         handle: '.item-container',
         tolerance: 'pointer',
         helper: 'clone',
         start: fixHelper,
         update: /* see below */

   }).find('.item-wrapper')
      .draggable({
         cursor: 'move',
         zIndex: 200,
         opacity: 0.75,
         handle: '.drag-handle',
         scroll: false,
         containment: 'window',
         appendTo: document.body,
         helper: 'clone',
         start: fixHelper
      });

There are several things to note when looking at the configuration of the Sortable and the Draggables. First, both are targeting the same DOM elements – .item-container. Even though the Sortable is attached to the parent container, the drag operations are attached to its children (.item-container). Since this will cause issues if both the Sortable and Draggable try to respond to drag events on the same element, some of the other configuration options need to be used to restrict the scope of which part of the element each widget will respond to. This is achieved with the handle option in the Sortable and Draggable widgets:


$('.sort-container')
      .sortable({
         ...
         handle: '.item-container',
         ...
   }).find('.item-wrapper')
      .draggable({
         ...
         handle: '.drag-handle',
         ...
      });

Effectively, this limits the Sortable to responding to drag events on the .item-container element and Draggable will only listen to events on the .drag-handle. The final point of note on the setup is the helper configuration. It is set to “clone” and the start callback is used to normalize the cloned element across all the draggable widgets:


   function fixHelper( e, ui ) {

      var $ctr = $(this);

      ui.helper
         .addClass('mx-state-moving ui-corner-all')
         .outerWidth($ctr.outerWidth())
         .find('.mx-content-hover')
            .removeClass('mx-content-hover')
            .end();
   }

This ensures the cloned element doesn’t have any of the classes related to hover cues assigned, matches the width of the item as it appeared in the container, and adds a class to style the helper while moving:


.item-wrapper.mx-state-moving { 
   background-color: #fcefa1; 
   color: #000; 
   margin: 0; 
}

The final problem to manage in the Sortable is handling a new item from the Draggable. The Sortable will automatically add an item from the Draggable container due to the connectToSortable option in the Draggable configuration. However, if you need to perform additional handling on the new item, you’ll need to work with one of the callbacks to attach that functionality. This turned out to be a little more difficult than I expected. I was hoping to be able to detect that a drag operation was initiated by the Draggable (similar to how I did it in the Droppable) and also determine where the item was dropped in the Sortable. However, none of the callbacks provided all this information at the same time. In one case, the placeholder is available but the sender is not. The sender also seems to only work when the item is coming from another Sortable. To work around these issues, I decided not to include the .drag-handle element in the Draggable item. When its dropped on the Sortable, I can inspect the ui.item element in the Sortable update() callback to determine if its missing that element. If it is missing, then I know it came from the Draggable and I need to run the code to handle it. If it is not missing, then I know its a normal sort operation in the Sortable widget and no further processing is required:

$('.sort-container')
      .sortable({

   ...
   
   update: function ( e, ui ) {

         /* Check if the drag handle is missing */
         if ( ui.item.find('.drag-handle').length == 0 ) {
            
            /* It is so increment the item counter */
            $('.drag-container .item-container').html('Item ' + (++items));
            
            /* 
                And setup the item so it has a drag handle and
                responds to drag events
            */
            ui.item            
               .find('.item-container')
                  .before( $('<div class="drag-handle">') )
                  .parent()                  
               .draggable({
               
                     cursor: 'move',
                     zIndex: 200,
                     opacity: 0.75,
                     handle: '.drag-handle',
                     scroll: false,
                     containment: 'window',
                     appendTo: document.body,
                     helper: 'clone',
                     start: fixHelper
                     
                  });
            
            /* 
               Reset the containment.  Somehow it breaks when adding
               the external item 
            */
            $(this).sortable('option', 'containment', 'parent');
         }

      }
   
   ...
   
  });

That takes care of the dragging functionality. Now we need to add some visual cues when the user hovers over various areas that are draggable. I simply toggle a class on any target I’d like to enable hovering. This handler can be used in either the jQuery hover() or the hoverIntent plugin:

   function toggleHover( e ) {

      if ( e.type == 'mouseenter' )
         $(this).addClass( 'mx-content-hover' );
      else
         $(this).removeClass( 'mx-content-hover' );

   }

Next, we need to define styles for each hover target:


.drag-container .item-wrapper.mx-content-hover { 
   background-color: #cce0ff; 
   color: #000; 
}

.drop-container.mx-content-hover { 
   background-color: #ccff99; 
}

.sort-container .drag-handle.mx-content-hover { 
   border-color: #cce0ff; 
}

.sort-container .item-wrapper.mx-content-hover { 
   color: #000; 
}

Finally, the jQuery hover handler (or hoverIntent depending on if you’d like a delayed response) needs to be setup on all the hover targets so their classes can be toggled:


$('.drag-container')
   .find('.item-wrapper')
      .draggable(...)
      .hover( toggleHover );

$('.sort-container')
   .sortable(...)
   .find('.item-wrapper')
      .draggable(...)
      .hover( toggleHover )
      .find('.drag-handle')
         .hover( toggleHover );  

That covers my basic approach to assembling several jQuery interaction widgets together and leveraging their built-in functionality while still being able to enhance the functionality where needed. While its certainly not a one-size-fits-all solution, I’ve found that it serves as a nice pattern that can be used as a starting point for more elaborate designs.

Reviewing CSS Layout Techniques for Controling Content Size to Fit the Page

April 1, 2013 Leave a comment

Sometimes going back to basics is not a bad thing. Generally, I learn something new every time I start over. In this case, I decided to spend some time looking at how to improve/simplify setting up the basic layout I might use to build an application. When I think about the problems I need to consider when creating my layout, I generally can break them down into these basic issues:

  • Creating various “regions” to hold content that are either fixed or resize to fit the remaining space
  • Keeping all the content inside the viewable browser window bounds. Any scrolling will be dealt with inside the different content “regions”
  • Ensuring the desired layout works well with widget libraries like jQuery UI

I used the term “region” to be as generic as possible. These can mean columns, headers, rows, panels – anything that holds some functional part of the application. That can translate into menus, tables, toolboxes, or various other widgets. For this discussion, I chose a basic 3-column layout where the middle column expands to fill the remaining space not used by the two fixed outside columns. The whole layout should also fill the entire available space on the page (both height and width). I’m going to start by solving the columns layout, move to the height issue, and then review how adding several widgets might require additional tweaking.

Creating a 3-Column Layout

I’ve found several approaches for creating multi-column layouts with both fixed and fluid columns. For a 3-column setup, the most common are two fixed column (left and right) with a fluid middle column.

css-layout-3-columns-fixed-fluid-fixed

Most references use floating elements but I also saw solutions for absolute positioned elements. In the end, I chose to use absolute positioning. Others may be more comfortable with floats, however, I prefer avoiding them. The setup for the columns is fairly simple – set the left and right to the fixed amount and then set the left/right margin of the middle element to match. Then use absolute positioning to line each element up across the page. When you resize the page, the left/right stay constant and the middle will automatically fill the remaining space.

<div class="col-wrapper">

   <div class="col-left">
         <div class="col-content">
         </div>
   </div>

   <div class="col-mid">
         <div class="col-content">
         </div>
   </div>

   <div class="col-right">
         <div class="col-content">
         </div>
   </div>
</div>
.col-wrapper { 
   position: relative; 
   width: 100%; 
   font-size: 1.2em; 
}

.col-left, .col-mid, .col-right { 
   position: absolute; 
}

.col-left  { 
   left: 0;  
   width: 300px; 
   background-color: yellow; 
}

.col-mid   { 
   left: 0; 
   margin-left: 300px; 
   margin-right: 300px; 
   background-color: lightblue;
}

.col-right { 
   right: 0; 
   width: 300px; 
   background-color: pink; 
}

.col-content { 
   margin: 0.8em; 
}

Notice that .col-mid defines a margin the same size as the right/left width. The result looks like this page. That pattern will work well for 2 and 3-column layouts. Moving to four or more might pose a bigger challenge.

Filling the Available Height

So far, the content in the columns will flow down the page and the browser will scroll the whole view. In an application, this probably is not desirable since one region may contain a menu you want to remain in view when the user is scrolling through a list of data. This means you need to ensure you contain the content to the height and width of the browser. The width is generally easy to manage, block elements naturally fill the width of their parent – its the height that always causes problems. As much as I’d like to keep this a pure CSS solution, I’ve found that using a tiny bit of Javascript is really the best way to deal with the height. Not only can you set it when the page finishes loading, you can also reset it every time the browser window is resized:

$(function() {
   $(window).on('resize', function () {
         $('.col-wrapper').outerHeight($(window).outerHeight());
      }).trigger('resize');
});

This takes care of the outer wrapper for the columns, however, the individual columns are not sized to fill that height. The simple solution seems to just make the height equal 100%. Which will work until you add any margin or padding on the element that you set this way. Since the columns are just going to define the location of other elements and not anything more, I can safely use height: 100% in my style. However, the content inside those columns also needs to fill the space and have margin to create some white space. If I apply the 100% height rule to those element, I get this resulting layout. The goal is to get something that looks like this:

css-layout-full-height-columns

I stumbled upon a site with various HTML/CSS layout patterns. The one I found that solved the problem is named “Stretched” and used absolutely positioned elements with the left/right/top/bottom styles set to force the element to fill in the available space with the margin included in the calculation. This approach avoids the problem with the inner element overrunning the bounds of the parent element because the height/width is 100% and the margin/padding causes the element to push outside the parent. Applying that concept to my layout example fixes the problem and the content fits perfectly with the desired margins.

Adding Widgets to the Design

Now that we have the two main pieces to our layout, let’s try building something a little more useful. I took the same 3-column layout and added jQuery UI widgets to the different elements. One of the things to consider when doing this is that most of the widgets will add certain styles to the target elements (or even wrap them). These styles need to be accounted for in the layout so everything looks lined up and uncluttered (no extra borders, etc).

css-layout-full-height-columns-jqueryui

Before diving into specific issues related to the widgets, I factored out the important parts of the layout so it was reusable across anything I needed to use it with. The columns where in pretty good shape already, but the stretching styles can be separated into one class that can mixed with other class styles as needed:


/* Setup container to fill column area and not overflow the bounds */
.fill-box { 
   position: absolute; 
   height: auto; 
   top: 0; 
   bottom: 0; 
   left: 0; 
   right: 0; 
   overflow: hidden; 
}

As long as there is a relative parent, this will cause the target element to completely fill the available space created by the parent element. Other styles can define any margin/padding/border and not leave the bounding box.

Next we can add specific styles for each column. The left column will hold an Accordion widget which will have Draggable elements in each grouping. The middle will hold a Sortable widget that will also accept the Draggable elements, and the right column will hold some additional content to fill the space.


/* Define specific styles for each column container */
.toolbox { 
   margin: 5px; 
   margin-top: 3px; 
   padding-bottom: 1px; 
}

.sortable { 
   margin: 5px; 
   border: 1px solid #aaa; 
   overflow-y: auto; 
}

.content { 
   margin: 5px; 
   border: 1px solid #aaa; 
   padding: 5px; 
   overflow-y: auto; 
}

The markup has the normal column elements plus a container for the widgets. The sortable and content area do not need any other wrappers, however, the accordion does to ensure it sizes correctly. Without the extra DIV, it was cut off at the bottom.


<div class="column-wrapper">

   <div class="column-left">
      <div class="fill-box toolbox">
         <div> 
            /* Need to wrap the accordion so it sizes correctly */
            <h3>Stuff A</h3>
            <div>
               /* DIVs for the Draggable widget */
            </div>
            <h3>Stuff B</h3>
            <div>
               /* DIVs for the Draggable widget */
            </div>
            <h3>Stuff C</h3>
            <div>
               /* DIVs for the Draggable widget */
            </div>
         <div>
      </div>
   </div>

   <div class="column-middle">
      <div class="fill-box sortable ui-corner-all">
         /* DIVs for the Sortable widget */
      </div>
   </div>

   <div class="column-right">
      <div class="fill-box content ui-corner-all">
         /* Paragraphs of text */
      </div>
   </div>

</div>

Now, the code to initialize each widget may need to be modified to handle the sizing we would like. The Sortable doesn’t need any special consideration, however, both the Draggable and Accordion do require a few adjustments to account for the width/height we are targeting.

First, the accordion widget has a heightStyle which can be set to “fill” so the widget will match the height of its parent. This calculation is only done one upon initialization of the widget so any subsequent screen resizes will not cause the widget to fill the height properly. Since there is already a handler in place for the window resize, the accordion can be refreshed in that handler to resize it as well.

   /* Track the window height and set the outer column wrapper to match */
   $(window).on('resize', function () {
         $('.column-wrapper').outerHeight($(window).outerHeight());
         
         /* Make the accordion recalc the height */
         $('.toolbox > div').filter('.ui-accordion').accordion( 'refresh' );
      }).trigger('resize');

   $('.toolbox')
      .accordion({ heightStyle: 'fill' });

Next, the draggable needs some tweaking to move correctly from the accordion widget to the sortable widget. Whenever the source element is cloned to be dragged to the sortable, it will fill the width of the parent it will be appended to (it needs to be in the column-wrapper so it doesn’t get lost from the overflow). Since the helper can take a function, we can clone the element and set its width to match so it retains its size during the drag:

   $('.draggable')
      .draggable({
         connectToSortable: '.sortable',
         helper: function() {
               return $(this).clone().outerWidth($(this).outerWidth());
            },
         appendTo: '.column-wrapper'
      }).disableSelection();

This approach provides a reusable pattern for crafting sections of a page that require filling specific dimensions. Its repeatable from the top of the page all the way down to images and buttons. If you’ve been struggling trying to keep portions of your page fluid without having to manage it with code or hard-coded sizing rules, then some of the ideas here might make things a little easier.

Follow

Get every new post delivered to your Inbox.