Ajax Bestiary: A Javascript Field Guide
 
Ajax Bestiary: A Javascript Field Guide
 
 

Entries Tagged as 'Widget'

Hovercard – tooltips on steroids

Posted by Dave Mahon

Hovercard is a jQuery plugin that lets you hover what amounts to a tooltip. Except unlike your normal tooltip, this one supports event callbacks and lets you use arbitrary HTML and use as much space as you need.

They also provide support for Twitter and Facebook integration out of the box!

Suggested uses include virtual business cards, price comparisons and editing in place. Personally, my mind leaps to a web-based implementation of Civilization – it’s instant feedback on any cell in the world.

Check out their sample screenshot and imagine what you could do with it.
Hovercard Sample Screenshot

jQuery UI fixes: z-index and modals

Posted by Dave Mahon

jQuery UI is useful, but several of its widgets suffer from an annoying bug by design. If you never deal with simulated modal windows then you’ll never even experience it, but if you try to use an autocomplete or datepicker widget within a simulated modal window, you’ll find the dynamically generated DIV’s behind the modal.

You might try hardcoding a very high z-index to compensate for this, but it’s not terribly flexible, especially within a complicated third-party template.

That is why I now use this snippet in the beforeShow (date picker) or open (autocomplete) events, acquired from sources I no longer recall, to fix it.

function(input, inst) {
  var zMax = 1;
  $(input).parents().each(function(){
    zMax = Math.max(zMax, $(this).css('z-index'));
  });

  setTimeout(
    function() {
      $('.ui-datepicker .ui-autocomplete').css('z-index', zMax + 1);
    },
    300
  );
}

Sadly, the use of setTimeout() is necessary, because the event fires before the markup is appended to the DOM. You may be able to cut it down to about 150 ms, but that can sometimes fail in IE on slow machines.

jQuery Visualize: Progressive Enhancement for Charting

Posted by Don Albrecht

Progressive enhancement is a wonderful concept that we normally apply to the creation of increasingly rich behavior for our web applications.

For example:

  • The text field gets a client side validator
  • Search boxes gain an autocomplete
  • Enhancements appear when a user hovers over a link
  • Images gain zoom and pan.

The Filament Group has taken this transmogrification one step further with their impressive new visualize plugin for jQuery.

The basic usage is simple.  All you need to do is give it a well formed html table and call $(‘#tableid’).visualize() and a well formed chart will be appended to the html immediately after the table.

Read more about it here:

http://www.filamentgroup.com/lab/update_to_jquery_visualize_accessible_charts_with_html5_from_designing_with/

Getting and setting values for jQuery widgets

Posted by Dave Mahon

If you come from an OOP background you’re likely used to defining class variables like this:

class MyClass {
   var internalValue1;
   var internalValue2;
   function constructor() {}
}

The values which are to be stored in your object are simple, straightforward, likely to be typed, and the compiler will detect typos in the variable names. JavaScript, as a loosely types language which treats its objects more like collections than discrete objects, can’t really offer us those protections. Conversely, that also means that we have a great deal of flexibility.

In essence, we can dynamically subclass our objects, which you have to admit is a neat trick.

So, for jQuery.UI widgets, the variables stored within our widget are not defined until we assign them. The act of assignment defines the variable name, which can then be called upon at will.

Assignment is simply:

this._setData(‘variablename’, variablevalue);

Retrieval of this value is similarly straightforward:

this._getData(‘variablename’);

This does mean that the old problem of misnamed variables is alive and well. It also means that you need to be prepared to handle an undefined response to the _getData call.

Event handling in jQuery widgets

Posted by Dave Mahon

This is simple – provided you understand that the reference the keyword this refers to changes depending on when it is called.

When called during initialization, this refers to the widget you’re initializing. When the event itself is triggered, this refers to the DOM node node and not the widget.

As such, we need to introduce a new variable during initialization which the jQuery.UI library calls self which is, of course, equal to the initialization this, not triggered this. (Those of you familiar with Object Oriented Programming and by-reference calls should have no issue with this concept).

<$.widget("ui.clicker", {
   _init: function() {
      self = this;
      this.element.click(function() {
         self.increment(self);
         self.render();
      });
      this.render();
   },
   increment: function(target) {
      target.value(target.value()-1);
      //The exact handling of target.value will be shown another day
   },
   render: function() {
      this.element.text(this.value());
   },
   value: function(val) {}
});

You’ll note that we have to pass self to the increment method or the widget won’t actually be able to find itself, but the render method, which was called during initialization, is henceforth always able to correctly reference this (the widget)!

Helpful error handling in jQuery

Posted by Dave Mahon

If you’re going to build a reusable tool, you’re going to want to be able to detect, handle and report error messages in a nice, clean way. It will make you and any other dev happy.

The cleanest way of handling genuine errors for developers using your tool – namely, invalid input sent to a function in the library – is to log it to the console. Doing so is refreshingly straightforward:

var err = new Error();
err.name = "jQuery.widget.UI.clicker.range()";
err.message = "Both values must be numeric to assign range";
throw(err);

This snippet comes straight from the widget I threw together. I encourage you to make the name as detailed as possible. It will make debugging so much easier. You can even pinpoint the exact point of error if the problem was say, an invalid query syntax. (Handy during the development phase; not so much in a production environment!)

Custom stateful jQuery widgets

Posted by Dave Mahon

The widget library included in jQuery UI is pretty cool, but sometimes you need to roll your own custom object. If it didn’t have to be reusable, you could always just use a whole slew of bind methods on a specific page. Likewise, if network bandwidth and latency weren’t an issue, you could just store everything server-side and make heavy use of XmlHttpRequest.

Of course we don’t live in that ideal world and so we need to store data locally and our objects inevitably need to be reused. Enter the jQuery Widget Factory. This nifty feature set included in jQuery UI satisfies all of these needs.

Further, implementing custom widgets is pretty easy. First, we’ll initialize the widget:

$.widget('ui.widgetname', { _init: function() {} );

Then we’ll set any defaults:

$.ui.widgetname.defaults = {};

Obviously, this can and should be in its own file. Then on the specific web page, we can instantiate the widget:

$(target).widgetname();

This affords us the flexibility to reuse the widget multiple times on the same page and across pages and sites. Tomorrow we’ll start working up a rather basic example of this.

Before then, note that we use the widgetname consistently in its definition and instantiation, so choose the name wisely. Collisions in the $.ui namespace seem unlikely, but in very complex applications, that is always a possibility.

You’ll also note that in the widget’s definition we included only an _init function. This is the generic constructor for the widget and the only required method; feel free to add more as needed. The underscore prefix declares the method “private” and can be used to prefix any function in the widget declaration. This being JavaScript, we know that hidden named functions are quite impossible, but it does conceal the method from the now deprecated $(element).plugin('function').

A Great Pure CSS Timeline Implementation

Posted by Don Albrecht

Matt Bango has published a pretty awesome pure css timeline visualization.  Best part about it is that he’s documented it QUITE well.

Pure CSS Timeline

A few key concepts:

  • The width of the nodes is pre-populated in the CSS
  • The display is based on a pair of UL’s one for the timeline elements and one for the intervals at the bottom.
  • Width is allowed to be specified in a style attribute on the individual nodes

There’s some pretty clear opportunities to automate the creation of this widget in javascript that I hope to circle back to some day.  In the mean time, you can check out the article and demo here:

http://mattbango.com/notebook/web-development/pure-css-timeline/

Simile Timeline, An Advanced Timeline VIsualization

Posted by Don Albrecht

As Timelines go, this is probably the most advanced widget I’ve come across.  It’s designed to facilitate theming, huge time ranges, various levels of detail, large variations in resolution and even data mashups.

Simile Timeline

So, how does it work?

Reading through the project wiki, they call out the way individual lanes of the timeline are built in code.  It’s a well formed architecture so I thought I’d call it out as well.

  • The timeline is divided into bands.  Each band has its own data source (‘event source’) which allows for handy data mashups.
  • The band has its own ether, a map between pixel coordinates and dates / times.
  • The ether has a dedicated ether painter which is responsible for date / time rendering as well as background details and highlighting.
  • Decorators augment the background of the band
  • the bands event painter is owned by the band and responsible for the rendering of a bands events.

Check it out here:
http://www.simile-widgets.org/timeline/

You can also  read more about the architecture here:
http://code.google.com/p/simile-widgets/wiki/Timeline_Basics

 

YUI Calendar Popup from Text Input

Posted by Don Albrecht

I needed a way to provide my users with a date picker that was automatically provided when a text area received focus.  I was eager to use the excellent YUI calendar as a starting point, but the provided documentation didn’t provide a solid example for this type of implementation.

Dav Glass has provided a solid example of the Calendar tied to a text input. But, his example is highly dependent on the text input having specific ids.  This doesn’t take advantage of YUI’s excellent Selector library really didn’t meet my need for a simple universal solution.

Key Requirements:

  1. Progressive Enhancement (No inline javascript)
  2. Yui based
  3. Universal implementation across all pages in a site.
  4. Support for multiple date inputs on a page.

Getting Started:

The bulk of the code used is pretty solidly Dav’s I’ve simply replaced all of the hard coded references to dynamically generated targets and moved from hard coded ID’s for the target fields to a css class.  Lastly, I’ve added a “activeCal” class to the currently active target input so that one calendar can be recycled across multiple text areas on the page.

Source:

var cal1;
var over_cal = false;
function transmogCals() {
    cal1 = new YAHOO.widget.Calendar("cal1","cal1Container");
    cal1.selectEvent.subscribe(getDate, cal1, true);
    cal1.renderEvent.subscribe(setupListeners, cal1, true);
    var pickers =  YAHOO.util.Selector.query('.date-picker'); 
for( i in pickers){
    YAHOO.util.Event.addListener(pickers[i], 'focus', showCal);
    YAHOO.util.Event.addListener(pickers[i], 'blur', hideCal);
    }
cal1.render();
}
function setupListeners() {
    YAHOO.util.Event.addListener('cal1Container', 'mouseover', overCal);
    YAHOO.util.Event.addListener('cal1Container', 'mouseout', outCal);
}
function getDate() {
        var calDate = this.getSelectedDates()[0];
        calDate = (calDate.getMonth() + 1) + '/' + calDate.getDate() + '/' + calDate.getFullYear();
        YAHOO.util.Selector.query('.activeCal')[0].value = calDate;
        over_cal = false;
        hideCal();
}
function showCal(e, targ) {
    var xy = YAHOO.util.Dom.getXY(this);
    var el = new YAHOO.util.Element(this); 
    el.addClass('activeCal');
    var date = this.value;
    if (date) {
        cal1.cfg.setProperty('selected', date);
        cal1.cfg.setProperty('pagedate', new Date(date), true);
        cal1.render();
    }
    YAHOO.util.Dom.setStyle('cal1Container', 'display', 'block');
    xy[1] = xy[1] + 20;
    YAHOO.util.Dom.setXY('cal1Container', xy);
}
function hideCal() {
    if (!over_cal) {
         var el = new YAHOO.util.Element(this); 
        el.removeClass('activeCal');
        YAHOO.util.Dom.setStyle('cal1Container', 'display', 'none');
    }
}
function overCal() {
    over_cal = true;
}
function outCal() {
    over_cal = false;
}
YAHOO.util.Event.addListener(window, 'load', transmogCals);

 

Adding it to your page

Integrating the code into the page is VERY easy.

In the header of the page add the following css includes.

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/combo?2.6.0/build/calendar/assets/skins/sam/calendar.css">
In the footer add the following script include and include the date-picker.js file
<script type=“text/javascript” src=“http://yui.yahooapis.com/combo?2.6.0/build/yahoo-dom-event/yahoo-dom-event.js&2.6.0/build/calendar/calendar-min.js&2.6.0/build/selector/selector-beta-min.js”></script> 
Lastly, place a class of date-picker to any text fields you want to tie to the input and add the following to your pages markup:

 

<div class='yui-skin-sam' style="position:absolute; left:-1000px;">
     <div id="cal1Container"></div>
   </div>