I’ve been trying to get better at following the JQuery UI Theme styles – the fact of the matter is I’ve just never been great at writing fancy style sheets, so having a re-usable framework complete with fancy gradient backgrounds is awesome. However, I’ve always been frustrated by the lack of a good “container” skeleton widget in the standard toolkit. I decided to spend a little bit of time designing a panel widget that works on items with this structure:
$.widget('ui.panel', { options: { collapsable: true,
collapsed: false,
title: null,
barHeight: 29
}, defaults: { headerCss: 'ui-widget-header ui-corner-top ui-panel-header'
, contentsCss: 'ui-widget-content ui-corner-bottom ui-panel-content ui-helper-clearfix'
, panelCss: 'ui-widget ui-panel'
, showSpeed: 'slow'
, titleSelector: 'h1,h2,h3,h4,h5'
, titleTemplate: '<span />'
}, _create: function () { var buffer;
var self = this;
self.initialState = { }; // Parse attribute options
if (self.element.attr('collapsable') == 'false') self.options.collapsable = false;
if (self.element.attr('collapsed') == 'true') self.options.collapsable = true;
// Create the header div
self.header = $('<div class="' + self.defaults.headerCss + '" />'); // Look for an h element to rip out for the title. If it is a h1 or h2, increase the bar's height
self.initialState.header = self.element.children(self.defaults.titleSelector).first();
if (self.initialState.header.length == 1) { self.initialState.header.remove();
if (self.initialState.header[0].tagName == 'H1' || self.initialState.header[0].tagName == 'H2'
&& self.options.barHeight == 29)
self.options.barHeight = 49;
if (self.options.title == null)
self.options.title = self.initialState.header.text();
}
buffer = $(self.defaults.titleTemplate);
if (self.options.title != null)
buffer.text(self.options.title);
self.header.append(buffer);
// TODO: Create the collapsable div and wire it up
if (self.options.collapsable) { buffer = $("<a class='ui-panel-header ui-icon ui-icon-circle-triangle-n' href='javascript:void(0)'></a>"); buffer.bind('click', function() { self._trigger('toggle'); }); self.header.append(buffer);
}
// Create the content element and move original content into it.
self.contents = $('<div class="' + self.defaults.contentsCss + '" />'); self.contents.text(self.element.text());
self.element.text(''); self.element.children().appendTo(self.contents);
// Finally, add my panel class and throw everything into the document.
self.element.addClass(self.defaults.panelCss);
self.element.append(self.header);
self.element.append(self.contents);
self.element.bind('paneltoggle', function(event) { if (self.options.collapsed)
self.expand();
else
self.collapse();
return true;
});
self.element.bind('panelcollapse', function(event) { if (self.options.collapsed == false) { self.contents.hide(self.defaults.showSpeed,
function() { self.header.children('a').removeClass('ui-icon-circle-triangle-n') .addClass('ui-icon-circle-triangle-s'); });
self.options.collapsed = true;
}
return true;
});
self.element.bind('panelexpand', function(event) { if (self.options.collapsed) { self.contents.show(self.defaults.showSpeed,
function() { self.header.children('a').removeClass('ui-icon-circle-triangle-s') .addClass('ui-icon-circle-triangle-n'); });
self.options.collapsed = false;
}
return true;
});
}, expand: function () { this._trigger('expand'); }, collapse: function() { this._trigger('collapse'); }, destroy: function () { this.element.unbind('panelexpand panelcollapse'); // Return element to pre-widget state
this.header.remove();
this.contents.detach();
this.element.text(this.contents.text());
if (this.initialState.header != null)
this.element.append(this.initialState.header);
this.element.append(this.contents.children());
// Call base destructor
$.Widget.prototype.destroy.apply(this, arguments);
}});
$.extend($.ui.panel, { version: '@VERSION') });