r3359 committed - labs: panel ...

r3359 committed - labs: panel ...


Revision: 3359
Author: idlesign
Date: Fri Oct 9 00:55:31 2009
Log: labs: panel
* new: 'width' option - if set panel's width will be adjusted according to
given value
* new: 'stackable' option - if true, special stack area (navigation window
emulation) is automatically created for 'slide-left' & 'slide-right'
collapseType panels only
* changed: improved destroy method
* changed: improved title text positioning in vertical panels
with 'trueVerticalText'
* changed: source code reformatted (tabs converted to spaces)
http://code.google.com/p/jquery-ui/source/detail?r=3359
Modified:
/branches/labs/panel/ui.panel.js
=======================================
--- /branches/labs/panel/ui.panel.js    Fri Oct 2 19:03:59 2009
+++ /branches/labs/panel/ui.panel.js    Fri Oct 9 00:55:31 2009
@@ -1,6 +1,7 @@
/*
-* Panel Draft 0.3.6
-* for jQuery UI
+* Panel / Content Grouping Draft for jQuery UI
+* ist-ui-panel
+* version 0.4
*
* Copyright (c) 2009 Igor 'idle sign' Starikov
* Dual licensed under the MIT (MIT-LICENSE.txt)
@@ -9,336 +10,410 @@
* http://code.google.com/p/ist-ui-panel/
*
* Depends:
-*    ui.core.js
+* ui.core.js
*/
(function($) {
$.widget('ui.panel', {
-    // create panel
-    _init: function() {
-     if (this.element.is('div')) {
-        var self = this,
-         o = this.options;
-
-        this.panelBox = this.element;
-        o.width = this.panelBox.css('width');
-        this.panelBox.attr('role', 'panel');
-        o.id = this.panelBox.attr('id');
-        this.headerBox = this.element.children().eq(0);
-        this.contentBox = this.element.children().eq(1);
-        o.content = this.contentBox.html();
-        // wrap content to prevent padding issue
-        this.contentBox.wrapInner('<div></div>');
-        this.contentTextBox =
this.contentBox.children().eq(0).addClass(o.contentTextClass);
-        this.headerBox.wrapInner('<div><span></span></div>');
-        // need separate titleBox and titleTextBox to avoid possible
collapse/draggable issues
-        this.titleBox = this.headerBox.children().eq(0);
-        this.titleTextBox = this.titleBox.children().eq(0);
-        this.titleText = this.titleTextBox.html();
-        this.headerBox.prepend('<span></span>')
-        this.rightBox =
this.headerBox.children().eq(0).addClass(o.rightboxClass);
-        // setting up controls
-        if (o.controls!=false){
-         // suppose 'o.controls' should be a ui.toolbar control
-         this.rightBox.append('<span></span>');
-         this.controlsBox =
this.rightBox.children().eq(0).addClass(o.controlsClass).html(o.controls);
-        } else {
-         this.controlsBox = null;
-        }
-
-        // styling
-        this.panelBox.addClass(o.widgetClass);
-        this.headerBox.addClass(o.headerClass);
-        this.titleBox.addClass(o.titleClass);
-        this.titleTextBox.addClass(o.titleTextClass);
-        this.contentBox.addClass(o.contentClass);
-
-        // collapsibility
-        if (o.collapsible){
-         switch (o.collapseType) {
-            case 'slide-right':
-             var childIndex = 0;
-             // there is a shift of child element index if controls are enabled
-             if (o.controls) { childIndex = 1; }
-             this.rightBox.append('<span><span/></span>');
-             this.collapsePanel =
this.rightBox.children().eq(childIndex).addClass(o.collapsePnlClass);
-             this.collapseButton =
this.collapsePanel.children().eq(0).addClass(o.slideRIcon);
-             this.iconBtnClpsd = o.slideRIconClpsd;
-             this.iconBtn = o.slideRIcon;
-             this.ctrlBox = this.controlsBox;
-            break;
-            case 'slide-left':
-             this.headerBox.prepend('<span><span/></span>');
-             this.collapsePanel =
this.headerBox.children().eq(0).addClass(o.collapsePnlClass);
-             this.collapseButton =
this.collapsePanel.children().eq(0).addClass(o.slideLIcon);
-             this.iconBtnClpsd = o.slideLIconClpsd;
-             this.iconBtn = o.slideLIcon;
-             this.ctrlBox = this.rightBox;
-            break;
-            default:
-             this.headerBox.prepend('<span><span/></span>');
-             this.collapseButton =
this.headerBox.children().eq(0).addClass(o.headerIcon);
-             this.iconBtnClpsd = o.headerIconClpsd;
-             this.iconBtn = o.headerIcon;
-             this.ctrlBox = this.controlsBox;
-            break;
-         }
-
-         this._buttonHover(this.collapseButton);
-         this.collapseButton.addClass(o.iconClass);
-         if (o.event) {
-            this.collapseButton.bind((o.event) + ".panel", function(event) { return
self._clickHandler.call(self, event, this); });
-            this.titleTextBox.bind((o.event) + ".panel", function(event) { return
self._clickHandler.call(self, event, this); });
-         }
-         // collapse panel if 'accordion' option is set
-         if (o.accordion) { o.collapsed = true; }
-         // restore state from cookie
-         if (o.cookie) {
-            if (self._cookie()==0) {
-             o.collapsed = false;
-            } else {
-             o.collapsed = true;
-            }
-         }
-         // store state as data
-         this.panelBox.data('collapsed', o.collapsed);
-
-         // panel collapsed - trigger action
-         if (o.collapsed) {
-            self.toggle(0, true);
-         }
-        } else {
-            this.titleTextBox.css('cursor','default');
-        }
-        // making panel draggable if not accordion-like
-        if (!o.accordion && o.draggable && $.fn.draggable){
this._makeDraggable(); }
-
-        this.panelBox.show();
-
-        // disabled panel handling
-        this.disable(o.disabled);
-     }
-    },
-
-    _cookie: function() {
-     var cookie = this.cookie || (this.cookie = this.options.cookie.name |
| 'ui-panel-'+this.options.id);
-     return $.cookie.apply(null, [cookie].concat($.makeArray(arguments)));
-    },
-
-    // ui.draggable config
-    _makeDraggable: function() {
-     this.panelBox.draggable({
-        containment: 'document',
-        handle: '.ui-panel-header',
-        cancel: '.ui-panel-content',
-        cursor: 'move'
-     });
-     this.contentBox.css('position','absolute');
-    },
-
-    _clickHandler: function(event, target){
-     var o = this.options;
-
-     if (o.disabled) { return false; }
-     this.toggle(o.collapseSpeed);
-     return false;
-    },
-
-    // disables panel (usign appropiate ui class)
-    disable: function (disable){
-     var o = this.options;
-
-     if (disable===undefined) disable = true;
-     if (disable) {
-        this.panelBox.children().addClass(o.disableClass);
-        // lock panel controls
-        if (this.controlsBox){
-         this.controlsBox.bind('click', function() { return false; });
-        }
-     } else {
-        this.panelBox.children().removeClass(o.disableClass);
-        if (this.controlsBox){
-         this.controlsBox.unbind('click');
-        }
-     }
-     // save state
-     o.disabled = disable;
-    },
-
-    // toggles panel state (folded/unfolded)
-    toggle: function (collapseSpeed, innerCall){
-     var self = this,
-        o = this.options,
-        btn = this.collapseButton,
-        ibc = this.iconBtnClpsd,
-        ib = this.iconBtn,
-        panelBox = this.panelBox,
-        contentBox = this.contentBox,
-        headerBox = this.headerBox,
-        titleTextBox = this.titleTextBox,
-        titleText = this.titleText,
-        ctrlBox = this.ctrlBox,
-        ie = '';
-
-     // that's IE 6-8 for sure, use appropriate style for vertical text
-     if (!jQuery.support.leadingWhitespace) ie="-ie";
-
-     // split toggle into 'fold' and 'unfold' actions and handle callbacks
-     if (contentBox.css('display')=='none') {
-        this._trigger("unfold");
-     } else {
-        this._trigger("fold");
-     }
-
-     if (ctrlBox) { ctrlBox.toggle(0); }
-
-     // various content sliding animations
-     if (o.collapseType=='default'){
-        if (collapseSpeed==0) {
-         if (ctrlBox) { ctrlBox.hide(); }
-         contentBox.hide();
-        } else {
-         contentBox.slideToggle(collapseSpeed);
-        }
-     } else {
-        if (collapseSpeed==0) {
-         // reverse collapsed option for immediate folding
-         o.collapsed=false;
-         if (ctrlBox) { ctrlBox.hide(); }
-         contentBox.hide();
-        } else {
-         contentBox.toggle();
-        }
-
-        if (o.collapsed==false){
-         if (o.trueVerticalText){
-            // true vertical text - svg or filter
-            headerBox.toggleClass('ui-panel-vtitle').css('height', o.vHeight);
-            if (ie==''){
-             titleTextBox
-                .empty()
-                // put transparent div over svg object for object onClick simulation
-                .append('<div
style="height:90%;width:100%;position:absolute;bottom:0;"></div><object
type="image/svg+xml" data="data:image/svg+xml;charset=utf-8,<svg
xmlns=\'http://www.w3.org/2000/svg\'><text x=\'-190\' y=\'13\'
style=\'font-weight:'+titleTextBox.css('font-weight')+';font-family:'+titleTextBox.css('font-family').replace(/"/g, '')+';font-size:'+titleTextBox.css('font-size')+';fill:'+titleTextBox.css('color')+';\'
transform=\'rotate(-90)\'
text-rendering=\'optimizeSpeed\'>'+titleText+'</text></svg>"></object>')
-                .css('height', o.vHeight);
-            }
-
-            titleTextBox.toggleClass('ui-panel-vtext'+ie);
-         } else {
-            // vertical text workaround
-            headerBox.attr('align','center');
-            titleTextBox.html(titleTextBox.text().replace(/(.)/g, '$1<BR>'));
-         }
-         panelBox.animate( {width: '2.4em'}, collapseSpeed );
-        } else {
-         if (o.trueVerticalText){
-            headerBox.toggleClass('ui-panel-vtitle').css('height', 'auto');
-            titleTextBox.empty().append(titleText);
-            titleTextBox.toggleClass('ui-panel-vtext'+ie);
-         } else {
-            headerBox.attr('align','left');
-            titleTextBox.html(titleTextBox.text().replace(/<BR>/g, ' '));
-         }
-         panelBox.animate( {width: o.width}, collapseSpeed );
-        }
-     }
-
-     // only if not initially folded
-     if (collapseSpeed!=0 || o.trueVerticalText) {
-        o.collapsed = !o.collapsed;
-     }
-
-     panelBox.data('collapsed', o.collapsed);
-
-     // save state in cookie if allowed
-     if (o.cookie) {
-        self._cookie(Number(o.collapsed), o.cookie);
-     }
-
-     // inner toggle call to show only one unfolded panel if 'accordion'
option is set
-     if (o.accordion && !innerCall){
-        
$("."+o.accordion+"[role='panel'][id!='"+(o.id)+"']:not(:data(collapsed))").panel('toggle',
collapseSpeed, true);
-     }
-
-     // css animation for header and button
-     btn.toggleClass(ibc).toggleClass(ib);
-     headerBox.toggleClass('ui-corner-all');
-    },
-
-    // sets panel's content
-    content: function(content){
-     this.contentTextBox.html(content);
-    },
-
-    // destroys panel
-    destroy: function(){
-     var o = this.options;
-
-     this.headerBox
-        .html(this.titleText)
-        .removeClass(o.headerClass);
-     this.contentBox
-        .removeClass(o.contentClass)
-        .html(o.content);
-     this.panelBox
-        .removeAttr('role')
-        .removeData('collapsed')
-        .unbind('.panel')
-        .removeClass(o.widgetClass);
-
-     if (o.cookie) { this._cookie(null, o.cookie); }
-    },
-
-    _buttonHover: function(el){
-     var o = this.options;
-
-     el
-     .bind('mouseover', function(){ $(this).addClass(o.hoverClass); })
-     .bind('mouseout', function(){ $(this).removeClass(o.hoverClass); })
-    }
+ // create panel
+ _init: function() {
+ if (this.element.is('div')) {
+ var self = this,
+ o = this.options;
+
+ this.panelBox = this.element;
+ // if width option is omitted, get width from css
+ if (o.width=='auto') {
+ o.width = this.panelBox.css('width');
+ } else {
+ this.panelBox.css('width', o.width);
+ }
+ this.panelBox.attr('role', 'panel');
+ o.id = this.panelBox.attr('id');
+ this.headerBox = this.element.children().eq(0);
+ this.contentBox = this.element.children().eq(1);
+ o.content = this.contentBox.html();
+ // wrap content to prevent padding issue
+ this.contentBox.wrapInner('<div></div>');
+ this.contentTextBox =
this.contentBox.children().eq(0).addClass(o.contentTextClass);
+ this.headerBox.wrapInner('<div><span></span></div>');
+ // need separate titleBox and titleTextBox to avoid
possible collapse/draggable issues
+ this.titleBox = this.headerBox.children().eq(0);
+ this.titleTextBox = this.titleBox.children().eq(0);
+ this.titleText = this.titleTextBox.html();
+ this.headerBox.prepend('<span></span>')
+ this.rightBox =
this.headerBox.children().eq(0).addClass(o.rightboxClass);
+ // setting up controls
+ if (o.controls!=false){
+ // suppose 'o.controls' should be a ui.toolbar control
+ this.rightBox.append('<span></span>');
+ this.controlsBox =
this.rightBox.children().eq(0).addClass(o.controlsClass).html(o.controls);
+ } else {
+ this.controlsBox = null;
+ }
+
+ // styling
+ this.panelBox.addClass(o.widgetClass);
+ this.headerBox.addClass(o.headerClass);
+ this.titleBox.addClass(o.titleClass);
+ this.titleTextBox.addClass(o.titleTextClass);
+ this.contentBox.addClass(o.contentClass);
+
+ // collapsibility
+ if (o.collapsible){
+ switch (o.collapseType) {
+ case 'slide-right':
+ var childIndex = 0;
+ // there is a shift of child element index if
controls are enabled
+ if (o.controls) { childIndex = 1; }
+ this.rightBox.append('<span><span/></span>');
+ this.collapsePanel =
this.rightBox.children().eq(childIndex).addClass(o.collapsePnlClass);
+ this.collapseButton =
this.collapsePanel.children().eq(0).addClass(o.slideRIcon);
+ this.iconBtnClpsd = o.slideRIconClpsd;
+ this.iconBtn = o.slideRIcon;
+ this.ctrlBox = this.controlsBox;
+ break;
+ case 'slide-left':
+ this.headerBox.prepend('<span><span/></span>');
+ this.collapsePanel =
this.headerBox.children().eq(0).addClass(o.collapsePnlClass);
+ this.collapseButton =
this.collapsePanel.children().eq(0).addClass(o.slideLIcon);
+ this.iconBtnClpsd = o.slideLIconClpsd;
+ this.iconBtn = o.slideLIcon;
+ this.ctrlBox = this.rightBox;
+ break;
+ default:
+ this.headerBox.prepend('<span><span/></span>');
+ this.collapseButton =
this.headerBox.children().eq(0).addClass(o.headerIcon);
+ this.iconBtnClpsd = o.headerIconClpsd;
+ this.iconBtn = o.headerIcon;
+ this.ctrlBox = this.controlsBox;
+ break;
+ }
+
+ this._buttonHover(this.collapseButton);
+ this.collapseButton.addClass(o.iconClass);
+ if (o.event) {
+ this.collapseButton.bind((o.event) + ".panel",
function(event) { return self._clickHandler.call(self, event, this); });
+ this.titleTextBox.bind((o.event) + ".panel",
function(event) { return self._clickHandler.call(self, event, this); });
+ }
+ // collapse panel if 'accordion' option is set
+ if (o.accordion) { o.collapsed = true; }
+ // restore state from cookie
+ if (o.cookie) {
+ if (self._cookie()==0) {
+ o.collapsed = false;
+ } else {
+ o.collapsed = true;
+ }
+ }
+ // store state as data
+ this.panelBox.data('collapsed', o.collapsed);
+
+ // stackability (navigation panel emulation) for
sliding panels
+ if (o.stackable && (o.collapseType=='slide-right' ||
o.collapseType=='slide-left')){
+
+ this.panelDock =
this.panelBox.siblings('div[role=panelDock]').eq(0);
+ this.panelFrame =
this.panelBox.siblings('div[role=panelFrame]').eq(0);
+
+ if (this.panelDock.length==0){
+ this.panelDock =
this.panelBox.parent(0).prepend('<div>').children().eq(0);
+ this.panelFrame =
this.panelDock.after('<div>').next().eq(0);
+
this.panelDock.attr('role', 'panelDock').css('float',
o.collapseType=='slide-left'?'left':'right');
+
this.panelFrame.attr('role', 'panelFrame').css({'float':o.collapseType=='slide-left'?'left':'right', 'overflow':'hidden'});
+ }
+
+ if (o.collapsed){
+ this.panelDock.append(this.panelBox);
+ } else {
+ this.panelFrame.append(this.panelBox);
+ }
+
+ }
+
+ // panel collapsed - trigger action
+ if (o.collapsed) {
+ self.toggle(0, true);
+ }
+
+ } else {
+ this.titleTextBox.css('cursor','default');
+ }
+ // making panel draggable if not accordion-like
+ if (!o.accordion && o.draggable && $.fn.draggable){
this._makeDraggable(); }
+
+ this.panelBox.show();
+
+ // disabled panel handling
+ this.disable(o.disabled);
+ }
+ },
+
+ _cookie: function() {
+ var cookie = this.cookie || (this.cookie =
this.options.cookie.name || 'ui-panel-'+this.options.id);
+ return $.cookie.apply(null,
[cookie].concat($.makeArray(arguments)));
+ },
+
+ // ui.draggable config
+ _makeDraggable: function() {
+ this.panelBox.draggable({
+ containment: 'document',
+ handle: '.ui-panel-header',
+ cancel: '.ui-panel-content',
+ cursor: 'move'
+ });
+ this.contentBox.css('position','absolute');
+ },
+
+ _clickHandler: function(event, target){
+ var o = this.options;
+
+ if (o.disabled) { return false; }
+ this.toggle(o.collapseSpeed);
+ return false;
+ },
+
+ // disables panel (usign appropiate ui class)
+ disable: function (disable){
+ var o = this.options;
+
+ if (disable===undefined) disable = true;
+ if (disable) {
+ this.panelBox.children().addClass(o.disableClass);
+ // lock panel controls
+ if (this.controlsBox){
+ this.controlsBox.bind('click', function() { return
false; });
+ }
+ } else {
+ this.panelBox.children().removeClass(o.disableClass);
+ if (this.controlsBox){
+ this.controlsBox.unbind('click');
+ }
+ }
+ // save state
+ o.disabled = disable;
+ },
+
+ // toggle panel state (fold/unfold)
+ toggle: function (collapseSpeed, innerCall){
+ var self = this,
+ o = this.options,
+ btn = this.collapseButton,
+ ibc = this.iconBtnClpsd,
+ ib = this.iconBtn,
+ panelBox = this.panelBox,
+ contentBox = this.contentBox,
+ headerBox = this.headerBox,
+ titleTextBox = this.titleTextBox,
+ titleText = this.titleText,
+ ctrlBox = this.ctrlBox,
+ panelDock = this.panelDock,
+ panelFrame = this.panelFrame,
+ ie = '';
+
+ // that's IE 6-8 for sure, use appropriate style for vertical
text
+ if (!jQuery.support.leadingWhitespace) ie="-ie";
+
+ // split toggle into 'fold' and 'unfold' actions and handle
callbacks
+ if (contentBox.css('display')=='none') {
+ this._trigger("unfold");
+ } else {
+ this._trigger("fold");
+ }
+
+ if (ctrlBox) { ctrlBox.toggle(0); }
+
+ // various content sliding animations
+ if (o.collapseType=='default'){
+ if (collapseSpeed==0) {
+ if (ctrlBox) { ctrlBox.hide(); }
+ contentBox.hide();
+ } else {
+ contentBox.slideToggle(collapseSpeed);
+ }
+ } else {
+ if (collapseSpeed==0) {
+ // reverse collapsed option for immediate folding
+ o.collapsed=false;
+ if (ctrlBox) { ctrlBox.hide(); }
+ contentBox.hide();
+ } else {
+ contentBox.toggle();
+ }
+
+ if (o.collapsed==false){
+
+ if (o.trueVerticalText){
+ // true vertical text - svg or filter
+
headerBox.toggleClass('ui-panel-vtitle').css('height', o.vHeight);
+ if (ie==''){
+ // fix title text positioning
+ var boxStyle
= 'height:'+(parseInt(o.vHeight)-50)+'px;width:100%;position:absolute;bottom:0;left:0;';
+ titleTextBox
+ .empty()
+ // put transparent div over svg object for
object onClick simulation
+ .append('<div
style="'+boxStyle+'z-index:3;"></div><object style="'+boxStyle+'z-index:2;"
type="image/svg+xml" data="data:image/svg+xml;charset=utf-8,<svg
xmlns=\'http://www.w3.org/2000/svg\'><text
x=\'-'+(parseInt(o.vHeight)-60)+'px\' y=\'16px\'
style=\'font-weight:'+titleTextBox.css('font-weight')+';font-family:'+titleTextBox.css('font-family').replace(/"/g, '')+';font-size:'+titleTextBox.css('font-size')+';fill:'+titleTextBox.css('color')+';\'
transform=\'rotate(-90)\'
text-rendering=\'optimizeSpeed\'>'+titleText+'</text></svg>"></object>')
+ .css('height', o.vHeight);
+ }
+
+ titleTextBox.toggleClass('ui-panel-vtext'+ie);
+ } else {
+ // vertical text workaround
+ headerBox.attr('align','center');
+
titleTextBox.html(titleTextBox.text().replace(/(.)/g, '$1<BR>'));
+ }
+ panelBox.animate( {width: '2.4em'}, collapseSpeed );
+
+ if (o.stackable){
+ if (innerCall){
+ // preserve html defined panel order
+ panelDock.append(panelBox);
+ } else {
+ // last folded on the top of stack
+ panelDock.prepend(panelBox);
+ }
+ }
+
+ } else {
+
+ if (o.stackable){
+ panelFrame.append(panelBox);
+ }
+
+ if (o.trueVerticalText){
+
headerBox.toggleClass('ui-panel-vtitle').css('height', 'auto');
+ titleTextBox.empty().append(titleText);
+ titleTextBox.toggleClass('ui-panel-vtext'+ie);
+ } else {
+ headerBox.attr('align','left');
+
titleTextBox.html(titleTextBox.text().replace(/<BR>/g, ' '));
+ }
+ panelBox.animate( {width: o.width}, collapseSpeed );
+ }
+ }
+
+ // only if not initially folded
+ if (collapseSpeed!=0 || o.trueVerticalText) {
+ o.collapsed = !o.collapsed;
+ }
+
+ panelBox.data('collapsed', o.collapsed);
+
+ // save state in cookie if allowed
+ if (o.cookie) {
+ self._cookie(Number(o.collapsed), o.cookie);
+ }
+
+ // inner toggle call to show only one unfolded panel
if 'accordion' option is set
+ if (o.accordion && !innerCall){
+
$("."+o.accordion+"[role='panel'][id!='"+(o.id)+"']:not(:data(coll