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