If you find Layout useful and want to support its development...

UI Layout Support
Visit this group

Updated Oct 29, 2012

This is a temporary page to collect new features added in the Release Candidate versions for UI Layout 1.3.0.

I will add all the new features I can remember here for each RC version. When 1.3.0 Final is released, this information will be merged into the website documentation.


Latest Version: 1.3.0 RC-30.79

jquery.layout-1.3.0.rc30.79.js  -or- 

jquery.layout-1.3.0.rc30.79.min.js  -or- 

If you're not already using a 1.3.0.RC version of Layout, also download the newest layout stylesheet. This stylesheet is cosmetic and not required for Layout to work , but does provides useful samples and tips for styling a layout to achieve what you want. There are some changes in this regard from Layout 1.2.0...

* layout-default-latest.css


New in RC30.79

  • Changed [pane].state.css.width value from [pane].css("width") to [pane].width() for consistency with other CSS values provided to users. (not used internally)

New in RC30.78

  • Updated $.layout.browser so is no longer reliant on $.browser, which was removed in jQuery 1.9.
  • Adjusted layout errors so they do not add extra blank lines in the console-log.

New in RC30.77

  • Fixed bug in cookie 'expires' code that prevented cookies from saving
    (This bug first appeared in RC30.75)
  • Fixed bug with onload_start/end and onunload_start/end not firing
  • Update cssWidth/cssHeight methods so Layout now handles all possible box-sizing types.

    (Requires a version of jQuery that includes support.boxSizing data)

New in RC30.76

  • Fixed bug when a pane has initHidden: true
    (This bug first appeared in RC30.75)

New in RC30.75

  • Fixed bug when a pane is automatically closed onLoad due to insufficient room.
  • Fixed bug when a child-layout is destroyed and then the parent-pane is resized.
  • Fixed but when cookie is passed expiry-days as a string, eg: "30".
  • Add a new error message (log) when invalid pane-names are passed to methods.

New in RC30.74

Restored the functionality to load-state into an already existing layout. This now works with the cascading-state functionality added in RC30.7. So by setting/restoring state in the outer-layout, it will also restore the state of all child-layouts, provided the state-data exists for them and providing the option is set for this.

This demo has buttons at the bottom of the center-pane that will restore state to as it was when the page loaded, and can do so both with or without pane-animations...


New in RC30.73

  • Fixed effect syntax bug when using jQuery UI 1.8.23+. Effects logic now properly handles both the old and new UI syntax.
  • Added newSize, newWidth & newHeight state-values for use in onopen_start callbacks. These temporarly values indicate the size a pane will be once it opens.

New in RC30.72

  • Fixed logic bug in pane-masking so that panes could be resized in all directions.
  • Updated resize all method to allow dynamically changing the layout 'outset' option.
  • Added console.log output of the exception errors generated by layout callbacks.

New in RC30.71

  • Fixed double firing of callbacks when a layout is inside the content-div of its parent-pane.

New in RC30.7

Bug Fixes
  • Fixed bug that incorrectly enabled showDebugMessages when showErrorMessages was enable
  • Improved option parsing to allow unlimited mixing of sub-key & flat-format options.
  • Added background-color to transparent pane-masks to help resolve masking issues in IE.
  • Fixed misc syntax for compatibility with jQuery 1.8.
Misc. Changes
  • The options.[pane].autoResize option is now copied to state.[pane].autoResize. The state key will reflect is autoResize is still enabled (it's disabled by a manual resize).
  • Improved option parsing to allow unlimited mixing of sub-key & flat-format options.
  • Can now pass true to resizeAll() method to recalculate container insets. This allows changing insets on the fly, based on padding or new insets option (below). See buttons in demo: body_padding.html
  • Added 'forceResize' argument (optional) to sizePane() method: layout.sizePane( pane, size, skipCallback, noAnimation, forceResize )
    This is useful if you change the padding or border on a pane and need to force a box-model size recalculation.
New Layout-Container Functionality
  • Layouts on BODY element now respect margins, borders and paddings (padding-only in IE6). See demo: body_padding.html
  • New layout.insets option overrides container.padding CSS for specifying layout insets from container boundaries. (example below)
  • Scrolling (overflowX/Y) now set intelligently if container has minWidth and/or minHeight specified.
Child-Layout Changes

A number of enhancements were added to expand integration between parent and child (nested) layouts. This includes name changes to most child options and methods...

  • The syntax of child layouts has changed. The term "child" is no longer used in any options, instances, state or methods. Everything now uses the term "children" because the options & methods can always refer to one-or-more child-layouts.
  • So the options key "childOptions" is now just "children". This can be a single hash of options (as before), OR an array of hashes to define multiple child-layouts, like when using layouts inside tabs. The layout inside each tab-panel would be 'children' of the pane containing the tabs-widget.
  • NOTE: the backwards-compatibility module will automatically rename "childOptions" to "children", so your layouts should work without any changes. However if you are accessing methods, options or child-instances via code, then you must update it to the use the new names. Ask if you have any questions.
  • Layout can now manage multiple child-layouts per pane. For example, a set of 'tabs' inside a pane that each have a layout.
  • Options for child-layouts now include "containerSelector" This option allows tells layout where to find the child layout when it is not directly-nested inside the parent-pane.
  • Layout will initialize layouts in ALL child-containers that match containerSelector, using the same set of childOptions. (Must create additional children separately if they need different layout options.)
  • When setting child-options for a layout that is not directly nested, you must specify a 'containerSelector' so the parent layout knows how to find the child-layout-container. This selector should be valid relative to the outer-pane where you are specifying the child-options. Layout uses this syntax to find the child-container: $Pane.find( containerSelector )
  • By default, the creation, destruction and resizing of layouts cascades to all child-layouts. However you can disable cascading at any level by disabling any of these options in the parent-pane (all are true by default), eg:
    • initChildren: false
    • destroyChildren: false
    • resizeChildren: false
  • Layout will automatically detect child-layouts that are directly nested, even if the children are added after the parent -ayout is created. BUT, if you add a child-layout that is not directly-nested - like inside a tab-panel - then you can notify the parent-layout of the child, and pass a pointer to the child-instance so they can be linked...

    parentLayout.refreshChildren( "center", childLayoutInstance );

    (When using the special resizeTabs callback, you don't need to link the layouts - the callback handles it.)
  • You can also use refreshChildren to create child-layouts specified in the 'children' options after the parent has been created, by calling refresh without passing a child-instance, like...

    parentLayout.refreshChildren( "center" );

    This will cause layout to reprocess the 'children' options for the center-pane and try to create the layouts now.
  • The layout.refreshChildren( pane, newChild ) method is the RECOMMENDED METHOD to notify a parent layout about a manually created child-layout. Pass the newly created instance ('newChild') to the parent to connect them together.
  • The child-instance structure has also changed to accomodate multiple children per-pane. You now access a child like this: myLayout.children.center.layoutName (aka: layout.center.children.layoutName). EACH child-layout is a 'key' under children. Layout creates this key using this logic:
    1. options.stateManagement.cookie.name (cookie-name) – if exists
    2. options.name (layout-name) – if exists
    3. layoutN (eg: "layout1") – auto-generated key using sequential numbering
    These instance-names are also be used for stateManagement, so the layout-state can be related to the correct layout. See more info below.
New State Management Features

Layout's state-management can now handle an unlimited number of layouts in a single sated-state object. This means a parent layout can save and restore the states of all its child/nested layouts, and all their children. So if you have a page-layout with 12 nested layouts inside it, the page-layout can handle state-management for them all! Any 'branch' of layouts can be handled as a unit, and be disconnected from the state of its parents.

  • New layout.stateManagement.includeChildren option – default = true. When enabled, layout's state-management will include child-layouts when saving & restoring state. This option cascades to all child-layout unless specifically disabled in child's options.
  • When using cascading state-management, DO NOT enable stateManagement in the child-layouts. Enabling state-management for a child tells Layout that child will handle its own state.
  • So to STOP a child-layout from inheritting state, do either of these things:
    childOptions.stateManagement__enabled:  true – this layout will load & save its state separately
    childOptions.stateManagement__autoLoad: falseanything other than 'true'
  • The saved-state hash-structure has been extended to accomodate state for multiple children per-pane. The state object stores child-state like this: state.center.children.layoutName. EACH child-layout is a 'key' under children. Layout uses the same key as for the instance structure, described above.
  • If all layouts are created onLoad, then Layout will auto-generate layout names/keys and handle everything automatically. The same applies if layouts are added after load, but always created in the same order. Because keys are generated using sequential numbering, the keys in the saved-state will still match.
  • If your page creates child layouts dynamically (eg: using Ajax), then you should specify a 'name' (layout-name or cookie-name) for each dynamic layout to ensure the correct saved-state will be matched to that layout when it is created.
  • StateManagment.autoSave & StateManagment.autoLoad options are now multi-functional. Both options can now be callbacks for integrating custom state-management, so you no longer need to use the layout.onload and layout.onunload callbacks for this.
    • autoSave can be 'true' or a custom function that returns the state-data hash
    • autoLoad can be 'true', a custom function that returns a state-data hash, or BE a state-data hash that loads automatically with the layout.
      (Layout uses an autoLoad state-hash to pass state from parents to children.)
  • If a functions is set for autoSave or autoLoad, it is passed the same arguments as other layout callbacks.
Misc Internal Changes
  • Utility $.layout.getElementCSS is now $.layout.getElementStyles (for clarity)
  • $.config.[pane].side value is now lowercase (eg: "top" - not "Top")
  • layout.state.container now lists 'insets' in a hash like state.container.inset.top instead of individually like state.container.insetTop
  • New state-key: layout.state.container.isBody = true/false
  • layout.state.container.offetWidth/Height is now layout.state.container.layoutWidth/Height to avoid confusion with DOM properties. (These are used only to handle quirks-mode in IE.)
  • Changed the order of arguments on internal _sizePane() method to match external Instance.sizePane()
  • Added separate jQuery wrapper for plug-ins to ensure no sharing of internal vars.

New in RC30.62

Bug Fixes
  • Fixed bug triggered by code typo: if(":visible:")
  • Fixed incorrect resizer-tips being applied in open and closed states
  • Fixed internal utility that incorrectly applied a "display" style-rule to elements
  • Fixed regExp syntax used when reading options for trigger-events
  • Fixed undeclared variable to avoid creating a global var

New in RC30.61

Bug Fixes
  • Fixed box-model detection to work in both old and new versions of jQuery (IE bug)
  • Fixed/replaced old $.curCSS syntax that has been removed from jQuery
  • Fixed incorrect show-messages logic that caused debug messages to shown when option not enabled
  • Fixed incorrect pane-binding method name: "sizePane"
  • Fixed syntax error in enableSlidable method
  • Exposed showMasks() and hideMasks() methods on Layout instance object for use by custom code
  • Fixed syntax error in code that syncs pin-buttons with layout-state

New in RC30.6

Bug Fixes
  • Fixed bug triggered by a minWidth or minHeight on the center-pane
  • Fixed issue detecting quirks-mode and box-model issues
  • Fixed triggering for layout-events bound to the container element
  • Fixed bug where layout-event triggering cascaded to parent layout as well
  • Fixed variable name ('short') in callback code that prevented minification
  • Restored error-capture for invalid callbacks
New Language Options

Layout had multiple ways of changing the text used for tips and messages, which A) was somewhat confusing, and B) had some bugs. So the old $.layout.language functionality is now gone. All language settings are now part of the standard options. If you want to change the language settings globally, modify the global options.

Language options are in 2 separate subkeys of the options:

Developer Error Messages

Error messages are 'layout options'. There is no reason to customize these for each layout, so if you want to customize them for a language, this is best done by modifying the global default options. Below are the defaults:

$.layout.defaults = {
, errors: {
    pane:               "pane"      // "layout pane element" - used only in error messages
  , selector:           "selector"  // "jQuery-selector" - used only in error messages
  , addButtonError:     "Error Adding Button \n\nInvalid "
  , containerMissing:   "UI Layout Initialization Error\n\nThe specified layout-container does not exist."
  , centerPaneMissing:  "UI Layout Initialization Error\n\nThe center-pane element does not exist.\n\nThe center-pane is a required element."
  , noContainerHeight:  "UI Layout Initialization Warning\n\nThe layout-container \"CONTAINER\" has no height.\n\nTherefore the layout is 0-height and hence 'invisible'!"
  , callbackError:      "UI Layout Callback Error\n\nThe EVENT callback is not a valid function."

End-User Tips & Messages

The tooltips and alert for end-users are 'pane options', meaning they can be customized for each pane. By default all panes use the same tips – set in the 'panes' subkey. You can modify the global defaults, and the 'panes' default for each layout, and the settings for a specific pane if desired. Like all other options, the more specific settings will override the more general ones.

$.layout.defaults = {
, panes: {
  , tips: {
      Open:           "Open"    // eg: "Open Pane"
    , Close:          "Close"
    , Resize:         "Resize"
    , Slide:          "Slide Open"
    , Pin:            "Pin"
    , Unpin:          "Un-Pin"
    , noRoomToOpen:   "Not enough room to show this panel." // blank = no message
    , minSizeWarning: "Panel has reached its minimum size"  // statusbar message
    , maxSizeWarning: "Panel has reached its maximum size"  // ditto

NOTE that the tip-options that start with a capital letter (eg: Open, Close) should be specified with a capital letter (eg: Ouvrier, Fermier), unless you specifically want your tooltips to be displayed in all-lowercase.

The new language options replace both the $.layout.language object and the old 'tip' options. All the options listed below no longer exist. However Layout's backwards-compatibility module will automatically rename your old options to their new equivalents, which are also shown below:

 OLD Options       => NEW Options
 noRoomToOpenTip   => tips.noRoomToOpen
 togglerTip_open   => tips.Close
 togglerTip_closed => tips.Open
 resizerTip        => tips.Resize
 sliderTip         => tips.Slide

NOTE that the togglerTip_closed is equivalent to tips.Open. This is because the new options are based on the 'word meaning', where the old options were based on the 'current pane state'.

Here is a sample of how to customize the language in the layout options...

// flat-format option format
    panes__tips__Open:   "Ouvrier" // default for all panes in layout
,   panes__tips__Close:  "Fermier"
,   west__tips__Open:    "Ourvrier la Menu" // for west-pane only
,   west__tips__Close:   "Fermier la Menu"


// sub-key option format
    panes: { // defaults for all panes in layout
        tips: {
            Open:   "Ouvrier"
        ,   Close:  "Fermier"
,   west: {  // for west-pane only
        tips: {
            Open:   "Ouvrier la Menu"
        ,   Close:  "Fermier la Menu"


// flat-format and sub-key option formats combined
    panes__tips: { // defaults for all panes in layout
        Open:   "Ouvrier"
    ,   Close:  "Fermier"
,   west__tips: {  // for west-pane only
        Open:    "Ourvrier la Menu"
    ,   Close:   "Fermier la Menu"


New in RC30.5


This release enhances Layout's event model. The goal is to provide the full range of event, method, and callback features available in jQuery and jQuery UI widgets. Layout now has many, many more ways for interacting with layouts

This release also tweaks parent-child layout integration. Numerous layouts can now be specified as a single set of hierarchical options. Layout will automatically initialize each sub-layout in sequence, and link them all together for resizing and destruction (this can be overridden). The goal is to make a page full of nested layouts act as if they are one big layout, yet allow any part to be individually loaded, removed or manipulated.

Fixed pane-resizing bug when using percentage or 'auto' size settings

This fixed a bug that occurred under specific (rare) conditions that caused panes to not size to the correct size.

The "No center-pane found" message now obeys showErrorMessage option

Previously this error message would always appear when no center-pane was found, regardless how the showErrorMessage option was set. Now no message will appear if showErrorMessage=false, allowing for panes to be dynamically added without the user seeing an error.

NOTE: Setting showErrorMessage=false will prevent Layout from telling you when something is wrong! So do not set this option while creating and testing your layout. Enable it only when you are ready to make your layout public.

Refined linking of parent/child layouts

The RC30 series closely integrates parent/child layouts. A few tweaks were added to this logic to avoid circular references between parents and childs. So here are the basics:

  • A layout has direct references to child-layouts inside EACH of its panes
  • The child value for a pane is NULL if it does not have a child-layout
  • The property Instance.hasParentLayout equals 'true' if there is a parent layout
  • There is NOT a pointer to the parent-layout instance because this would create a never-ending circle of parent-child references. (stack-overflow bug fixed in RC30.3)
  • If an inner-layout is 'directly-nested' inside a parent layout, then you can get a pointer to the parent layout from container of the inner-layout, which is also a 'pane' in the outer-layout, eg: parentLayout = childLayout.container.data("parentLayout")
  • If an inner-layout is not 'directly-nested' you can find the parent-layout by searching for the 'containerClass' (default = "ui-layout-container"), eg: parentLayout = childLayout.container.closest(".ui-layout-container").
  • If layouts are not directly-nested, you can manually set a pointer to the child in the parent, and enable the hasParentLayout flag in the child. This will link the layouts so resize and destroy events cascade from parent to child.
// get the child layout nested inside the outer-center-pane
var childInstance = thisLayout.children.center;
var childInstance = thisLayout.center.child;

// get a layout nested 4 levels deep
var deepChild = outerLayout.west.child.north.child.center.child.north;
deepChild.close("west"); // close west-pane in nested layout

// see if a layout is nested inside another layout
if ( thisLayout.hasParentLayout ) {
    // find the parent-layout...

	// first get the 'container element' for this layout
    var $layoutContainer = thisLayout.container;
    // see if this layout is inside the 'pane' of a parent 
    var parentLayout = $layoutContainer.data("parentLayout");

    // if not directly-nested, must search up the DOM
    if ( !parentLayout ) {
        // find the closest layout-container wrapped around this one
        var $parentContainer = $layoutContainer.closest(".ui-layout-container");
        if ( $parentContainer.length )
            parentLayout = $parentContainer.data("layout");

    // trigger a resizeAll command on the parent-layout
    if (parentLayout)

This demo has options for 7 layouts specified inside a single set of options...

Child-Layout Create/Destroy Demo (nested_children.html)

It illustrates how parent/child layouts autotomatically link together for creation and destruction. It includes sample for how to create child layouts inside any element, not just a 'pane', eg:

//  this layout is inside the 'content-div' of the center-pane
,   center__childOptions: {
        name:  'middle-center'
        // no extras options required – handled automatically
//  this layout is inside a wrapper-div (NOT directly-nested)
,   east__childOptions: {
        name:  'middle-east'
    ,   containerSelector:  '> div' // first child-div of pane
New event-binding options on layout-elements

Previously layout event callbacks could only be set in the layout options, which also meant that each event could only have a single callback. This new binding option addresses both issues.

// bind an onopen callback to the west pane-element
$("body > .ui-layout-west").bind("layoutpaneonopen", function(){
    alert("west.onopen callback #1");
// bind ANOTHER onopen callback to the west pane-element
$("body > .ui-layout-west").bind("layoutpaneonopen", function(){
    alert("west.onopen callback #2");

// bind an onresizeall callback to the layout container-element
$("body").bind("layoutonresizeall", function(){
    alert("layout.onresizeall callback");

When using element binding, all 'pane event names' are prefixed with "layoutpane", and all 'layout event names' are prefixed with "layout". Callbacks bound this way work exactly like callbacks set in the options, including being passed the same set of parameters.

New method-triggering option on layout-container and layout-pane-elements.

Previously layout methods always had to be called using the layout-instance object. Now methods can be activated using the standard jQuery event-triggering syntax.

Method names use the same prefixes as the event-callbacks described above: Layout methods are prefixed with "layout" and pane methods are prefixed with "layoutpane". Following jQuery UI guidelines, methods names are all referenced in lower-case, even those that are normally in camel-case, eg: myLayout.resizeAll() => $pane.trigger("layoutresizeall")

Trigger the resizeAll method directly on the layout container element

Open the west pane by triggering the command directly on the pane
$("body > .ui-layout-west").trigger("layoutpaneopen");

Methods that contain the word "pane" have alternate versions without this redundancy, eg:

// normal/full method name
$("body > .ui-layout-west").trigger("layoutpaneremovepane");

// alternate/abbreviated method name
$("body > .ui-layout-west").trigger("layoutpaneremove");

If you need to pass one or more parameters to a layout method, put them in an array, per standard jQuery rules for trigger()...

// size pane to 200px
$("body > .ui-layout-west").trigger("layoutpaneremove", [ 200 ]);

// un-hide pane, and open it, with no animation
$("body > .ui-layout-west").trigger("layoutpaneshow", [ true, true ]);

Events triggered on layout elements DO NOT propagate/bubble-up, so triggering 'layoutpaneopen' on a pane in a nested-layout will not trigger an open event on the wrapping pane in the outer-layout.

When calling layout methods, a 'pane element' can be passed instead of a 'pane name'.

The new event model adds more flexibility in identifying panes to act on. You can now pass either the pane-name, the pane DOM-element, the pane as a jQuery object, or an 'event' triggered on the pane-element:

// these 5 'closePane' commands all work the same

// pane-name as a string

// pane as a DOM element
    myLayout.close( this );

// pane as a jQuery object
    myLayout.close( $(this).closest(".ui-layout-pane") );

// a 'click event' on a pane-element
$(".ui-layout-pane").click( myLayout.close );

// trigger method discussed in previous feature
Added new method to allow event callbacks to be manually triggered

A new layout.runCallbacks() method lets you trigger event callbacks for a specific event. This includes the callback set in the options plus any callbacks bound to the layout-element.

This is different from 'trigger events' as discussed above, because the runCallbacks method only runs the callback for an event – it does NOT trigger the event to occur. So calling myLayout.runCallbacks("onopen", "west") is NOT the same as myLayout.open("west"). The purpose of the runCallbacks method is to allow callbacks to be fired without an event trigger, which means you could run "onopen" callbacks a second time, which would not happen if you simply called open("west") a second time — that would do nothing since the pane is already open.

// trigger ALL west.onresize callbacks
myLayout.runCallbacks("onresize", "west");

// trigger ONLY the west.onresize callback set in 'options'
// ie, skip any callbacks set on the pane-element
myLayout.runCallbacks("onresize", "west", true);

This could be useful when manually manipulating content inside a pane, and then wanting Layout callbacks to reprocess the contents.

New way to access layout-pane properties and methods

Layout RC30 added new 'pane' aliases to the layout-instance object. These aliases provide access to the properties of a pane, eg:

var paneObject = myLayout.west;
// paneObject now contains this data
    name:     "west"
,   pane:     myLayout.panes.west     // pane element
,   content:  myLayout.content.west   // content-div element
,   options:  myLayout.options.west   // pane options
,   state:    myLayout.state.west     // pane state
,   child:    myLayout.children.west  // pane child-layout Instance

// can also get paneObect from the pane-element
var paneObject = $(".ui-layout-west").data("layoutPane");

The ability to get these pointers directly from the pane-element, without knowing the 'name' of the pane, makes writing generic functions much easier. For example:

// function to close a pane if current size is less than 200px
function closeSmallPane () {
    var layoutPane = $(this).data("layoutPane");
    if (layoutPane.name === "center")
        return; // skip center panes
    if ( layoutPane.state.size < 200 )

// bind generic function to event on ALL panes on page
$(".ui-layout-pane").mouseenter( closeSmallPane );

New in RC30.4

Tweaked state-data so onclose_open callback gets more accurate info.

This very minor update was added to coordinate with the pseudoClose 1.1 callback update. By returning more complete state-info about what the pane is doing, a pane's normal hide()/show() functionality can be used even when the pseudoClose callback is assigned.

Fixed in RC30.3

Fixed circular layout-pointer bug

Layout RC30 added pointers both from parent to children layouts and from child to parent layout. However this creates an infinite circle of references from parent to child to parent to child... To resolve this, the [layout-instance].parent pointer has been removed.

A new hasParentLayout flag has been added to layouts instead of a pointer to the parent layout:

// this sample assumes all layouts have already been created...

// GET the layout-instance of an inner-layout
var innerLayout = $("#innerContainer").data("layout");

if ( innerLayout.hasParentLayout ) {
    // we can get an instance of the parent-layout from the 
    // 'container' element of this child-layout
    var parentLayout = innerLayout.container.data("parentLayout");

    // we could also check that layout for a parent...
    if ( parentLayout.hasParentLayout ) {
        var grandparentLayout = parentLayout.container.data("parentLayout");
Fixed bug in disable-text-selection-while-resizing feature

Disabling text-selection relies on a jQuery UI utility, so this feature does not work without UI. Previously was generating an error in the console every time a Resizer-bar was hovered.

Remove hack used to work around Webkit rendering issue

There are certain circumstances where Webkit (Chrome specfically) does not render the screen as fast as the Javascript runs. One example is opening a popup window that has a layout. Even though the layout is created after document.ready, the BODY elements is detected 'not visible'. This causes Layout to abort because it cannot initialize within a hidden container.

The previous hack always added a delay for Chrome, but this meant Layout loaded asynchronously in Chrome. This can cause sequence-of-events issues in users' code. RC30.3 eliminates this and adds a delay only when the container is BODY (an outer-layout), and only if it does not load correctly the first time.

This issue can be seen in (some versions of) Chrome on this test-page: test_popup_window.html. You may have to try the popup a few times - the rendering bug is erratic!

New in RC30.2

Size-to-grid option

A new option was added that will cause manual resizing of panes to 'snap to a grid' of the size specified. This option is passed to the Draggable widget, which handles the snap-to-grid functionality. This is a pane-option, so can be set as a default or customized per-pane.

//  Enable snap-to-grid
,   west__resizingGrid: 20 // pixels - default = false (none)
Fix bug when sizing panes with a size-option of "100%" or -1

The sizing logic was not correctly handling 100% size options, causing the pane to be auto-sized rather than sized to 100% of available space. This was fixed.

New in RC30.1

WARNING: Do not implement this version in a live website or application without testing it.

I have tested this version thoroughly, but there are SO MANY changes that it is impossible to test every possible scenario. So for now this version should be treated as a "beta version". The RC29.15 version should be considered the "last stable version" until RC30 has been tested for a couple of weeks.

The RC30 series makes significant changes to Layout's internal structure. Most of these changes are backwards compatible, but a few minor tweaks to your options may be required to get things exactly as you want because a few 'defaults' have been changed.

GLOBAL Layout Options

Many more things are now exposed globally, including the default layout options. Here is how to set 'global default options' that will apply to all your layouts:

// IMPORTANT – always 'extend' the defaults - never 'replace' them!
$.extend( $.layout.defaults, {
    showErrorMessages:  false
    // NOTE the new 'panes' key - replaces 'defaults'
,   panes: {
        spacing_open:   10
    ,   togglerLength:  60
    ,   liveResizing:   true
,   north: {
        closable:       false
    ,   spacing_open:   0

OR by setting individual keys:
// change a 'layout option'
$.layout.defaults.showErrorMessages = false;
// change a 'default pane option'
$.layout.defaults.panes.liveResizing = true;

NOTE that the key for 'default pane-options' was renamed from "defaults" to "panes". This makes the key's purpose more clear and avoids confusing the pane-defaults key with $.layout.defaults, which is the top-level of the options.

Option Name Changes

A number of options have been renamed. Layout will still work with the old option names by automatically converting them to the new names on initialization, but it would be good for you to learn the new syntax. Here is a chart of all name recent changes:

OLD Option Name:             NEW Option Name
applyDefaultStyles:          applyDemoStyles
resizeNestedLayout:          resizeChildLayout
resizeWhileDragging:         livePaneResizing
resizeContentWhileDragging:  liveContentResizing
triggerEventsWhileDragging:  triggerEventsDuringLiveResize
maskIframesOnResize:         maskContents
useStateCookie:              stateManagement.enabled
cookie.autoLoad:             stateManagement.autoLoad
cookie.autoSave:             stateManagement.autoSave
cookie.keys:                 stateManagement.stateKeys
cookie.name:                 stateManagement.cookie.name
cookie.domain:               stateManagement.cookie.domain
cookie.path:                 stateManagement.cookie.path
cookie.expires:              stateManagement.cookie.expires
cookie.secure:               stateManagement.cookie.secure

You can access this list at a hash at: $.layout.backwardCompatibility.map

New & Updated Options

A number of new options were added, and the effect of some old options modified slightly. Rather than list only the changes, here is a COMPLETE LIST of all Layout options in RC30, with NEW options in red and RENAMED options in blue.
(if comments below are chopped off, see $.layout.defaults in the JS file to read the full comments)

// set pointer to language-defaults key - used for default-tips on each pane
var lang = $.layout.language;

$.layout.defaults = {
 *  - none of these options are applicable to individual panes
    name:                        ""          // Not required, but useful for buttons and used for the state-cookie
,   containerClass:              "ui-layout-container" // layout-container element
,   scrollToBookmarkOnLoad:      true        // after creating a layout, scroll to bookmark in URL (.../page.htm#myBookmark)
,   resizeWithWindow:            true        // bind thisLayout.resizeAll() to the window.resize event
,   resizeWithWindowDelay:       200         // delay calling resizeAll because makes window resizing very jerky
,   resizeWithWindowMaxDelay:    0           // 0 = none - force resize every XX ms while window is being resized
,   onresizeall_start:           null        // CALLBACK when resizeAll() STARTS    - NOT pane-specific
,   onresizeall_end:             null        // CALLBACK when resizeAll() ENDS    - NOT pane-specific
,   onload_start:                null        // CALLBACK when Layout inits - after options initialized, but before elements
,   onload_end:                  null        // CALLBACK when Layout inits - after EVERYTHING has been initialized
,   onunload_start:              null        // CALLBACK when Layout is destroyed OR onWindowUnload
,   onunload_end:                null        // CALLBACK when Layout is destroyed OR onWindowUnload
,   autoBindCustomButtons:       false       // search for buttons with ui-layout-button class and auto-bind them
,   initPanes:                   true        // false = DO NOT initialize the panes onLoad - will init later
,   showErrorMessages:           true        // enables fatal error messages to warn developers of common errors
,   showDebugMessages:           false       // display console-and-alert debug msgs - IF this Layout version _has_ debugging code!
//  Changing this zIndex value will cause other zIndex values to automatically change
,   zIndex:                      null        // the PANE zIndex - resizers and masks will be +1
//  DO NOT CHANGE the zIndex values below unless you clearly understand their relationships
,   zIndexes: {                              // set _default_ z-index values here...
        pane_normal:             0           // normal z-index for panes
    ,   content_mask:            1           // applied to overlays used to mask content INSIDE panes during resizing
    ,   resizer_normal:          2           // normal z-index for resizer-bars
    ,   pane_sliding:            100         // applied to *BOTH* the pane and its resizer when a pane is 'slid open'
    ,   pane_animate:            1000        // applied to the pane when being animated - not applied to the resizer
    ,   resizer_drag:            10000       // applied to the CLONED resizer-bar when being 'dragged'
 *  - settings under the 'panes' key become the default settings for *all panes*
 *  - ANY pane-option here can also be set for a specific pane, which will override the 'panes' value
,   panes: { // default options for 'all panes' - will be overridden by 'per-pane settings'
        applyDemoStyles:         false       // renamed from "applyDefaultStyles" for clarity
    ,   closable:                true        // pane can open & close
    ,   resizable:               true        // when open, pane can be resized 
    ,   slidable:                true        // when closed, pane can 'slide open' over other panes - closes on mouse-out
    ,   initClosed:              false       // true = init pane as 'closed'
    ,   initHidden:              false       // true = init pane as 'hidden' - no resizer-bar/spacing
    //, paneSelector:            ""          // MUST be pane-specific - jQuery selector for pane
    ,   findNestedContent:       false       // true = $P.find(contentSelector), false = $P.children(contentSelector)
    ,   contentSelector:         ".ui-layout-content" // INNER div/element to auto-size so only it scrolls, not the entire pane!
    ,   contentIgnoreSelector:   ".ui-layout-ignore"  // element(s) to 'ignore' when measuring 'content'
    //  GENERIC ROOT-CLASSES - for auto-generated classNames
    ,   paneClass:               "ui-layout-pane"     // Layout Pane
    ,   resizerClass:            "ui-layout-resizer"  // Resizer Bar
    ,   togglerClass:            "ui-layout-toggler"  // Toggler Button
    ,   buttonClass:             "ui-layout-button"   // CUSTOM Buttons    - eg: '[ui-layout-button]-toggle/-open/-close/-pin'
    //, size:                    100         // initial size of pane - normally should be pane-specific -
    ,   minSize:                 0           // limit when manually resizing a pane (height for N/S panes, width for E/W)
    ,   maxSize:                 0           // ditto, 0 = no limit
    ,   spacing_open:            6           // space between pane and adjacent panes - when pane is 'open'
    ,   spacing_closed:          6           // ditto - when pane is 'closed'
    ,   togglerLength_open:      50          // Length = WIDTH of toggler button on north/south sides - HEIGHT on east/west sides
    ,   togglerLength_closed:    50          // 100% OR -1 means 'full height/width of resizer bar' - 0 means 'hidden'
    ,   togglerAlign_open:       "center"    // top/left, bottom/right, center, OR...
    ,   togglerAlign_closed:     "center"    // 1 => nn = offset from top/left, -1 => -nn == offset from bottom/right
    ,   togglerTip_open:         lang.Close  // Toggler tool-tip (title)
    ,   togglerTip_closed:       lang.Open   // ditto
    ,   togglerContent_open:     ""          // text or HTML to put INSIDE the toggler
    ,   togglerContent_closed:   ""          // ditto
    ,   resizerDblClickToggle:   true        // true = double-clicking anywhere on the resizer-bar will toggle the pane open/closed
    ,   autoResize:              true        // IF size is 'auto' or a percentage, then recalc 'pixel size' whenever the layout resizes
    ,   autoReopen:              true        // IF a pane was auto-closed due to noRoom, reopen it when there is room? False = leave it closed
    ,   resizerDragOpacity:      1           // option for ui.draggable
    //, resizerCursor:           ""          // MUST be pane-specific - cursor when over resizer-bar
    ,   maskContents:            false       // true = add DIV-mask over-or-inside this pane so can 'drag' over IFRAMES
    ,   maskObjects:             false       // true = add IFRAME-mask over-or-inside this pane to cover objects/applets - content-mask will overlay this mask
    ,   maskZindex:              null        // will override zIndexes.content_mask if specified - not applicable to iframe-panes
    ,   livePaneResizing:        false       // true = LIVE Resizing as resizer is dragged
    ,   liveContentResizing:     false       // true = re-measure header/footer heights as resizer is dragged
    ,   liveResizingTolerance:   1           // how many px change before pane resizes, to control performance
    //  TIPS & MESSAGES - global defaults from $.layout.language (lang)
    ,   noRoomToOpenTip:         lang.noRoomToOpenTip
    ,   resizerTip:              lang.Resize // Resizer tool-tip (title)
    ,   sliderTip:               lang.Slide  // resizer-bar triggers 'sliding' when pane is closed
    ,   sliderCursor:            "pointer"   // cursor when resizer-bar will trigger 'sliding'
    ,   slideTrigger_open:       "click"     // click, dblclick, mouseenter
    ,   slideTrigger_close:      "mouseleave"// click, mouseleave
    ,   slideDelay_open:         300         // applies only for mouseenter event - 0 = instant open
    ,   slideDelay_close:        300         // applies only for mouseleave event (300ms is the minimum!)
    ,   hideTogglerOnSlide:      false       // when pane is slid-open, should the toggler show?
    ,   preventQuickSlideClose:  $.layout.browser.webkit // handle problem when Chrome triggers slideClosed as it is opening
    ,   preventPrematureSlideClose: false     // handle incorrect mouseleave trigger, like when over an open SELECT field in IE
    //  HOT-KEYS & MISC
    ,   showOverflowOnHover:     false       // will bind allowOverflow() utility to pane.onMouseOver
    ,   enableCursorHotkey:      true        // enabled 'cursor' hotkeys
    //, customHotkey:            ""          // MUST be pane-specific - EITHER a charCode OR a character
    ,   customHotkeyModifier:    "SHIFT"     // either 'SHIFT', 'CTRL' or 'CTRL+SHIFT' - NOT 'ALT'
    ,   fxName:                  "slide"     // ('none' or blank), slide, drop, scale -- only relevant to 'open' & 'close', NOT 'size'
    ,   fxSpeed:                 null        // slow, normal, fast, 200, nnn - if passed, will OVERRIDE fxSettings.duration
    ,   fxSettings:              {}          // can be passed, eg: { easing: "easeOutBounce", duration: 1500 }
    ,   fxOpacityFix:            true        // tries to fix opacity in IE to restore anti-aliasing after animation
    ,   animatePaneSizing:       false       // true = animate resizing when sizePane() is called - not applicable to drag-resizing
    /*  NOTE: Action-specific FX options are auto-generated from the options above if not specifically set:
    ,   fxName_open:             "slide"     // 'Open' pane animation
    ,   fnName_close:            "slide"     // 'Close' pane animation
    ,   fxName_size:             "slide"     // 'Size' pane animation - when animatePaneSizing = true
    ,   fxSpeed_open:            null
    ,   fxSpeed_close:           null
    ,   fxSpeed_size:            null
    ,   fxSettings_open:         {}
    ,   fxSettings_close:        {}
    ,   fxSettings_size:         {}
    ,   childOptions:            null        // Layout-options for nested/child layout - even {} is valid as options
    ,   initChildLayout:         true        // true = child layout will be created as soon as _this_ layout completes initialization
    ,   destroyChildLayout:      true        // true = destroy child-layout if this layout is destroyed
    ,   resizeChildLayout:       true        // true = trigger child-layout.resizeAll() when this pane is resized
    ,   triggerEventsOnLoad:     false        // true = trigger onopen OR onclose callbacks when layout initializes
    ,   triggerEventsDuringLiveResize: true    // true = trigger onresize callback REPEATEDLY if livePaneResizing==true
    ,   onshow_start:            null        // CALLBACK when pane STARTS to Show    - BEFORE onopen/onhide_start
    ,   onshow_end:              null        // CALLBACK when pane ENDS being Shown    - AFTER  onopen/onhide_end
    ,   onhide_start:            null        // CALLBACK when pane STARTS to Close    - BEFORE onclose_start
    ,   onhide_end:              null        // CALLBACK when pane ENDS being Closed    - AFTER  onclose_end
    ,   onopen_start:            null        // CALLBACK when pane STARTS to Open
    ,   onopen_end:              null        // CALLBACK when pane ENDS being Opened
    ,   onclose_start:           null        // CALLBACK when pane STARTS to Close
    ,   onclose_end:             null        // CALLBACK when pane ENDS being Closed
    ,   onresize_start:          null        // CALLBACK when pane STARTS being Resized ***FOR ANY REASON***
    ,   onresize_end:            null        // CALLBACK when pane ENDS being Resized ***FOR ANY REASON***
    ,   onsizecontent_start:     null        // CALLBACK when sizing of content-element STARTS
    ,   onsizecontent_end:       null        // CALLBACK when sizing of content-element ENDS
    ,   onswap_start:            null        // CALLBACK when pane STARTS to Swap
    ,   onswap_end:              null        // CALLBACK when pane ENDS being Swapped
    ,   ondrag_start:            null        // CALLBACK when pane STARTS being ***MANUALLY*** Resized
    ,   ondrag_end:              null        // CALLBACK when pane ENDS being ***MANUALLY*** Resized
 *  - options listed below MUST be specified per-pane - they CANNOT be set under 'panes'
 *  - all options under the 'panes' key can also be set specifically for any pane
 *  - most options under the 'panes' key apply only to 'border-panes' - NOT the the center-pane
,   north: {
        paneSelector:            ".ui-layout-north"
    ,   size:                    "auto"      // eg: "auto", "30%", .30, 200
    ,   resizerCursor:           "n-resize"  // custom = url(myCursor.cur)
    ,   customHotkey:            ""          // EITHER a charCode (43) OR a character ("o")
,   south: {
        paneSelector:            ".ui-layout-south"
    ,   size:                    "auto"
    ,   resizerCursor:           "s-resize"
    ,   customHotkey:            ""
,   east: {
        paneSelector:            ".ui-layout-east"
    ,   size:                    200
    ,   resizerCursor:           "e-resize"
    ,   customHotkey:            ""
,   west: {
        paneSelector:            ".ui-layout-west"
    ,   size:                    200
    ,   resizerCursor:           "w-resize"
    ,   customHotkey:            ""
,   center: {
        paneSelector:            ".ui-layout-center"
    ,   minWidth:                0
    ,   minHeight:               0

NOTE that the options above do not include state-management, cookie or button options. These features are now layout plug-ins, so their options exist only if related plug-ins is loaded. For example, the layout.state plug-in will add a 'stateManagment' key to the defaults, which contains all the options specific to state-management, including cookie options. You can set all plug-in defaults globally within $layout.defaults, and specifically using your normal layout options. See the info on each plug-in below for a list of the options each will add.

New Child Layout Features

Layout 1.3 has new options that make it more seamless to integrate multi-level layouts:

,   childOptions:       null // Layout-options for nested/child layout - even {} is valid as options
,   initChildLayout:    true // true = child layout will be created as soon as _this_ layout completes initialization
,   destroyChildLayout: true // true = destroy child-layout if this layout is destroyed
,   resizeChildLayout:  true // true = trigger child-layout.resizeAll() when this pane is resized

All these options are new except resizeChildLayout, which was previously named "resizeNestedLayout". Below is a summary of the new functionality and versatility these options provide:

Can now include the 'options' for ALL child-layouts within the options of the pane in the outer-layout that contains the innerLayout. In other words, all the options for both the outer-most layout and all child/nested layouts it contains can now be specified in a single options hash - if desired. Here's a sample showing the options for a page layout that contains child-layouts:

// page layout options PLUS options for 5 nested layout - 2-levels deep
$("body").layout({ // page layout - outer-most layout
    name:            "page"

    panes: {                       // page layout -> pane-defaults
        spacing_open:    0

,   center: {                      // page layout -> center-pane
        minWidth:    400
    ,   minHeight:   300
        // 2nd level layout inside this center-pane
    ,   childOptions: {
            name:        "page_center"
        ,   resizable:   false
        ,   center: {              // page_center layout -> center-pane
                // 3rd level layout inside this center-pane
                childOptions: {
                    name:    "page_center_center"
                ,   west: {        //  layout -> center-pane
                        closable:  false
        ,   west: {                // page_center layout -> west-pane
                // 3rd level layout inside this west-pane
                childOptions: {
                    name:    "page_center_west"
                ,   panes: {       // page_center_west layout -> pane-defaults
                        closable:  false

,   east: {                        // page layout -> east-pane
        // 2nd level layout inside this east-pane
        childOptions: {
            name:      "page_east"
        ,   panes: {               // page_east layout -> pane-defaults
                closable:  false
	    ,   center: {
                // 3rd level layout inside this center-pane
                childOptions: {
                    name:    "page_east_center"
                ,   panes: {       // page_east_center layout -> pane-defaults
                        spacing_open:  0


Child Layouts can also be created by assigning various option hashes:

// layout options common to both east & west sidebars
var sidebarLayoutOptions = {
    resizable:     false
,   closable:      false
,   spacing_open:  0

// layout options for 3rd level layout (page -> center -> center)
var pageCenterCenterLayoutOptions = {
    spacing_open:  0

// layout options for 2nd level layout (page -> center)
var pageCenterLayoutOptions = {
    spacing_open:         0
,   center__childOptions: pageCenterCenterLayoutOptions

// page layout options PLUS options for 5 nested layout - 2-levels deep
$("body").layout({ // page layout - outer-most layout
    name:         "page"
    panes: {                       // page layout -> pane-defaults
        spacing_open:  0
,   center: {                      // page layout -> east-pane
        minWidth:      400
    ,   minHeight:     300
        // 2nd AND 3rd level layouts inside this center-pane
        childOptions:  pageCenterLayoutOptions
,   west: {                        // page layout -> center-pane
        minSize:       150
        // 2nd level layout inside this west-pane
    ,   childOptions:  sidebarLayoutOptions
,   east: {                        // page layout -> center-pane
        minSize:       150
        // 2nd level layout inside this east-pane
    ,   childOptions:  sidebarLayoutOptions
How Child Layouts Work

Layout has always had child layouts, and the functionality of this does not change. The only change is tighter and easier integration between parent & child layouts.

If you use the methods above to assign child layouts, an 'Instance pointer' is automatically created in the parent layout to the child layout. For example, if there is a child-layout inside the center-pane of the outer-layout, you can access the child layout like so:

// create the outer-layout with a child-layout inside the center-pane
var outerLayout = $("body").layout({
    name:            "page"
,   center: {
        // 2nd level layout inside this center-pane
    ,   childOptions: {
            name:        "page_center"
        ,   resizable:   false

access the child-layout through the 'children' hash in the outer-layout
var innerLayout = outerLayout.children.center;

access the child-layout through the 'center' hash in the outer-layout
var innerLayout = outerLayout.center.child;

Even if you do not use the child-options feature and create child layouts individually, Layout will still create an instance-pointer to the child layout - if the child-layout has the outer-pane as its 'container' element.

You can also specifically assign one layout as the child of another, like so:

// create the outer-layout
var outerLayout = $("body").layout();

// create a layout inside a descendant element - and set it as a 'child' of outLayout->center
outerLayout.children.center = $("#wrapper").layout();
outerLayout.center.child = $("#wrapper").layout();

Initialization of child layouts is automatic - unless you set the option initChildLayout=false (this can be set for each pane). Destruction of child layouts is also automatic, unless you set the option destroyChildLayout=false. This means that an entire page of layouts can be created or destroyed with a single command, as long as the child-layouts are associated with their parent pane.

// Child-Access Method #1
// access the child-layout through the 'children' hash in the outer-layout
var innerLayout = outerLayout.children.center;

// Child-Access Method #2
// access the child-layout through the 'center' alias in the outer-layout
var innerLayout = outerLayout.center.child;

// Access layouts multiple-levels deep
var pageLayout = $("body").layout(); // get layout-instance
// find a layout nested 3-levels deep inside the page-layout
var deepLayout = pageLayout.center.child.west.child.north.child;
New Layout 'parent' key

Along with the new 'children' key, layouts also have a new 'parent' key. If the layout can determine that it is a child of another layout, a pointer to the parent-layout is set in the [Instance].parent key. For example:

// assuming all layouts have already been initialized...
var innerLayout  = $("#innerContainer).layout(); // get inner-layout 'instance'
var parentLayout = innerLayout.parent; // get parent-layout 'instance'

It is rare that you should ever need to access a parent-layout, but this key is provided as a compliment to the 'children' key. Note that this doesn't tell you which 'pane' of the parent-layout the innerLayout is inside.

New Pane-Alias Keys in Layout Instance

As indicated above, the layout instance-object now includes a key for each pane in the layout. These keys provide an alternate method for acessing pane-specific data: 'children', 'options' & 'state':

// get the layout instance
var myLayout = $("body").layout();

// standard method for accessing pane-specific data
var options  = myLayout.options.west;
var state    = myLayout.state.west;
var children = myLayout.children.west;

// alternate method for accessing pane-specific data
var options  = myLayout.west.options;
var state    = myLayout.west.state;
var children = myLayout.west.children;

// or using more compact syntax
var west     = myLayout.west;
var options  = west.options;
var state    = west.state;
var children = west.children;

These new aliases can be useful for writing clearer code, especially in generic functions.

New Pane Masking Options

Layout has long had a masking option intended to mask iframes so that it's possible to drag the resizers over top of them. However the masking DIV used does not work for 'objects', like video players, Google maps, applets, etc. So this version add an updated masking system that can also mask these objects.

,   maskContents: false  // true = add DIV-mask over-or-inside this pane so can 'drag' over IFRAMES
,   maskObjects:  false  // true = add IFRAME-mask over-or-inside this pane to cover objects/applets - content-mask will overlay this mask
,   maskZindex:   null   // will override zIndexes.content_mask if specified - not applicable to iframe-panes

The old "maskIframesOnResize" option is now "maskContents". Enabling this option is sufficient to handle iframes and anything else other the applets/objects. If you have an object that needs masking, also enable the maskObjects option. The object mask works by covering the pane with a transparent iframe. In some browsers this makes the object 'disappear', and in others it doesn't. But the objects is effectively masked for Layout's needs regardless whether it is still visible or not. When the object mask is used, the content mask (a transparent DIV) is also used, because the transparent iframe must also be masked!

The only time the maskZindex option needs to be changed is if you have elements inside the pane that have a high zIndex applied. In this case, the maskZindex should be set so it is 'higher' than any other element inside the pane it is masking.

New Plug-in Architecture

Layout now has a flexible plug-in system. Plug-ins can be integrated with important layout events, and can extend the default options (not all plug-ins have options).

Using this new capability, all 'extra features' have been removed from the Layout core and moved into plug-ins. These plug-ins include:

  • State Management — Same features as state-management in RC29, but with some option name-changes.
  • Custom Button Binding — Same features as state-management in RC29, but with some option name-changes.
  • State Management — Same features as state-management in RC29, but with some option name-changes.

For now, ALL plug-ins are bundles in the same JS file as the core Layout plug-in. This provides full backwards compatibility and simplifies downloading. Eventually I'll add a 'builder' to the website so you can choose which plug-ins (and callbacks) you want, and only those will be bundled into the download file – similar to how jQuery UI downloads work. (Custom callbacks are NOT currently included inside the core Layout file.)

New Layout Plugin Architecture

Layout now has a plugins systems. Layout options and other data is now easy to extend, and a number of event-arrays have been provides so plugins can hook into events easily. When a plugin is loaded, it extends Layout's functionality. The plugin is automatically available to _all_ layouts on the page, though many plugins have options to enable or disable their features.

Plugins JS files be loaded AFTER the layout file is loaded. However in RC301.1, I have included all plugins inside the main Layout file , so there is not need to load extra files.

You can test whether a plugin is loaded by checking the $.layout.plugins hash. Each plugin will add a key here to indicate that it has loaded. So you can do check like this:

    if ( $.layout.plugins.stateManagement ) {
State Management Plugin

This plug-in has the same functionality as state-management in previous version, however the options have been reorganized so that all related options now fall under the key added by the plugin:

$.layout.defaults.stateManagement = {
    enabled:      false // true = enable state-management, even if not using cookies
,   autoSave:     true  // Save a state-cookie when page exits?
,   autoLoad:     true  // Load the state-cookie when Layout inits?
    // List state-data to save - must be pane-specific
,   stateKeys:    "north.size,south.size,east.size,west.size,"+
,   cookie: {
        name:     ""    // If not specified, will use Layout.name if set, else just "Layout"
    ,   domain:   ""    // blank = current domain
    ,   path:     ""    // blank = current page, '/' = entire website
    ,   expires:  ""    // blank = session, Date = expiry date, n>0 = days, null/0/n<0 = delete
    ,   secure:   false // true = use cookie only for HTTPS pages - always encrypted

Button Binding Plugin



Change in how '-hover' Classes Added

The extra "hover classes* are now always added to resizers and togglers - regardless whether the resizable or closable options are enabled.

Previously the hover-classes were added only if resizable/closable were enabled, but that is not ideal since the purpose of the hover-classes is simply to standardize CSS for old browsers like IE6, which do not understand the :hover pseudo-class on anything other than hyperlinks.

If you want to control the hover styles for elements, this should be done purely with CSS. So the -hover layout-classes are now consistent with the :hover pseudo-class, regardless of JavaScript functionality.

So IF you want to accommodate IE6, use "-hover" on classNames, like this:

    .ui-layout-resizer-hover { background: #FCC; } 
    .ui-layout-resizer-west-hover { background: #FCC; } 

...INSTEAD OF using the CSS ":hover" pseudo-class...

    .ui-layout-resizer:hover { background: #FCC; } 
    .ui-layout-resizer-west:hover { background: #FCC; } 


New in RC29.15

New Initialization Functionality

Previously you could not initialize a layout when the container-element was 'hidden'. So when using layouts inside tabs or any other time the layout was not initially visible, custom logic was required so the layout was created only after it became visible.

Now ALL layouts can be initialized on-page-load – whether visbible or hidden. If the layout is hidden — or if the center-pane element does not exist — then the layout will "partially initialize". The loads the options and creates the layout instance, but does not initialize the layout-panes.

Each time a layout method is called — like resizeAll() — the layout will check its status and complete initialization if it can. The same goes for automatic events triggered by window.resize or outer-layouts. If the layout still can't complete initialization, it will ignore the command given and continue waiting.

Or, to specifically tell the layout to complete initialization, call: myLayout.initPanes(). If possible, initialization will complete; If not, the command is ignored, as it is if initialization has already completed. Calling any method will do the same thing, so resizeAll() is just as good as initPanes().

The most common situation where partial initialization is useful is a layout-inside-a-tab – inner-layouts are often hidden inside an inactive tab. Instead of a special function, all you need now is a simple callback on tabs.show...

    // create the tabs
        show: function(){ tabLayout.resizeAll(); }
    // create the page layout
    pageLayout = $("body").layout( pageLayoutOptions );
    // create inner-layout (currently hidden)
    tabLayout  = $("#tab2").layout( tabLayoutOptions );

OR if the inner layout is created first...

    // create the page layout
    pageLayout = $("body").layout( pageLayoutOptions );
    // create inner-layout (currently hidden)
    tabLayout  = $("#tab2").layout( tabLayoutOptions );
    // create the tabs
        show: tabLayout.resizeAll
    // adjust page-layout after creating the tabs

This code also works for Ajax-tabs where the pane-elements do not even exist yet! The layout will wait until it can find the 'center-pane' element before completing initialization.

Two of the Tabs demos have been updated to use the new features and syntax:

New Layout Options
  • New option to disable layout error messages, for rare cases where necessary:
        showErrorMessages: true  // (default)

    NOTE: When using delayed initialization (described above), set showErrorMessages=false to avoid warnings about a 'hidden container' or 'missing center-pane'. But if your layout is not working right, re-enable the messages for testing.

  • Layout's language data was moved so that it can now be fully customized. Most tips could already be customized in the options, but not all of them. Plus changes can now be done globally (once) instead of repeated in each layout. (except when you want to customize tips per-pane)
    // Global Language Customization
    $.extend( $.layout.language, {
    //  Tips and messages for resizers, togglers, custom buttons, etc.
        Open:            "Open"  // eg: "Open Pane"
    ,   Close:           "Close"
    ,   Resize:          "Resize"
    ,   Slide:           "Slide Open"
    ,   Pin:             "Pin"
    ,   Unpin:           "Un-Pin"
    ,   noRoomToOpenTip: "Not enough room to show this pane."
    //  Developer error messages
    ,   pane:                 "pane"     // description of "layout pane-element"
    ,   selector:             "selector" // description of "jQuery-selector"
    ,   errButton:            "Error Adding Button\n\n"
                            + "Invalid " // error-data is appended to this
    ,   errContainerMissing:  "UI Layout Initialization Error\n\n"
                            + "The specified layout-container does not exist."
    ,   errContainerHeight:   "UI Layout Initialization Warning\n\n"
                            + "The layout-container \"CONTAINER\" has no height.\n\n"
                            + "Therefore the layout is 0-height and hence 'invisible'!"
    ,   errCenterPaneMissing: "UI Layout Initialization Error\n\n"
                            + "The center-pane element does not exist.\n\n"
                            + "The center-pane is a required element."
    // ALL layouts will use the language defaults above, but can still be customized...
        west__togglerTip_open:   "Hide Main Menu"
    ,   west__togglerTip_closed: "Show Main Menu"
    ,   west__sliderTip:         "Show Main Menu"
    ,   west__noRoomToOpenTip:   "Not enough room to open the Main Menu"
New Layout Methods
  • Moved more helper methods into $.layout namespace
  • Renamed 2 user-accessible helper methods:
    getElemDims() is now: getElementDimensions()
    getElemCSS()  is now: getElementCSS()
    // Example
    var json_dimensions = getElementDimensions( $Element );
    // Example
    var json_css = getElementCSS( $Element, "width,height,border,padding" );
    // NOTE: border, padding & margin return ALL relatedstyles, like...
        width:              "500px"
    ,   height:             "350px"
    ,   padding-left:       "10px"
    ,   padding-right:      "10px"
    ,   padding-bottom:     "10px"
    ,   padding-top:        "10px"
    ,   border-left-color:  "#000"
    ,   border-left-style:  "solid"
    ,   border-left-width:  "1px"
    ,   border-right-color: "#000"
    ,   border-right-style: "solid"
    ,   border-right-width: "1px"
    ,   [ etc. ]
Other Updates
  • Changed syntax for getting 'tagName' for forward compatibility (.attr("tagName") syntax is deprecated)
  • Misc small bug-fixes.
New Add-ons — "Callbacks"

I now package custom code snippets into reusable callback functions that can be loaded into the $.layout namespace. This makes code for special situations easy to reuse. I have created 2 callbacks so far, including one that leverages the new integration functionality. All callbacks can be downloaded in a single file, or as individual files:

Callbacks Library — contains all callbacks in one file:

resizeTabLayout Callback — automatically finds a layout nested inside a tab and initializes or resized it:

resizeTabLayout Example

    // mouseleave event - 300 is the minimum
        show: $.layout.callbacks.resizeTabLayout
    // OR mixed with custom code
        show: function (evt, ui) {
            [ other code ]

    // OR without the callback method
    show: function (evt, ui) {
        var tabLayout = $(ui.panel).data("layout");
        if ( tabLayout ) tabLayout.resizeAll();
        [ other code ]

pseudoClose Callback — prevents iframes, flash and other objects from reloading when the pane closes.

pseudoClose Example

    // mouseenter event - 0 = instant open
    south__onclose_start: $.layout.callbacks.pseudoClose
    // or
        show: function () {
        [ other code ]
        return false; // CANCEL normal close

New in RC29.14

New Options

New options for setting a 'delay' when triggering slide-open (mouseEnter) and slide-closed (mouseLeave). Options have no effect when slide-trigger is click or dblClick.

   slideTrigger_open:  "mouseenter"
,  slideTrigger_close: "mouseleave" // default
,  slideDelay_open:    300 // mouseenter event - 0 = instant open
,  slideDelay_close:   300 // mouseleave event - 300 is the minimum

New in RC29.13

New & Removed Classnames
  • options.containerClass — (optional) className(s) will be added to the layout-container - for styling or identification
  • Resizing-limit is now customizable per-pane, eg:
    .ui-layout-resizer-west-dragging-limit { background: red; }
  • Toggler content-open/-closed spans no longer have 'hover' classes added. Instead use syntax like:
    .ui-layout-toggler-west-hover .content-open { background: yellow; }
New & Renamed Events

The onload and onunload events have been extended with _start & _end versions. The new onload_end event is useful for modifying the layout after it is created.

  • onload_start — when Layout inits - after options initialized, but before elements initialized
  • onload_end — when Layout inits - after EVERYTHING has been initialized (alias: onload)
  • onunload_start — when Layout is destroyed - before saving state
  • onunload_end — when Layout is destroyed - after saving state (alias: onunload)

    NOTE: The onload event in previous versions is now onload_start. Modify your code accordingly.

New Layout Methods
  • myLayout.addPane( pane ) — add a pane to an existing layout
  • myLayout.removePane( pane [, true] ) — remove pane from layout – true = also delete the element

    These methods allow pane-elements to be added and removed after initialization. If necessary, modify the applicable pane-options before calling addPane, eg:

    myLayout.options.east.paneSelector = "#myNewPane";
    myLayout.options.east.initClosed = true;

    If the specified pane already exists, it will be removed before the new one is added. This is a way to re-initialize a pane with new options that cannot otherwise be changed, like 'resizable'.

Bug Fixes

  • Slider-bar 'onmouseover' event no longer triggered when over the toggler button
  • CSS on pane content-element now correctly reset if layout is destroy()ed
  • Added patch to fix bug in UI Draggable when page used dir="rtl"
  • Fixed bugs in nested-layout auto-resizing - wasn't triggered in some cases
  • Fixed param definitions for compiling in Google Closure

Added in RC29.12

  • Some performance improvements when resizing layouts that have 'closed panes'.
  • Modified how layout "Instance" is handled. Can still retrieve an instance by calling $ContainerElem.layout(), but now can also use standard UI widget syntax:
    In addition, all layout child-elements (panes, resizers & togglers) can return the layout instance they are part of, like:
    These child elements use 'parentLayout' instead of just 'layout' because they are not the container-element. A 'pane-element' that contains a nested layout could return have BOTH data("p arentLayout") and data("layout") instances. The former is the layout where the element is a 'layout-pane' (aka 'child'), the latter is the sub-layout where the element is the 'layout-container' (aka 'parent').

    SEE demos/layout_methods.html for samples
  • Added 6 new methods that allow primary pane-functionality to be enabled/disabled AFTER the layout is created.

    However the [pane_]closable and [pane_]resizable options must be enabled at the time of Initialization or else they cannot be enabled later. So if you want the ability to enable a feature like west__resizable, but have it disabled onLoad, enable it in the options and then call disableResizable("west") immediately after creating the layout. This will enable you to enableResizable("west") later.

    UPDATE: removePane() & addPane() methods in RC29.13 allow a pane to be 're-initialized' with different options

    disableClosable( pane [, hideToggler ] );
    enableClosable( pane ); // always un-hides Toggler
    disableResizable( pane );
    enableResizable( pane );
    disableSlidable( pane );
    enableSlideable( pane );
    SEE demos/layout_methods.html for samples

Added in RC29.11

  • The loadState() method can now be called after initialization of the layout. The layout will be updated to match the state passed. By default the changes are made without open/close animations. If animation is desired, pass 'true' as a 2nd param, eg:
    myLayout.loadState( stateJSON, true )

Fixed in RC29.10

  • Fixed onload callback - 'Instance' (1st param) was undefined

Added in RC29.9

  • NEW preventPrematureSlideClose option (default=false). When enabled, this addresses situations where a mouseout event is incorrectly triggered, causing a pane to 'slide closed' while the mouse if really still over it. This happens in IE when using a SELECT picklist.

Fixed in RC-29.8

  • Second fix for compatibility with jQuery UI 1.8.5

Fixed in RC-29.7

  • Fixed initialization bug for compatibility with jQuery UI 1.8.5

Fixed in RC-29.6

  • Fixed zIndex bug where pane given zIndex=100 when closed

Fixed in RC-29.5

  • Fixed potential bug where pane zIndex didn't reset after animation
  • Fixed bug where close callback not called after pane was 'sliding'
  • Refined automatic resizing of nested layouts.

Fixed in RC-29.4

  • Fixed innerHeight() attribute for compatibility with UI 1.8.4
  • Minor refactoring of code
  • Made JavaDoc syntax compatible with Google Closure Compiler
  • Restored some utility methods that were temporarily removed in RC-29

Fixed in RC-29.3

  • Fixed bug in destroy() method.

Fixed in RC-29.2

  • Fixed implementation of the onsizecontent callbacks added in RC-29

Fixed in RC-29.1

  • Fixed bug in content-sizing that miscalculated padding/margin at bottom of pane
  • Margins on all content-elements are now accounted for when sizing content.

Added in RC-29

NOTE: This is only some of the refinements planned for RC-29. It was taking too long to get them all completed and tested, so I broke the updates into 2 releases: RC-29 is the first half - RC-30 will add the remainder. RC-30 will include some fundamental changes to some option-names and utility methods in preparation for finalizing version 1.3.0.

Fixed numerous small bugs, like no longer adding 'hover' classes to disabled resizers, making sure required resizing is always triggered, etc.

Updated header/content sizing (ie, .ui-layout-content). Now faster and more accurate. Added callbacks for content-sizing:

  • onsizecontent_start
  • onsizecontent_end / onsizecontent

Fixed the "text selection while resizing" issue, even in Google Chrome. The "noSelectionWhileDragging" option no longer exists because now text-selection is always disabled when resizing because the new method has no negative effects.

Added callbacks for manual resizing:

  • ondrag_start
  • ondrag_end / ondrag

Fixed pane-swapping functionality, and...

Added callback for pane-swapping:

  • onswap_start
  • onswap_end / onswap

Added action methods for 'sliding'.. (Previously required passing extra params to the open() and close() methods):

  • myLayout.slideOpen("west");
  • myLayout.slideClose("west");
  • myLayout.slideToggle("west");

Added option to prevent Chrome from immediately closing a pane after it has 'slid open'. This is automatically enabled for Webkit browsers, but not for others. You can override the default if necessary:

  • preventQuickSlideClose: !!($.browser.webkit || $.browser.safari) // default

The old option for handling this issue has been removed:

  • trackMouseWhenSliding: false // NO LONGER EXISTS

Added automatic nested-layout resizing. This change affects the options you set. When you have a 'directly nested' layout (definition below), you no longer need to set a callback to resize the nested layout. If you use RC-29 and still have old onresize callbacks set, the nested-layout will be resized twice. This doesn't hurt anything, but is an unnecessary drag on performance, so old callbacks should be removed.

This functionality is controlled by a new option and enabled by default for all panes:

  • resizeNestedLayout: true // default

There is little need to ever disable it, but it could be if necessary, eg:

  • west__resizeNestedLayout: false

What is a "Directly Nested Layout"?

A "directly-nested-layout" is one where the same element that is a 'pane' in an outer-layout is also the 'container' for an inner/nested layout. In this case, Layout will recognize the nested layout when the outer-pane resizes, and so automatically trigger resizeAll() on the nested-layout after it finishes resizing the outer-pane.

Example: Directly-Nested Inner-Layout -- WILL Auto-Resize

<div class="ui-layout-center"> <!-- outer pane / inner container -->
   <div class="ui-layout-north">  North  </div>
   <div class="ui-layout-center"> Center </div>
   <div class="ui-layout-couth">  South  </div>

HOWEVER, if the inner-layout in inside any kind of 'extra wrapper-div' as a container - ie, not the outer 'pane' itself - then it is not 'directly nested'. In this case Layout will not know it exists, so an onresize callback will still be needed on the outer-pane, as it is now.

Example: Inner-Layout with 'Extra Wrapper' -- Will NOT Auto-Resize

<div class="ui-layout-center"> <!-- outer pane -->
   <div id="innerLayoutWrapper"> <!-- wrapper / inner container -->
       <div class="ui-layout-north">  North  </div>
       <div class="ui-layout-center"> Center </div>
       <div class="ui-layout-couth">  South  </div>

There are A LOT of changes in this release, so please report any errors you find to help debug it. There will be more big changes coming in RC-30, which will become Layout 1.3.0 Final after it is tested for a few weeks.

Added in RC-28

  1. New pane-option: findNestedContent: false (default)

    This option can be set per-pane, eg: west__findNestedContent: true

    Normally a content-element must be a child of the pane-element, but when this option is enabled, Layout will 'find' the [pane].contentSelector element anywhere inside the pane. This allows content elements to be nested inside wrappers.

    CAUTION: Do not enable this option unless you have a content-element for Layout to find. If the layout does not have a content-element, but does have an inner-layout with a content-element, this might be found, causing the inner content-element to be bound to both the inner- and outer-layouts, creating resize-sequencing issues.
  2. New pane-method: initContent( pane )

    This method requires a pane, eg: myLayout.initContent("west");

    This method allows you to re-initialize a content-element after the layout is created. This is necessary if a content element is added or removed. Even removing and re-adding a content-div with the same ID will require re-initialization because the 'pointer' to that object is broken.

    This method should also be called if you remove a content element. In this case calling initContent will let Layout know that this element no longer exists.

Added in RC-27

  1. Fix bug in callback queuing
  2. Internal updates to handle string-objects

Added in RC-26

  1. Now validates to prevent a layout being created without a center-pane

Added in RC-25

  1. Can now get a Layout Instance after initialization from the DOM object...
  2. $("#containerRef").layout({ options... }); // init var Instance = $("#containerRef").layout(); // get Instance
  3. New error message to warn of 0-height layouts - most common mistake

Added in RC-24

  1. New auto-bind button class: ui-layout-button-open-slide-[west]
  2. New auto-bind button class: ui-layout-button-toggle-slide-[west]
  3. Fixed bug in mouse detection code
  4. Fixed bug in sliding formatting logic

Added in RC-23

  1. New option: resizeContentWhileDragging: false (default). When false, Layout does not check the height of headers and footers inside panes while doing live-resizing. This is deferred until resizing is 'done' to increase performance. If you have headers and footers that change size (eg, wrap text) and you want perfect content sizing while live-resizing, then change this option to true.
  2. Content elements - with the 'ui-layout-content' class - can now be 'nested' within the pane. It no longer needs to be a direct child of the pane element.

Fixed in RC-22

  1. Fixed bug in callback logic when using live-resizing and triggerEventsWhileDragging option.

Fixed in RC-21

  1. Fixed bug to remove 'close' trigger on resizer when a pane is 'pinned'. Actually a jQuery bug - only unbinding one mouseout event instead of all.

Fixed in RC-20

  1. Fixed bug when slideOpen and slideClosed trigger events are both 'click' The click event was cascading to cause pane to immediately close after opening.

Fixed in RC-19

  1. Fixed ui-layout-content resizing to work perfectly in all browsers and all doctypes. Content sizing will not faithfully account for padding on the pane-element and margins on all the header, footer and content divs.

  2. Added automatic minSize for all panes. Panes can no longer be manually resized so small that they must be 'hidden'.

Added in RC-18

New option: resizeWithWindowMaxDelay

This option works in concert with resizeWithWindowDelay to control layout resizing during browser-window resizing. The 'MaxDelay', if set, will cause the layout to resize every XX milliseconds even if the window is still being resized. For example...

    resizeWithWindowDelay:    300 		
,   resizeWithWindowMaxDelay: 1000 

If no window-resize event is triggered for 300ms, the layout will be resized. This timer is reset each time a window-resize event is detected. So as long as the user keeps resizing the window, it will keep resetting the 300ms timer - waiting for the user to finish.

However, even if the user keeps resizing the window, the layout will resize every 1000ms anyway because of the resizeWithWindowMaxDelay option. If you do not want your layout to resize until the user is 'done' resizing the window, then leave resizeWithWindowMaxDelay as 0 (default), which disables this extra functionality.

Fixed in RC-17

  1. Fixed multiple callback firing onLoad and onResize
  2. Added option for mouse detection to avoid sliding-pane closing prematurely:
[pane].trackMouseWhenSliding: false // default

NOTE that trackMouseWhenSliding applies only when a pane is 'sliding' (temporarily open). However enabling mouse-position detection sometimes causes the mouseOut event to be missed (pane does not close), so enable only when/where needed. Only known issue is SELECT field in IE, which causes mouseOut event. But Google Chrome may also cause premature slide-closed?

Fixed in RC-16

  1. Bug-fix for window.resize callbacks Re-enabled mouse detection to avoid sliding-panes closing prematurely

Added in RC-15

  1. Set the zIndex of 'panes' (resize-bars will be 1-higher). This is GLOBAL - cannot be set 'per pane'
zIndex: null // default - same as: 1
  1. Disable 'close' when resizer-bar is double-clicked. This is a per-pane option
resizerDblClickToggle: true // default
west__resizerDblClickToggle: false // sample
  1. Ensure 'text' is not selected during when dragging the resizer-bar
noSelectionWhileDragging: true // default
west__noSelectionWhileDragging: false // sample
  1. When using live-resizing, callback events are normally triggered repeatedly. Disable this option to to avoid this and trigger callbacks only when resizing is complete.
triggerEventsWhileDragging: true // default
west__triggerEventsWhileDragging: false // sample
  1. Also added 2 new properties to provide access to the generated elements...
Example: var westResizerBar = myLayout.resizers.west
Example: var westToggleBtn = myLayout.togglers.west
  1. Lastly, I removed the default hotkeys for SHIFT+Cursor keys. Cursor-hotkeys now only works with CTRL+ - like CTRL+Left-Cursor to toggle the west/left pane. This eliminates conflicts with text-selection hotkeys.

Fixed in RC-5 to RC-14

These releases were mostly bug fixes. Some new features were probably added, but I do not have a list available right now.

Updated in RC-4.2

  1. Update State Management (no longer requires json2.js )

    This update REMOVES the dependancy for State Management. You no longer need json2.js to use the new feature.

Added in RC-4.1

  1. Add State Management (requires json2.js - SEE RC-4.2 )

    For details, see: http://groups.google.com/group/jquery-ui-layout/browse_thread/thread/b6d7b9446bde4b54/6610e869a7908689?q=

Added in RC-4

Here is the 1.3.RC4 version (I skipped RC3). I fixed all known bugs and completed all the remaining features I was working on.

Layout will now autoClose (if pane is 'closable') or autoHide panes when there is not enough room for them to fit. This is determined based on the border-pane's minSize and center minWidth/minHeight. If you want the pane will re-open when there is enough room again, enable the autoReopen option.

autoReopen: false // default

NOTE that autoOpen does not work well with live-resizing because the pane will re-open as soon as there is even 1px of space available, making the pane very small.

There is an new option for the 'auto' and percentage-sizing capabilities. If you enable this, layout will recalculate percentages every time the layout is resized to try and maintain the same ratios...

autoResize: false // default

If you enable this for a pane that has 'auto' size, the pane will resize to fit wrapped content.

If a pane is 'manually resized', autoResize is automatically turned off for that pane.

If minSize rules prevent layout from achieving the percentage-size specified, the panes will be smaller. However, Layout will continue trying to achieve the full size every time the layout resizes.

The option previously named "setWindowResizeTrigger" has been renamed to "resizeWithWindow". Normally you do not have to worry about this, but it can be useful with a nested layout that is inside a 'non-layout container'.

resizeWithWindow: true // default, UNLESS container is a 'pane' of an outer-layout

A new companion options sets a 'delay' before resizing the layout when the window is resizing. The default is 250ms, which makes window resizing smoother because the layout is not trying to resize 50-times/second

resizeWithWindowDelay: 250 // default 

Layout has 2 new methods: swapPanes() and destroy()


...will REMOVE the layout, putting everything back as it was originally. You can see a demo here: /demos/destroy.html

myLayout.swapPanes("west", "east")
...will MOVE a pane(s) from one edge to another. You can move any pane to any side. If only one side has a pane, then the pane is 'moved'. If both the source and target sides have panes, then the 2 panes 'swap sides'. Layout will try to intelligently resize the panes as needed. You can see a demo here: /demos/swap_panes.html

Here are some additional pages I used to test RC4 features...