upgraded to yui 0.12.0

upgraded to yui-ext 0.33 rc2
This commit is contained in:
JT Smith 2006-11-28 02:23:34 +00:00
parent 62b3d90db7
commit cfd09a5cb6
1271 changed files with 539033 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,348 @@
/*
* YUI Extensions 0.33 RC2
* Copyright(c) 2006, Jack Slocum.
*/
YAHOO.ext.DatePicker = function(id, parentElement){
this.id = id;
this.selectedDate = new Date();
this.visibleDate = new Date();
this.element = null;
this.shadow = null;
this.callback = null;
this.buildControl(parentElement || document.body);
this.mouseDownHandler = YAHOO.ext.EventManager.wrap(this.handleMouseDown, this, true);
this.keyDownHandler = YAHOO.ext.EventManager.wrap(this.handleKeyDown, this, true);
this.wheelHandler = YAHOO.ext.EventManager.wrap(this.handleMouseWheel, this, true);
};
YAHOO.ext.DatePicker.prototype = {
show : function(x, y, value, callback){
this.hide();
this.selectedDate = value;
this.visibleDate = value;
this.callback = callback;
this.refresh();
this.element.show();
this.element.setXY(this.constrainToViewport ? this.constrainXY(x, y) : [x, y]);
this.shadow.show();
this.shadow.setRegion(this.element.getRegion());
this.element.dom.tabIndex = 1;
this.element.focus();
YAHOO.util.Event.on(document, "mousedown", this.mouseDownHandler);
YAHOO.util.Event.on(document, "keydown", this.keyDownHandler);
YAHOO.util.Event.on(document, "mousewheel", this.wheelHandler);
YAHOO.util.Event.on(document, "DOMMouseScroll", this.wheelHandler);
},
constrainXY : function(x, y){
var w = YAHOO.util.Dom.getViewportWidth();
var h = YAHOO.util.Dom.getViewportHeight();
var size = this.element.getSize();
return [
Math.min(w-size.width, x),
Math.min(h-size.height, y)
];
},
hide : function(){
this.shadow.hide();
this.element.hide();
YAHOO.util.Event.removeListener(document, "mousedown", this.mouseDownHandler);
YAHOO.util.Event.removeListener(document, "keydown", this.keyDownHandler);
YAHOO.util.Event.removeListener(document, "mousewheel", this.wheelHandler);
YAHOO.util.Event.removeListener(document, "DOMMouseScroll", this.wheelHandler);
},
setSelectedDate : function(date){
this.selectedDate = date;
},
getSelectedDate : function(){
return this.selectedDate;
},
showPrevMonth : function(){
this.visibleDate = this.getPrevMonth(this.visibleDate);
this.refresh();
},
showNextMonth : function(){
this.visibleDate = this.getNextMonth(this.visibleDate);
this.refresh();
},
showPrevYear : function(){
var d = this.visibleDate;
this.visibleDate = new Date(d.getFullYear()-1, d.getMonth(), d.getDate());
this.refresh();
},
showNextYear : function(){
var d = this.visibleDate;
this.visibleDate = new Date(d.getFullYear()+1, d.getMonth(), d.getDate());
this.refresh();
},
handleMouseDown : function(e){
var target = e.getTarget();
if(target != this.element.dom && !YAHOO.util.Dom.isAncestor(this.element.dom, target)){
this.hide();
}
},
handleKeyDown : function(e){
switch(e.browserEvent.keyCode){
case e.LEFT:
this.showPrevMonth();
e.stopEvent();
break;
case e.RIGHT:
this.showNextMonth();
e.stopEvent();
break;
case e.DOWN:
this.showPrevYear();
e.stopEvent();
break;
case e.UP:
this.showNextYear();
e.stopEvent();
break;
}
},
handleMouseWheel : function(e){
var delta = e.getWheelDelta();
if(delta > 0){
this.showPrevMonth();
e.stopEvent();
} else if(delta < 0){
this.showNextMonth();
e.stopEvent();
}
},
handleClick : function(e){
var d = this.visibleDate;
var t = e.getTarget();
if(t && t.className){
switch(t.className){
case 'active':
this.handleSelection(new Date(d.getFullYear(), d.getMonth(), parseInt(t.innerHTML)));
break;
case 'prevday':
var p = this.getPrevMonth(d);
this.handleSelection(new Date(p.getFullYear(), p.getMonth(), parseInt(t.innerHTML)));
break;
case 'nextday':
var n = this.getNextMonth(d);
this.handleSelection(new Date(n.getFullYear(), n.getMonth(), parseInt(t.innerHTML)));
break;
case 'ypopcal-today':
this.handleSelection(new Date());
break;
case 'next-month':
this.showNextMonth();
break;
case 'prev-month':
this.showPrevMonth();
break;
}
}
e.stopEvent();
},
selectToday : function(){
this.handleSelection(new Date());
},
handleSelection: function(date){
this.selectedDate = date;
this.callback(date);
this.hide();
},
getPrevMonth : function(d){
var m = d.getMonth();var y = d.getFullYear();
return (m == 0 ? new Date(--y, 11, 1) : new Date(y, --m, 1));
},
getNextMonth : function(d){
var m = d.getMonth();var y = d.getFullYear();
return (m == 11 ? new Date(++y, 0, 1) : new Date(y, ++m, 1));
},
getDaysInMonth : function(m, y){
return (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) ? 31 : (m == 4 || m == 6 || m == 9 || m == 11) ? 30 : this.isLeapYear(y) ? 29 : 28;
},
isLeapYear : function(y){
return (((y % 4) == 0) && ((y % 100) != 0) || ((y % 400) == 0));
},
clearTime : function(date){
if(date){
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
}
return date;
},
refresh : function(){
var d = this.visibleDate;
this.buildInnerCal(d);
this.calHead.update(this.monthNames[d.getMonth()] + ' ' + d.getFullYear());
if(this.element.isVisible()){
this.shadow.setRegion(this.element.getRegion());
}
}
};
/**
* This code is not pretty, but it is fast!
* @ignore
*/
YAHOO.ext.DatePicker.prototype.buildControl = function(parentElement){
var c = document.createElement('div');
c.style.position = 'absolute';
c.style.visibility = 'hidden';
document.body.appendChild(c);
var html = '<iframe id="'+this.id+'_shdw" frameborder="0" style="position:absolute; z-index:2000; display:none; top:0px; left:0px;" class="ypopcal-shadow"></iframe>' +
'<div hidefocus="true" class="ypopcal" id="'+this.id+'" style="-moz-outline:none; position:absolute; z-index:2001; display:none; top:0px; left:0px;">' +
'<table class="ypopcal-head" border=0 cellpadding=0 cellspacing=0><tbody><tr><td class="ypopcal-arrow"><div class="prev-month">&#160;</div></td><td class="ypopcal-month">&#160;</td><td class="ypopcal-arrow"><div class="next-month">&#160;</div></td></tr></tbody></table>' +
'<center><div class="ypopcal-inner">';
html += "<table border=0 cellpadding=2 cellspacing=0 class=\"ypopcal-table\"><thead><tr class=\"ypopcal-daynames\">";
var names = this.dayNames;
for(var i = 0; i < names.length; i++){
html += '<td>' + names[i].substr(0, 1) + '</td>';
}
html+= "</tr></thead><tbody><tr>";
for(var i = 0; i < 42; i++) {
if(i % 7 == 0 && i != 0){
html += '</tr><tr>';
}
html += "<td>&nbsp;</td>";
}
html += "</tr></tbody></table>";
html += '</div><button class="ypopcal-today" style="margin-top:2px;">'+this.todayText+'</button></center></div>';
c.innerHTML = html;
this.shadow = getEl(c.childNodes[0], true);
this.shadow.enableDisplayMode();
this.element = getEl(c.childNodes[1], true);
this.element.enableDisplayMode();
document.body.appendChild(this.shadow.dom);
document.body.appendChild(this.element.dom);
document.body.removeChild(c);
this.element.on("selectstart", function(){return false;});
var tbody = this.element.dom.getElementsByTagName('tbody')[1];
this.cells = tbody.getElementsByTagName('td');
this.calHead = this.element.getChildrenByClassName('ypopcal-month', 'td')[0];
this.element.mon('mousedown', this.handleClick, this, true);
};
YAHOO.ext.DatePicker.prototype.buildInnerCal = function(dateVal){
var days = this.getDaysInMonth(dateVal.getMonth() + 1, dateVal.getFullYear());
var firstOfMonth = new Date(dateVal.getFullYear(), dateVal.getMonth(), 1);
var startingPos = firstOfMonth.getDay();
if(startingPos == 0) startingPos = 7;
var pm = this.getPrevMonth(dateVal);
var prevStart = this.getDaysInMonth(pm.getMonth()+1, pm.getFullYear())-startingPos;
var cells = this.cells;
days += startingPos;
// convert everything to numbers so it's fast
var day = 86400000;
var date = this.clearTime(new Date(pm.getFullYear(), pm.getMonth(), prevStart));
var today = this.clearTime(new Date()).getTime();
var sel = this.selectedDate ? this.clearTime(this.selectedDate).getTime() : today + 1; //today +1 will never match anything
var min = this.minDate ? this.clearTime(this.minDate).getTime() : Number.NEGATIVE_INFINITY;
var max = this.maxDate ? this.clearTime(this.maxDate).getTime() : Number.POSITIVE_INFINITY;
var ddMatch = this.disabledDatesRE;
var ddText = this.disabledDatesText;
var ddays = this.disabledDays;
var ddaysText = this.disabledDaysText;
var format = this.format;
var setCellClass = function(cal, cell, d){
cell.title = '';
var t = d.getTime();
if(t == today){
cell.className += ' today';
cell.title = cal.todayText;
}
if(t == sel){
cell.className += ' selected';
}
// disabling
if(t < min) {
cell.className = ' ypopcal-disabled';
cell.title = cal.minText;
return;
}
if(t > max) {
cell.className = ' ypopcal-disabled';
cell.title = cal.maxText;
return;
}
if(ddays){
var day = d.getDay();
for(var i = 0; i < ddays.length; i++) {
if(day === ddays[i]){
cell.title = ddaysText;
cell.className = ' ypopcal-disabled';
return;
}
}
}
if(ddMatch && format){
var fvalue = d.format(format);
if(ddMatch.test(fvalue)){
cell.title = ddText.replace('%0', fvalue);
cell.className = ' ypopcal-disabled';
return;
}
}
};
var i = 0;
for(; i < startingPos; i++) {
cells[i].innerHTML = (++prevStart);
date.setDate(date.getDate()+1);
cells[i].className = 'prevday';
setCellClass(this, cells[i], date);
}
for(; i < days; i++){
intDay = i - startingPos + 1;
cells[i].innerHTML = (intDay);
date.setDate(date.getDate()+1);
cells[i].className = 'active';
setCellClass(this, cells[i], date);
}
var extraDays = 0;
for(; i < 42; i++) {
cells[i].innerHTML = (++extraDays);
date.setDate(date.getDate()+1);
cells[i].className = 'nextday';
setCellClass(this, cells[i], date);
}
};
YAHOO.ext.DatePicker.prototype.todayText = "Today";
YAHOO.ext.DatePicker.prototype.minDate = null;
YAHOO.ext.DatePicker.prototype.maxDate = null;
YAHOO.ext.DatePicker.prototype.minText = "This date is before the minimum date";
YAHOO.ext.DatePicker.prototype.maxText = "This date is after the maximum date";
YAHOO.ext.DatePicker.prototype.format = 'm/d/y';
YAHOO.ext.DatePicker.prototype.disabledDays = null;
YAHOO.ext.DatePicker.prototype.disabledDaysText = '';
YAHOO.ext.DatePicker.prototype.disabledDatesRE = null;
YAHOO.ext.DatePicker.prototype.disabledDatesText = '';
YAHOO.ext.DatePicker.prototype.constrainToViewport = true;
YAHOO.ext.DatePicker.prototype.monthNames = Date.monthNames;
YAHOO.ext.DatePicker.prototype.dayNames = Date.dayNames;

View file

@ -0,0 +1,567 @@
/*
* YUI Extensions 0.33 RC2
* Copyright(c) 2006, Jack Slocum.
*/
/**
* @class YAHOO.ext.Resizable
* @extends YAHOO.ext.util.Observable
* <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
* and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
* the textarea in a div and set "resizeChild" to true (or the id of the textarea), <b>or</b> set wrap:true in your config and
* the element will be wrapped for you automatically.</p><br/>
* Here's a Resizable with every possible config option and it's default value:
<pre><code>
var resizer = new YAHOO.ext.Resizable('element-id', {
resizeChild : false,
adjustments : [0, 0],
minWidth : 5,
minHeight : 5,
maxWidth : 10000,
maxHeight : 10000,
enabled : true,
wrap: false, // true to wrap the element
width: null, // initial size
height: null, // initial size
animate : false,
duration : .35,
dynamic : false,
handles : false,
multiDirectional : false,
disableTrackOver : false,
easing : YAHOO.util.Easing ? YAHOO.util.Easing.easeOutStrong : null,
widthIncrement : 0,
heightIncrement : 0,
pinned : false,
width : null,
height : null,
preserveRatio : false,
transparent: false,
minX: 0,
minY: 0,
draggable: false
});
resizer.on('resize', myHandler);
</code></pre>
* <p>
* To hide a particular handle, set it's display to none in CSS, or through script:<br>
* resizer.east.setDisplayed(false);
* </p>
* @constructor
* Create a new resizable component
* @param {String/HTMLElement/YAHOO.ext.Element} el The id or element to resize
* @param {Object} config configuration options
*/
YAHOO.ext.Resizable = function(el, config){
this.el = getEl(el);
if(config && config.wrap){
config.resizeChild = this.el;
this.el = this.el.wrap(typeof config.wrap == 'object' ? config.wrap : null);
this.el.id = this.el.dom.id = config.resizeChild.id + '-rzwrap';
this.el.setStyle('overflow', 'hidden');
this.el.setPositioning(config.resizeChild.getPositioning());
config.resizeChild.clearPositioning();
if(!config.width || !config.height){
var csize = config.resizeChild.getSize();
//csize.width -= config.adjustments[0];
//csize.height -= config.adjustments[1];
this.el.setSize(csize.width, csize.height);
}
if(config.pinned && !config.adjustments){
config.adjustments = 'auto';
}
}
this.proxy = this.el.createProxy({tag: 'div', cls: 'yresizable-proxy', id: this.el.id + '-rzproxy'})
this.proxy.unselectable();
// the overlay traps mouse events while dragging and fixes iframe issue
this.overlay = this.el.createProxy({tag: 'div', cls: 'yresizable-overlay', html: '&#160;'});
this.overlay.unselectable();
this.overlay.enableDisplayMode('block');
this.overlay.mon('mousemove', this.onMouseMove, this, true);
this.overlay.mon('mouseup', this.onMouseUp, this, true);
YAHOO.ext.util.Config.apply(this, config, {
/** True to resizeSize the first child or id/element to resize @type YAHOO.ext.Element */
resizeChild : false,
/** String "auto" or an array [width, height] with values to be <b>added</b> to the resize operation's new size. @type Array/String */
adjustments : [0, 0],
/** The minimum width for the element @type Number */
minWidth : 5,
/** The minimum height for the element @type Number */
minHeight : 5,
/** The maximum width for the element @type Number */
maxWidth : 10000,
/** The maximum height for the element @type Number */
maxHeight : 10000,
/** false to disable resizing @type Boolean */
enabled : true,
/** True to animate the resize (not compatible with dynamic sizing) @type Boolean */
animate : false,
/** Animation duration @type Float */
duration : .35,
/** True to resize the element while dragging instead of using a proxy @type Boolean */
dynamic : false,
// these 3 are only available at config time
/** String consisting of the resize handles to display. Valid handles are
* n (north), s (south) e (east), w (west), ne (northeast), nw (northwest), se (southeast), sw (southwest)
* and all (which applies them all). If this is blank it defaults to "e,s,se". Handles can be delimited using
* a space, comma or semi-colon. This is only applied at config time. @type String*/
handles : false,
multiDirectional : false,
/** true to disable mouse tracking. This is only applied at config time. @type Boolean*/
disableTrackOver : false,
/** Animation easing @type YAHOO.util.Easing */
easing : YAHOO.util.Easing ? YAHOO.util.Easing.easeOutStrong : null,
/** The increment to snap the width resize in pixels (dynamic must be true) @type Number */
widthIncrement : 0,
/** The increment to snap the height resize in pixels (dynamic must be true) @type Number */
heightIncrement : 0,
/** true to pin the resize handles. This is only applied at config time. @type Boolean*/
pinned : false,
/** The initial width for the element @type Number */
width : null,
/** The initial height for the element @type Number */
height : null,
/** true to preserve the initial size ratio. @type Boolean*/
preserveRatio : false,
/** true for transparent handles. This is only applied at config time. @type Boolean*/
transparent: false,
/** The minimum allowed page X for the element (only used for west resizing, defaults to 0) @type Number */
minX: 0,
/** The minimum allowed page Y for the element (only used for north resizing, defaults to 0) @type Number */
minY: 0,
/** convenience to initialize drag drop. @type Boolean*/
draggable: false
});
if(this.pinned){
this.disableTrackOver = true;
this.el.addClass('yresizable-pinned');
}
// if the element isn't positioned, make it relative
if(this.el.getStyle('position') != 'absolute'){
this.el.setStyle('position', 'relative');
}
if(!this.handles){ // no handles passed, must be legacy style
this.handles = 's,e,se';
if(this.multiDirectional){
this.handles += ',n,w';
}
}
if(this.handles == 'all'){
this.handles = 'n s e w ne nw se sw';
}
var hs = this.handles.split(/\s*?[,;]\s*?| /);
var ps = YAHOO.ext.Resizable.positions;
for(var i = 0, len = hs.length; i < len; i++){
if(hs[i] && ps[hs[i]]){
var pos = ps[hs[i]];
this[pos] = new YAHOO.ext.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
}
}
// legacy
this.corner = this.southeast;
this.activeHandle = null;
if(this.resizeChild){
if(typeof this.resizeChild == 'boolean'){
this.resizeChild = YAHOO.ext.Element.get(this.el.dom.firstChild, true);
}else{
this.resizeChild = YAHOO.ext.Element.get(this.resizeChild, true);
}
}
if(this.adjustments == 'auto'){
var rc = this.resizeChild;
var hw = this.west, he = this.east, hn = this.north, hs = this.south;
if(rc && (hw || hn)){
rc.setRelativePositioned();
rc.setLeft(hw ? hw.el.getWidth() : 0);
rc.setTop(hn ? hn.el.getHeight() : 0);
}
this.adjustments = [
(he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
(hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
];
}
if(this.draggable){
this.dd = this.dynamic ?
this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
}
// public events
this.events = {
/**
* @event beforeresize
* Fired before resize is allowed. Set enabled to false to cancel resize.
* @param {YAHOO.ext.Resizable} this
* @param {YAHOO.ext.EventObject} e The mousedown event
*/
'beforeresize' : new YAHOO.util.CustomEvent(),
/**
* @event resize
* Fired after a resize.
* @param {YAHOO.ext.Resizable} this
* @param {Number} width The new width
* @param {Number} height The new height
* @param {YAHOO.ext.EventObject} e The mouseup event
*/
'resize' : new YAHOO.util.CustomEvent()
};
if(this.width !== null && this.height !== null){
this.resizeTo(this.width, this.height);
}else{
this.updateChildSize();
}
};
YAHOO.extendX(YAHOO.ext.Resizable, YAHOO.ext.util.Observable, {
/**
* Perform a manual resize
* @param {Number} width
* @param {Number} height
*/
resizeTo : function(width, height){
this.el.setSize(width, height);
this.updateChildSize();
this.fireEvent('resize', this, width, height, null);
},
startSizing : function(e){
this.fireEvent('beforeresize', this, e);
if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
this.resizing = true;
this.startBox = this.el.getBox();
this.startPoint = e.getXY();
this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
(this.startBox.y + this.startBox.height) - this.startPoint[1]];
this.proxy.setBox(this.startBox);
this.overlay.setSize(YAHOO.util.Dom.getDocumentWidth(), YAHOO.util.Dom.getDocumentHeight());
this.overlay.show();
if(!this.dynamic){
this.proxy.show();
}
}
},
onMouseDown : function(handle, e){
if(this.enabled){
e.stopEvent();
this.activeHandle = handle;
this.overlay.setStyle('cursor', handle.el.getStyle('cursor'));
this.startSizing(e);
}
},
onMouseUp : function(e){
var size = this.resizeElement();
this.resizing = false;
this.handleOut();
this.overlay.hide();
this.fireEvent('resize', this, size.width, size.height, e);
},
updateChildSize : function(){
if(this.resizeChild){
var el = this.el;
var child = this.resizeChild;
var adj = this.adjustments;
if(el.dom.offsetWidth){
var b = el.getSize(true);
child.setSize(b.width+adj[0], b.height+adj[1]);
}
// Second call here for IE
// The first call enables instant resizing and
// the second call corrects scroll bars if they
// exist
if(YAHOO.ext.util.Browser.isIE){
setTimeout(function(){
if(el.dom.offsetWidth){
var b = el.getSize(true);
child.setSize(b.width+adj[0], b.height+adj[1]);
}
}, 10);
}
}
},
snap : function(value, inc, min){
if(!inc || !value) return value;
var newValue = value;
var m = value % inc;
if(m > 0){
if(m > (inc/2)){
newValue = value + (inc-m);
}else{
newValue = value - m;
}
}
return Math.max(min, newValue);
},
resizeElement : function(){
var box = this.proxy.getBox();
//box.width = this.snap(box.width, this.widthIncrement);
//box.height = this.snap(box.height, this.heightIncrement);
//if(this.multiDirectional){
this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
//}else{
// this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
//}
this.updateChildSize();
this.proxy.hide();
return box;
},
constrain : function(v, diff, m, mx){
if(v - diff < m){
diff = v - m;
}else if(v - diff > mx){
diff = mx - v;
}
return diff;
},
onMouseMove : function(e){
if(this.enabled){
try{// try catch so if something goes wrong the user doesn't get hung
//var curXY = this.startPoint;
var curSize = this.curSize || this.startBox;
var x = this.startBox.x, y = this.startBox.y;
var ox = x, oy = y;
var w = curSize.width, h = curSize.height;
var ow = w, oh = h;
var mw = this.minWidth, mh = this.minHeight;
var mxw = this.maxWidth, mxh = this.maxHeight;
var wi = this.widthIncrement;
var hi = this.heightIncrement;
var eventXY = e.getXY();
var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
var pos = this.activeHandle.position;
switch(pos){
case 'east':
w += diffX;
w = Math.min(Math.max(mw, w), mxw);
break;
case 'south':
h += diffY;
h = Math.min(Math.max(mh, h), mxh);
break;
case 'southeast':
w += diffX;
h += diffY;
w = Math.min(Math.max(mw, w), mxw);
h = Math.min(Math.max(mh, h), mxh);
break;
case 'north':
diffY = this.constrain(h, diffY, mh, mxh);
y += diffY;
h -= diffY;
break;
case 'west':
diffX = this.constrain(w, diffX, mw, mxw);
x += diffX;
w -= diffX;
break;
case 'northeast':
w += diffX;
w = Math.min(Math.max(mw, w), mxw);
diffY = this.constrain(h, diffY, mh, mxh);
y += diffY;
h -= diffY;
break;
case 'northwest':
diffX = this.constrain(w, diffX, mw, mxw);
diffY = this.constrain(h, diffY, mh, mxh);
y += diffY;
h -= diffY;
x += diffX;
w -= diffX;
break;
case 'southwest':
diffX = this.constrain(w, diffX, mw, mxw);
h += diffY;
h = Math.min(Math.max(mh, h), mxh);
x += diffX;
w -= diffX;
break;
}
var sw = this.snap(w, wi, mw);
var sh = this.snap(h, hi, mh);
if(sw != w || sh != h){
switch(pos){
case 'northeast':
y -= sh - h;
break;
case 'north':
y -= sh - h;
break;
case 'southwest':
x -= sw - w;
break;
case 'west':
x -= sw - w;
break;
case 'northwest':
x -= sw - w;
y -= sh - h;
break;
}
w = sw;
h = sh;
}
if(this.preserveRatio){
switch(pos){
case 'southeast':
case 'east':
h = oh * (w/ow);
h = Math.min(Math.max(mh, h), mxh);
w = ow * (h/oh);
break;
case 'south':
w = ow * (h/oh);
w = Math.min(Math.max(mw, w), mxw);
h = oh * (w/ow);
break;
case 'northeast':
w = ow * (h/oh);
w = Math.min(Math.max(mw, w), mxw);
h = oh * (w/ow);
break;
case 'north':
var tw = w;
w = ow * (h/oh);
w = Math.min(Math.max(mw, w), mxw);
h = oh * (w/ow);
x += (tw - w) / 2;
break;
case 'southwest':
h = oh * (w/ow);
h = Math.min(Math.max(mh, h), mxh);
var tw = w;
w = ow * (h/oh);
x += tw - w;
break;
case 'west':
var th = h;
h = oh * (w/ow);
h = Math.min(Math.max(mh, h), mxh);
y += (th - h) / 2;
var tw = w;
w = ow * (h/oh);
x += tw - w;
break;
case 'northwest':
var tw = w;
var th = h;
h = oh * (w/ow);
h = Math.min(Math.max(mh, h), mxh);
w = ow * (h/oh);
y += th - h;
x += tw - w;
break;
}
}
this.proxy.setBounds(x, y, w, h);
if(this.dynamic){
this.resizeElement();
}
}catch(e){}
}
},
handleOver : function(){
if(this.enabled){
this.el.addClass('yresizable-over');
}
},
handleOut : function(){
if(!this.resizing){
this.el.removeClass('yresizable-over');
}
},
/**
* Returns the element this component is bound to.
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
},
/**
* Returns the resizeChild element (or null).
* @return {YAHOO.ext.Element}
*/
getResizeChild : function(){
return this.resizeChild;
}
});
// hash to map config positions to true positions
YAHOO.ext.Resizable.positions = {
n: 'north', s: 'south', e: 'east', w: 'west', se: 'southeast', sw: 'southwest', nw: 'northwest', ne: 'northeast'
};
YAHOO.ext.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
if(!this.tpl){
// only initialize the template if resizable is used
var tpl = YAHOO.ext.DomHelper.createTemplate(
{tag: 'div', cls: 'yresizable-handle yresizable-handle-{0}', html: '&#160;'}
);
tpl.compile();
YAHOO.ext.Resizable.Handle.prototype.tpl = tpl;
}
this.position = pos;
this.rz = rz;
this.el = this.tpl.append(rz.el.dom, [this.position], true);
this.el.unselectable();
if(transparent){
this.el.setOpacity(0);
}
this.el.mon('mousedown', this.onMouseDown, this, true);
if(!disableTrackOver){
this.el.mon('mouseover', this.onMouseOver, this, true);
this.el.mon('mouseout', this.onMouseOut, this, true);
}
};
YAHOO.ext.Resizable.Handle.prototype = {
afterResize : function(rz){
// do nothing
},
onMouseDown : function(e){
this.rz.onMouseDown(this, e);
},
onMouseOver : function(e){
this.rz.handleOver(this, e);
},
onMouseOut : function(e){
this.rz.handleOut(this, e);
}
};

View file

@ -0,0 +1,455 @@
/*
* YUI Extensions 0.33 RC2
* Copyright(c) 2006, Jack Slocum.
*/
/*
* splitbar.js, version .7
* Copyright(c) 2006, Jack Slocum.
* Code licensed under the BSD License
*/
if(YAHOO.util.DragDropMgr){
YAHOO.util.DragDropMgr.clickTimeThresh = 350;
}
/**
* @class YAHOO.ext.SplitBar
* @extends YAHOO.ext.util.Observable
* Creates draggable splitter bar functionality from two elements.
* <br><br>
* Usage:
* <pre><code>
var split = new YAHOO.ext.SplitBar('elementToDrag', 'elementToSize',
YAHOO.ext.SplitBar.HORIZONTAL, YAHOO.ext.SplitBar.LEFT);
split.setAdapter(new YAHOO.ext.SplitBar.AbsoluteLayoutAdapter("container"));
split.minSize = 100;
split.maxSize = 600;
split.animate = true;
split.onMoved.subscribe(splitterMoved);
</code></pre>
* @requires YAHOO.ext.Element
* @requires YAHOO.util.Dom
* @requires YAHOO.util.Event
* @requires YAHOO.util.CustomEvent
* @requires YAHOO.util.DDProxy
* @requires YAHOO.util.Anim (optional) to support animation
* @requires YAHOO.util.Easing (optional) to support animation
* @constructor
* Create a new SplitBar
* @param {String/HTMLElement/Element} dragElement The element to be dragged and act as the SplitBar.
* @param {String/HTMLElement/Element} resizingElement The element to be resized based on where the SplitBar element is dragged
* @param {Number} orientation (optional) Either YAHOO.ext.SplitBar.HORIZONTAL or YAHOO.ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
* @param {Number} placement (optional) Either YAHOO.ext.SplitBar.LEFT or YAHOO.ext.SplitBar.RIGHT for horizontal or
YAHOO.ext.SplitBar.TOP or YAHOO.ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the intial position
position of the SplitBar).
*/
YAHOO.ext.SplitBar = function(dragElement, resizingElement, orientation, placement){
/** @private */
this.el = YAHOO.ext.Element.get(dragElement, true);
this.el.dom.unselectable = 'on';
/** @private */
this.resizingEl = YAHOO.ext.Element.get(resizingElement, true);
/**
* @private
* The orientation of the split. Either YAHOO.ext.SplitBar.HORIZONTAL or YAHOO.ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
* Note: If this is changed after creating the SplitBar, the placement property must be manually updated
* @type Number
*/
this.orientation = orientation || YAHOO.ext.SplitBar.HORIZONTAL;
/**
* The minimum size of the resizing element. (Defaults to 0)
* @type Number
*/
this.minSize = 0;
/**
* The maximum size of the resizing element. (Defaults to 2000)
* @type Number
*/
this.maxSize = 2000;
this.onMoved = new YAHOO.util.CustomEvent("SplitBarMoved", this);
/**
* Whether to animate the transition to the new size
* @type Boolean
*/
this.animate = false;
/**
* Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
* @type Boolean
*/
this.useShim = false;
/** @private */
this.shim = null;
/** @private */
this.proxy = YAHOO.ext.SplitBar.createProxy(this.orientation);
/** @private */
this.dd = new YAHOO.util.DDProxy(this.el.dom.id, "SplitBars", {dragElId : this.proxy.id});
/** @private */
this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
/** @private */
this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
/** @private */
this.dragSpecs = {};
/**
* @private The adapter to use to positon and resize elements
*/
this.adapter = new YAHOO.ext.SplitBar.BasicLayoutAdapter();
this.adapter.init(this);
if(this.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
/** @private */
this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? YAHOO.ext.SplitBar.LEFT : YAHOO.ext.SplitBar.RIGHT);
this.el.setStyle('cursor', 'e-resize');
}else{
/** @private */
this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? YAHOO.ext.SplitBar.TOP : YAHOO.ext.SplitBar.BOTTOM);
this.el.setStyle('cursor', 'n-resize');
}
this.events = {
/**
* @event resize
* Fires when the splitter is moved (alias for moved)
* @param {YAHOO.ext.SplitBar} this
* @param {Number} newSize the new width or height
*/
'resize' : this.onMoved,
/**
* @event moved
* Fires when the splitter is moved
* @param {YAHOO.ext.SplitBar} this
* @param {Number} newSize the new width or height
*/
'moved' : this.onMoved,
/**
* @event beforeresize
* Fires before the splitter is dragged
* @param {YAHOO.ext.SplitBar} this
*/
'beforeresize' : new YAHOO.util.CustomEvent('beforeresize')
}
}
YAHOO.extendX(YAHOO.ext.SplitBar, YAHOO.ext.util.Observable, {
onStartProxyDrag : function(x, y){
this.fireEvent('beforeresize', this);
if(this.useShim){
if(!this.shim){
this.shim = YAHOO.ext.SplitBar.createShim();
}
this.shim.setVisible(true);
}
YAHOO.util.Dom.setStyle(this.proxy, 'display', 'block');
var size = this.adapter.getElementSize(this);
this.activeMinSize = this.getMinimumSize();;
this.activeMaxSize = this.getMaximumSize();;
var c1 = size - this.activeMinSize;
var c2 = Math.max(this.activeMaxSize - size, 0);
if(this.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
this.dd.resetConstraints();
this.dd.setXConstraint(
this.placement == YAHOO.ext.SplitBar.LEFT ? c1 : c2,
this.placement == YAHOO.ext.SplitBar.LEFT ? c2 : c1
);
this.dd.setYConstraint(0, 0);
}else{
this.dd.resetConstraints();
this.dd.setXConstraint(0, 0);
this.dd.setYConstraint(
this.placement == YAHOO.ext.SplitBar.TOP ? c1 : c2,
this.placement == YAHOO.ext.SplitBar.TOP ? c2 : c1
);
}
this.dragSpecs.startSize = size;
this.dragSpecs.startPoint = [x, y];
YAHOO.util.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
},
/**
* @private Called after the drag operation by the DDProxy
*/
onEndProxyDrag : function(e){
YAHOO.util.Dom.setStyle(this.proxy, 'display', 'none');
var endPoint = YAHOO.util.Event.getXY(e);
if(this.useShim){
this.shim.setVisible(false);
}
var newSize;
if(this.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
newSize = this.dragSpecs.startSize +
(this.placement == YAHOO.ext.SplitBar.LEFT ?
endPoint[0] - this.dragSpecs.startPoint[0] :
this.dragSpecs.startPoint[0] - endPoint[0]
);
}else{
newSize = this.dragSpecs.startSize +
(this.placement == YAHOO.ext.SplitBar.TOP ?
endPoint[1] - this.dragSpecs.startPoint[1] :
this.dragSpecs.startPoint[1] - endPoint[1]
);
}
newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
if(newSize != this.dragSpecs.startSize){
this.adapter.setElementSize(this, newSize);
this.onMoved.fireDirect(this, newSize);
}
},
/**
* Get the adapter this SplitBar uses
* @return The adapter object
*/
getAdapter : function(){
return this.adapter;
},
/**
* Set the adapter this SplitBar uses
* @param {Object} adapter A SplitBar adapter object
*/
setAdapter : function(adapter){
this.adapter = adapter;
this.adapter.init(this);
},
/**
* Gets the minimum size for the resizing element
* @return {Number} The minimum size
*/
getMinimumSize : function(){
return this.minSize;
},
/**
* Sets the minimum size for the resizing element
* @param {Number} minSize The minimum size
*/
setMinimumSize : function(minSize){
this.minSize = minSize;
},
/**
* Gets the maximum size for the resizing element
* @return {Number} The maximum size
*/
getMaximumSize : function(){
return this.maxSize;
},
/**
* Sets the maximum size for the resizing element
* @param {Number} maxSize The maximum size
*/
setMaximumSize : function(maxSize){
this.maxSize = maxSize;
},
/**
* Sets the initialize size for the resizing element
* @param {Number} size The initial size
*/
setCurrentSize : function(size){
var oldAnimate = this.animate;
this.animate = false;
this.adapter.setElementSize(this, size);
this.animate = oldAnimate;
}
});
/**
* @private static Create the shim to drag over iframes
*/
YAHOO.ext.SplitBar.createShim = function(){
var shim = document.createElement('div');
shim.unselectable = 'on';
YAHOO.util.Dom.generateId(shim, 'split-shim');
YAHOO.util.Dom.setStyle(shim, 'width', '100%');
YAHOO.util.Dom.setStyle(shim, 'height', '100%');
YAHOO.util.Dom.setStyle(shim, 'position', 'absolute');
YAHOO.util.Dom.setStyle(shim, 'background', 'white');
YAHOO.util.Dom.setStyle(shim, 'z-index', 11000);
window.document.body.appendChild(shim);
var shimEl = YAHOO.ext.Element.get(shim);
shimEl.setOpacity(.01);
shimEl.setXY([0, 0]);
return shimEl;
};
/**
* @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
*/
YAHOO.ext.SplitBar.createProxy = function(orientation){
var proxy = document.createElement('div');
proxy.unselectable = 'on';
YAHOO.util.Dom.generateId(proxy, 'split-proxy');
YAHOO.util.Dom.setStyle(proxy, 'position', 'absolute');
YAHOO.util.Dom.setStyle(proxy, 'visibility', 'hidden');
YAHOO.util.Dom.setStyle(proxy, 'z-index', 11001);
YAHOO.util.Dom.setStyle(proxy, 'background-color', "#aaa");
if(orientation == YAHOO.ext.SplitBar.HORIZONTAL){
YAHOO.util.Dom.setStyle(proxy, 'cursor', 'e-resize');
}else{
YAHOO.util.Dom.setStyle(proxy, 'cursor', 'n-resize');
}
// the next 2 fix IE abs position div height problem
YAHOO.util.Dom.setStyle(proxy, 'line-height', '0px');
YAHOO.util.Dom.setStyle(proxy, 'font-size', '0px');
window.document.body.appendChild(proxy);
return proxy;
};
/**
* @class YAHOO.ext.SplitBar.BasicLayoutAdapter
* Default Adapter. It assumes the splitter and resizing element are not positioned
* elements and only gets/sets the width of the element. Generally used for table based layouts.
*/
YAHOO.ext.SplitBar.BasicLayoutAdapter = function(){
};
YAHOO.ext.SplitBar.BasicLayoutAdapter.prototype = {
// do nothing for now
init : function(s){
},
/**
* Called before drag operations to get the current size of the resizing element.
* @param {YAHOO.ext.SplitBar} s The SplitBar using this adapter
*/
getElementSize : function(s){
if(s.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
return s.resizingEl.getWidth();
}else{
return s.resizingEl.getHeight();
}
},
/**
* Called after drag operations to set the size of the resizing element.
* @param {YAHOO.ext.SplitBar} s The SplitBar using this adapter
* @param {Number} newSize The new size to set
* @param {Function} onComplete A function to be invoke when resizing is complete
*/
setElementSize : function(s, newSize, onComplete){
if(s.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
if(!YAHOO.util.Anim || !s.animate){
s.resizingEl.setWidth(newSize);
if(onComplete){
onComplete(s, newSize);
}
}else{
s.resizingEl.setWidth(newSize, true, .1, onComplete, YAHOO.util.Easing.easeOut);
}
}else{
if(!YAHOO.util.Anim || !s.animate){
s.resizingEl.setHeight(newSize);
if(onComplete){
onComplete(s, newSize);
}
}else{
s.resizingEl.setHeight(newSize, true, .1, onComplete, YAHOO.util.Easing.easeOut);
}
}
}
};
/**
*@class YAHOO.ext.SplitBar.AbsoluteLayoutAdapter
* @extends YAHOO.ext.SplitBar.BasicLayoutAdapter
* Adapter that moves the splitter element to align with the resized sizing element.
* Used with an absolute positioned SplitBar.
* @param {String/HTMLElement/Element} container The container that wraps around the absolute positioned content. If it's
* document.body, make sure you assign an id to the body element.
*/
YAHOO.ext.SplitBar.AbsoluteLayoutAdapter = function(container){
this.basic = new YAHOO.ext.SplitBar.BasicLayoutAdapter();
this.container = getEl(container);
}
YAHOO.ext.SplitBar.AbsoluteLayoutAdapter.prototype = {
init : function(s){
this.basic.init(s);
//YAHOO.util.Event.on(window, 'resize', this.moveSplitter.createDelegate(this, [s]));
},
getElementSize : function(s){
return this.basic.getElementSize(s);
},
setElementSize : function(s, newSize, onComplete){
this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
},
moveSplitter : function(s){
var yes = YAHOO.ext.SplitBar;
switch(s.placement){
case yes.LEFT:
s.el.setX(s.resizingEl.getRight());
break;
case yes.RIGHT:
s.el.setStyle('right', (this.container.getWidth() - s.resizingEl.getLeft()) + 'px');
break;
case yes.TOP:
s.el.setY(s.resizingEl.getBottom());
break;
case yes.BOTTOM:
s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
break;
}
}
};
/**
* Orientation constant - Create a vertical SplitBar
* @static
* @type Number
*/
YAHOO.ext.SplitBar.VERTICAL = 1;
/**
* Orientation constant - Create a horizontal SplitBar
* @static
* @type Number
*/
YAHOO.ext.SplitBar.HORIZONTAL = 2;
/**
* Placement constant - The resizing element is to the left of the splitter element
* @static
* @type Number
*/
YAHOO.ext.SplitBar.LEFT = 1;
/**
* Placement constant - The resizing element is to the right of the splitter element
* @static
* @type Number
*/
YAHOO.ext.SplitBar.RIGHT = 2;
/**
* Placement constant - The resizing element is positioned above the splitter element
* @static
* @type Number
*/
YAHOO.ext.SplitBar.TOP = 3;
/**
* Placement constant - The resizing element is positioned under splitter element
* @static
* @type Number
*/
YAHOO.ext.SplitBar.BOTTOM = 4;

View file

@ -0,0 +1,714 @@
/*
* YUI Extensions 0.33 RC2
* Copyright(c) 2006, Jack Slocum.
*/
/**
* @class YAHOO.ext.TabPanel
* @extends YAHOO.ext.util.Observable
* Creates a lightweight TabPanel component using Yahoo! UI.
* <br><br>
* Usage:
* <pre><code>
<font color="#008000">// basic tabs 1, built from existing content</font>
var tabs = new YAHOO.ext.TabPanel('tabs1');
tabs.addTab('script', "View Script");
tabs.addTab('markup', "View Markup");
tabs.activate('script');
<font color="#008000">// more advanced tabs, built from javascript</font>
var jtabs = new YAHOO.ext.TabPanel('jtabs');
jtabs.addTab('jtabs-1', "Normal Tab", "My content was added during construction.");
<font color="#008000">// set up the UpdateManager</font>
var tab2 = jtabs.addTab('jtabs-2', "Ajax Tab 1");
var updater = tab2.getUpdateManager();
updater.setDefaultUrl('ajax1.htm');
tab2.onActivate.subscribe(updater.refresh, updater, true);
<font color="#008000">// Use setUrl for Ajax loading</font>
var tab3 = jtabs.addTab('jtabs-3', "Ajax Tab 2");
tab3.setUrl('ajax2.htm', null, true);
<font color="#008000">// Disabled tab</font>
var tab4 = jtabs.addTab('tabs1-5', "Disabled Tab", "Can't see me cause I'm disabled");
tab4.disable();
jtabs.activate('jtabs-1');
}
* </code></pre>
* @requires YAHOO.ext.Element
* @requires YAHOO.ext.UpdateManager
* @requires YAHOO.util.Dom
* @requires YAHOO.util.Event
* @requires YAHOO.util.CustomEvent
* @requires YAHOO.util.Connect (optional)
* @constructor
* Create new TabPanel.
* @param {String/HTMLElement/Element} container The id, DOM element or YAHOO.ext.Element container where this TabPanel is to be rendered.
* @param {Boolean} config Config object to set any properties for this TabPanel or true to render the tabs on the bottom.
*/
YAHOO.ext.TabPanel = function(container, config){
/**
* The container element for this TabPanel.
* @type YAHOO.ext.Element
*/
this.el = getEl(container, true);
/** The position of the tabs. Can be 'top' or 'bottom' @type String */
this.tabPosition = 'top';
this.currentTabWidth = 0;
/** The minimum width of a tab (ignored if resizeTabs is not true). @type Number */
this.minTabWidth = 40;
/** The maximum width of a tab (ignored if resizeTabs is not true). @type Number */
this.maxTabWidth = 250;
/** The preferred (default) width of a tab (ignored if resizeTabs is not true). @type Number */
this.preferredTabWidth = 175;
/** Set this to true to enable dynamic tab resizing. @type Boolean */
this.resizeTabs = false;
/** Set this to true to turn on window resizing monitoring (ignored if resizeTabs is not true). @type Boolean */
this.monitorResize = true;
if(config){
if(typeof config == 'boolean'){
this.tabPosition = config ? 'bottom' : 'top';
}else{
YAHOO.ext.util.Config.apply(this, config);
}
}
if(this.tabPosition == 'bottom'){
this.bodyEl = getEl(this.createBody(this.el.dom));
this.el.addClass('ytabs-bottom');
}
this.stripWrap = getEl(this.createStrip(this.el.dom), true);
this.stripEl = getEl(this.createStripList(this.stripWrap.dom), true);
this.stripBody = getEl(this.stripWrap.dom.firstChild.firstChild, true);
if(this.tabPosition != 'bottom'){
/** The body element that contains TabPaneItem bodies.
* @type YAHOO.ext.Element
*/
this.bodyEl = getEl(this.createBody(this.el.dom));
this.el.addClass('ytabs-top');
}
this.items = [];
this.bodyEl.setStyle('position', 'relative');
// add indexOf to array if it isn't present
if(!this.items.indexOf){
this.items.indexOf = function(o){
for(var i = 0, len = this.length; i < len; i++){
if(this[i] == o) return i;
}
return -1;
}
}
this.active = null;
this.onTabChange = new YAHOO.util.CustomEvent('TabItem.onTabChange');
this.activateDelegate = this.activate.createDelegate(this);
this.events = {
/**
* @event tabchange
* Fires when the active tab changes
* @param {YAHOO.ext.TabPanel} this
* @param {YAHOO.ext.TabPanelItem} activePanel The new active tab
*/
'tabchange': this.onTabChange,
/**
* @event beforetabchange
* Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
* @param {YAHOO.ext.TabPanel} this
* @param {Object} e Set cancel to true on this object to cancel the tab change
* @param {YAHOO.ext.TabPanelItem} tab The tab being changed to
*/
'beforetabchange' : new YAHOO.util.CustomEvent('beforechange')
};
YAHOO.ext.EventManager.onWindowResize(this.onResize, this, true);
this.cpad = this.el.getPadding('lr');
this.hiddenCount = 0;
}
YAHOO.ext.TabPanel.prototype = {
fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
on : YAHOO.ext.util.Observable.prototype.on,
addListener : YAHOO.ext.util.Observable.prototype.addListener,
delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
/**
* Creates a new TabPanelItem by looking for an existing element with the provided id - if it's not found it creates one.
* @param {String} id The id of the div to use <b>or create</b>
* @param {String} text The text for the tab
* @param {<i>String</i>} content (optional) Content to put in the TabPanelItem body
* @param {<i>Boolean</i>} closable (optional) True to create a close icon on the tab
* @return {YAHOO.ext.TabPanelItem} The created TabPanelItem
*/
addTab : function(id, text, content, closable){
var item = new YAHOO.ext.TabPanelItem(this, id, text, closable);
this.addTabItem(item);
if(content){
item.setContent(content);
}
return item;
},
/**
* Returns the TabPanelItem with the specified id/index
* @param {String/Number} id The id or index of the TabPanelItem to fetch.
* @return {YAHOO.ext.TabPanelItem}
*/
getTab : function(id){
return this.items[id];
},
/**
* Hides the TabPanelItem with the specified id/index
* @param {String/Number} id The id or index of the TabPanelItem to hide.
*/
hideTab : function(id){
var t = this.items[id];
if(!t.isHidden()){
t.setHidden(true);
this.hiddenCount++;
this.autoSizeTabs();
}
},
/**
* "Unhides" the TabPanelItem with the specified id/index
* @param {String/Number} id The id or index of the TabPanelItem to unhide.
*/
unhideTab : function(id){
var t = this.items[id];
if(t.isHidden()){
t.setHidden(false);
this.hiddenCount--;
this.autoSizeTabs();
}
},
/**
* Add an existing TabPanelItem.
* @param {YAHOO.ext.TabPanelItem} item The TabPanelItem to add
*/
addTabItem : function(item){
this.items[item.id] = item;
this.items.push(item);
if(this.resizeTabs){
item.setWidth(this.currentTabWidth || this.preferredTabWidth)
this.autoSizeTabs();
}else{
item.autoSize();
}
},
/**
* Remove a TabPanelItem.
* @param {String/Number} id The id or index of the TabPanelItem to remove.
*/
removeTab : function(id){
var items = this.items;
var tab = items[id];
if(!tab) return;
var index = items.indexOf(tab);
if(this.active == tab && items.length > 1){
var newTab = this.getNextAvailable(index);
if(newTab)newTab.activate();
}
tab.purgeListeners();
this.stripEl.dom.removeChild(tab.pnode.dom);
if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
this.bodyEl.dom.removeChild(tab.bodyEl.dom);
}
items.splice(index, 1);
delete this.items[tab.id];
this.autoSizeTabs();
},
getNextAvailable : function(start){
var items = this.items;
var index = start;
// look for a next tab that will slide over to
// replace the one being removed
while(index < items.length){
var item = items[++index];
if(item && !item.isHidden()){
return item;
}
}
// if one isn't found select the previous tab (on the left)
var index = start;
while(index >= 0){
var item = items[--index];
if(item && !item.isHidden()){
return item;
}
}
return null;
},
/**
* Disable a TabPanelItem. <b>It cannot be the active tab, if it is this call is ignored.</b>.
* @param {String/Number} id The id or index of the TabPanelItem to disable.
*/
disableTab : function(id){
var tab = this.items[id];
if(tab && this.active != tab){
tab.disable();
}
},
/**
* Enable a TabPanelItem that is disabled.
* @param {String/Number} id The id or index of the TabPanelItem to enable.
*/
enableTab : function(id){
var tab = this.items[id];
tab.enable();
},
/**
* Activate a TabPanelItem. The currently active will be deactivated.
* @param {String/Number} id The id or index of the TabPanelItem to activate.
*/
activate : function(id){
var tab = this.items[id];
if(tab == this.active){
return tab;
}
var e = {};
this.fireEvent('beforetabchange', this, e, tab);
if(e.cancel !== true && !tab.disabled){
if(this.active){
this.active.hide();
}
this.active = this.items[id];
this.active.show();
this.onTabChange.fireDirect(this, this.active);
}
return tab;
},
/**
* Get the active TabPanelItem
* @return {YAHOO.ext.TabPanelItem} The active TabPanelItem or null if none are active.
*/
getActiveTab : function(){
return this.active;
},
/**
* Updates the tab body element to fit the height of the container element
* for overflow scrolling
* @param {Number} targetHeight (optional) Override the starting height from the elements height
*/
syncHeight : function(targetHeight){
var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth('tb')-this.el.getPadding('tb');
var bm = this.bodyEl.getMargins();
var newHeight = height-(this.stripWrap.getHeight())-(bm.top+bm.bottom);
this.bodyEl.setHeight(newHeight);
return newHeight;
},
onResize : function(){
if(this.monitorResize){
this.autoSizeTabs();
}
},
/**
* Disables tab resizing while tabs are being added (if resizeTabs is false this does nothing)
*/
beginUpdate : function(){
this.updating = true;
},
/**
* Stops an update and resizes the tabs (if resizeTabs is false this does nothing)
*/
endUpdate : function(){
this.updating = false;
this.autoSizeTabs();
},
/**
* Manual call to resize the tabs (if resizeTabs is false this does nothing)
*/
autoSizeTabs : function(){
var count = this.items.length;
var vcount = count - this.hiddenCount;
if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
var w = Math.max(this.el.getWidth() - this.cpad, 10);
var availWidth = Math.floor(w / vcount);
var b = this.stripBody;
if(b.getWidth() > w){
var tabs = this.items;
this.setTabWidth(Math.max(availWidth, this.minTabWidth));
if(availWidth < this.minTabWidth){
/*if(!this.sleft){ // incomplete scrolling code
this.createScrollButtons();
}
this.showScroll();
this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
}
}else{
if(this.currentTabWidth < this.preferredTabWidth){
this.setTabWidth(Math.min(availWidth, this.preferredTabWidth));
}
}
},
/**
* Resizes all the tabs to the passed width
* @param {Number} The new width
*/
setTabWidth : function(width){
this.currentTabWidth = width;
for(var i = 0, len = this.items.length; i < len; i++) {
if(!this.items[i].isHidden())this.items[i].setWidth(width);
}
},
/**
* Destroys this TabPanel
* @param {Boolean} removeEl (optional) True to remove the element from the DOM as well
*/
destroy : function(removeEl){
YAHOO.ext.EventManager.removeResizeListener(this.onResize, this);
for(var i = 0, len = this.items.length; i < len; i++){
this.items[i].purgeListeners();
}
if(removeEl === true){
this.el.update('');
this.el.remove();
}
}
};
/**
* @class YAHOO.ext.TabPanelItem
* @extends YAHOO.ext.util.Observable
*/
YAHOO.ext.TabPanelItem = function(tabPanel, id, text, closable){
/**
* The TabPanel this TabPanelItem belongs to
* @type YAHOO.ext.TabPanel
*/
this.tabPanel = tabPanel;
/**
* The id for this TabPanelItem
* @type String
*/
this.id = id;
/** @private */
this.disabled = false;
/** @private */
this.text = text;
/** @private */
this.loaded = false;
this.closable = closable;
/**
* The body element for this TabPanelItem
* @type YAHOO.ext.Element
*/
this.bodyEl = getEl(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
this.bodyEl.setVisibilityMode(YAHOO.ext.Element.VISIBILITY);
this.bodyEl.setStyle('display', 'block');
this.bodyEl.setStyle('zoom', '1');
this.hideAction();
var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
/** @private */
this.el = getEl(els.el, true);
this.inner = getEl(els.inner, true);
this.textEl = getEl(this.el.dom.firstChild.firstChild.firstChild, true);
this.pnode = getEl(els.el.parentNode, true);
this.el.mon('click', this.onTabClick, this, true);
/** @private */
if(closable){
var c = getEl(els.close, true);
c.dom.title = this.closeText;
c.addClassOnOver('close-over');
c.mon('click', this.closeClick, this, true);
}
// these two are now private and deprecated
this.onActivate = new YAHOO.util.CustomEvent('TabItem.onActivate');
this.onDeactivate = new YAHOO.util.CustomEvent('TabItem.onDeactivate');
this.events = {
/**
* @event activate
* Fires when this tab becomes the active tab
* @param {YAHOO.ext.TabPanel} tabPanel
* @param {YAHOO.ext.TabPanelItem} this
*/
'activate': this.onActivate,
/**
* @event beforeclose
* Fires before this tab is closed. To cancal the close, set cancel to true on e. (e.cancel = true)
* @param {YAHOO.ext.TabPanelItem} this
* @param {Object} e Set cancel to true on this object to cancel the close.
*/
'beforeclose': new YAHOO.util.CustomEvent('beforeclose'),
/**
* @event close
* Fires when this tab is closed
* @param {YAHOO.ext.TabPanelItem} this
*/
'close': new YAHOO.util.CustomEvent('close'),
/**
* @event deactivate
* Fires when this tab is no longer the active tab
* @param {YAHOO.ext.TabPanel} tabPanel
* @param {YAHOO.ext.TabPanelItem} this
*/
'deactivate' : this.onDeactivate
};
this.hidden = false;
};
YAHOO.ext.TabPanelItem.prototype = {
fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
on : YAHOO.ext.util.Observable.prototype.on,
addListener : YAHOO.ext.util.Observable.prototype.addListener,
delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
purgeListeners : function(){
YAHOO.ext.util.Observable.prototype.purgeListeners.call(this);
this.el.removeAllListeners();
},
/**
* Show this TabPanelItem - this <b>does not</b> deactivate the currently active TabPanelItem.
*/
show : function(){
this.pnode.addClass('on');
this.showAction();
if(YAHOO.ext.util.Browser.isOpera){
this.tabPanel.stripWrap.repaint();
}
this.onActivate.fireDirect(this.tabPanel, this);
},
/**
* Hide this TabPanelItem - if you don't activate another TabPanelItem this could look odd.
*/
hide : function(){
this.pnode.removeClass('on');
this.hideAction();
this.onDeactivate.fireDirect(this.tabPanel, this);
},
hideAction : function(){
this.bodyEl.setStyle('position', 'absolute');
this.bodyEl.setLeft('-20000px');
this.bodyEl.setTop('-20000px');
this.bodyEl.hide();
},
showAction : function(){
this.bodyEl.setStyle('position', 'relative');
this.bodyEl.setTop('');
this.bodyEl.setLeft('');
this.bodyEl.show();
this.tabPanel.el.repaint.defer(1);
},
setTooltip : function(text){
this.titleEl.dom.title = text;
},
onTabClick : function(e){
e.preventDefault();
this.tabPanel.activate(this.id);
},
getWidth : function(){
return this.inner.getWidth();
},
setWidth : function(width){
var iwidth = width - this.pnode.getPadding("lr");
this.inner.setWidth(iwidth);
this.textEl.setWidth(iwidth-this.inner.getPadding('lr'));
this.pnode.setWidth(width);
},
setHidden : function(hidden){
this.hidden = hidden;
this.pnode.setStyle('display', hidden ? 'none' : 'block');
},
isHidden : function(){
return this.hidden;
},
getText : function(){
return this.text;
},
autoSize : function(){
this.el.beginMeasure();
this.textEl.setWidth(1);
this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding('lr'));
this.el.endMeasure();
},
setText : function(text){
this.text = text;
this.textEl.update(text);
this.textEl.dom.title = text;
if(!this.tabPanel.resizeTabs){
this.autoSize();
}
},
/**
* Activate this TabPanelItem - this <b>does</b> deactivate the currently active TabPanelItem.
*/
activate : function(){
this.tabPanel.activate(this.id);
},
/**
* Disable this TabPanelItem - this call is ignore if this is the active TabPanelItem.
*/
disable : function(){
if(this.tabPanel.active != this){
this.disabled = true;
this.pnode.addClass('disabled');
}
},
/**
* Enable this TabPanelItem if it was previously disabled.
*/
enable : function(){
this.disabled = false;
this.pnode.removeClass('disabled');
},
/**
* Set the content for this TabPanelItem.
* @param {String} content The content
* @param {Boolean} loadScripts true to look for and load scripts
*/
setContent : function(content, loadScripts){
this.bodyEl.update(content, loadScripts);
},
/**
* Get the {@link YAHOO.ext.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
* @return {YAHOO.ext.UpdateManager} The UpdateManager
*/
getUpdateManager : function(){
return this.bodyEl.getUpdateManager();
},
/**
* Set a URL to be used to load the content for this TabPanelItem.
* @param {String/Function} url The url to load the content from or a function to call to get the url
* @param {<i>String/Object</i>} params (optional) The string params for the update call or an object of the params. See {@link YAHOO.ext.UpdateManager#update} for more details. (Defaults to null)
* @param {<i>Boolean</i>} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
* @return {YAHOO.ext.UpdateManager} The UpdateManager
*/
setUrl : function(url, params, loadOnce){
if(this.refreshDelegate){
this.onActivate.unsubscribe(this.refreshDelegate);
}
this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
this.onActivate.subscribe(this.refreshDelegate);
return this.bodyEl.getUpdateManager();
},
/** @private */
_handleRefresh : function(url, params, loadOnce){
if(!loadOnce || !this.loaded){
var updater = this.bodyEl.getUpdateManager();
updater.update(url, params, this._setLoaded.createDelegate(this));
}
},
/** @private */
_setLoaded : function(){
this.loaded = true;
},
/** @private */
closeClick : function(e){
var e = {};
this.fireEvent('beforeclose', this, e);
if(e.cancel !== true){
this.tabPanel.removeTab(this.id);
this.fireEvent('close', this);
}
},
/**
* The text displayed in the tooltip for the close icon.
* @type String
*/
closeText : 'Close this tab'
};
/** @private */
YAHOO.ext.TabPanel.prototype.createStrip = function(container){
var strip = document.createElement('div');
strip.className = 'ytab-wrap';
container.appendChild(strip);
return strip;
};
/** @private */
YAHOO.ext.TabPanel.prototype.createStripList = function(strip){
// div wrapper for retard IE
strip.innerHTML = '<div class="ytab-strip-wrap"><table class="ytab-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
return strip.firstChild.firstChild.firstChild.firstChild;
};
/** @private */
YAHOO.ext.TabPanel.prototype.createBody = function(container){
var body = document.createElement('div');
YAHOO.util.Dom.generateId(body, 'tab-body');
YAHOO.util.Dom.addClass(body, 'yui-ext-tabbody');
container.appendChild(body);
return body;
};
/** @private */
YAHOO.ext.TabPanel.prototype.createItemBody = function(bodyEl, id){
var body = YAHOO.util.Dom.get(id);
if(!body){
body = document.createElement('div');
body.id = id;
}
YAHOO.util.Dom.addClass(body, 'yui-ext-tabitembody');
bodyEl.appendChild(body);
return body;
};
/** @private */
YAHOO.ext.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
var td = document.createElement('td');
stripEl.appendChild(td);
if(closable){
td.className = "ytab-closable";
if(!this.closeTpl){
this.closeTpl = new YAHOO.ext.Template(
'<a href="#" class="ytab-right"><span class="ytab-left"><em class="ytab-inner">' +
'<span unselectable="on" title="{text}" class="ytab-text">{text}</span>' +
'<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
);
}
var el = this.closeTpl.overwrite(td, {'text': text});
var close = el.getElementsByTagName('div')[0];
var inner = el.getElementsByTagName('em')[0];
return {'el': el, 'close': close, 'inner': inner};
} else {
if(!this.tabTpl){
this.tabTpl = new YAHOO.ext.Template(
'<a href="#" class="ytab-right"><span class="ytab-left"><em class="ytab-inner">' +
'<span unselectable="on" title="{text}" class="ytab-text">{text}</span></em></span></a>'
);
}
var el = this.tabTpl.overwrite(td, {'text': text});
var inner = el.getElementsByTagName('em')[0];
return {'el': el, 'inner': inner};
}
};

View file

@ -0,0 +1,497 @@
/*
* YUI Extensions 0.33 RC2
* Copyright(c) 2006, Jack Slocum.
*/
/**
* @class YAHOO.ext.View
* @extends YAHOO.ext.util.Observable
* Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
* This class also supports single and multi selection modes. <br>
* Create a data model bound view:
<pre><code>
var dataModel = new YAHOO.ext.grid.XMLDataModel(...);
var view = new YAHOO.ext.View('my-element',
'&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
dataModel, {
singleSelect: true,
selectedClass: 'ydataview-selected'
});
// listen for node click?
view.on('click', function(vw, index, node, e){
alert('Node "' + node.id + '" at index: ' + index + ' was clicked.');
});
// load XML data
dataModel.load('foobar.xml');
</code></pre>
For an example of creating a JSON/UpdateManager view, see {@link YAHOO.ext.JsonView}.
* <br><br>
* <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
* IE's limited insertion support with tables and Opera's faulty event bubbling.</b>
* @constructor
* Create a new View
* @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
* @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
* @param {DataModel} dataModel The bound data model
* @param {Object} config The config object
*/
YAHOO.ext.View = function(container, tpl, dataModel, config){
this.el = getEl(container, true);
this.nodes = this.el.dom.childNodes;
if(typeof tpl == 'string'){
tpl = new YAHOO.ext.Template(tpl);
}
tpl.compile();
/**
* The template used by this View
* @type {YAHOO.ext.DomHelper.Template}
*/
this.tpl = tpl;
this.setDataModel(dataModel);
var CE = YAHOO.util.CustomEvent;
/** @private */
this.events = {
/**
* @event click
* Fires when a template node is clicked.
* @param {YAHOO.ext.View} this
* @param {Number} index The index of the target node
* @param {HTMLElement} node The target node
* @param {YAHOO.ext.EventObject} e The raw event object
*/
'click' : new CE('click'),
/**
* @event dblclick
* Fires when a template node is double clicked.
* @param {YAHOO.ext.View} this
* @param {Number} index The index of the target node
* @param {HTMLElement} node The target node
* @param {YAHOO.ext.EventObject} e The raw event object
*/
'dblclick' : new CE('dblclick'),
/**
* @event contextmenu
* Fires when a template node is right clicked.
* @param {YAHOO.ext.View} this
* @param {Number} index The index of the target node
* @param {HTMLElement} node The target node
* @param {YAHOO.ext.EventObject} e The raw event object
*/
'contextmenu' : new CE('contextmenu'),
/**
* @event selectionchange
* Fires when the selected nodes change.
* @param {YAHOO.ext.View} this
* @param {Array} selections Array of the selected nodes
*/
'selectionchange' : new CE('selectionchange')
};
this.el.mon("click", this.onClick, this, true);
this.el.mon("dblclick", this.onDblClick, this, true);
this.el.mon("contextmenu", this.onContextMenu, this, true);
/**
* The css class to add to selected nodes
* @type {YAHOO.ext.DomHelper.Template}
*/
this.selectedClass = 'ydataview-selected';
this.selections = [];
this.lastSelection = null;
/**
* The root property in the loaded json object that contains the data
* @type {String}
*/
this.jsonRoot = null;
YAHOO.ext.util.Config.apply(this, config);
if(this.renderUpdates || this.jsonRoot){
var um = this.el.getUpdateManager();
um.setRenderer(this);
}
};
YAHOO.extendX(YAHOO.ext.View, YAHOO.ext.util.Observable, {
/**
* Returns the element this view is bound to.
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
},
render : function(el, response){
this.clearSelections();
this.el.update('');
var o;
try{
o = YAHOO.ext.util.JSON.decode(response.responseText);
if(this.jsonRoot){
o = eval('o.' + this.jsonRoot);
}
}catch(e){}
if(o && o.length){
this.html = [];
for(var i = 0, len = o.length; i < len; i++) {
this.renderEach(o[i]);
}
this.el.update(this.html.join(''));
this.html = null;
this.nodes = this.el.dom.childNodes;
this.updateIndexes(0);
}
},
/**
* Refreshes the view.
*/
refresh : function(){
this.clearSelections();
this.el.update('');
this.html = [];
this.dataModel.each(this.renderEach, this);
this.el.update(this.html.join(''));
this.html = null;
this.nodes = this.el.dom.childNodes;
this.updateIndexes(0);
},
/**
* Function to override to reformat the data that is sent to
* the template for each node.
* @param {Array/Object} data The raw data (array of colData for a data model bound view or
* a JSON object for an UpdateManager bound view).
* @param {Number} index The index of the data within the data model
*/
prepareData : function(data, index){
return data;
},
renderEach : function(data){
this.html[this.html.length] = this.tpl.applyTemplate(this.prepareData(data));
},
/**
* Refresh an individual node.
* @param {Number} index
*/
refreshNode : function(index){
this.refreshNodes(index, index);
},
refreshNodes : function(dm, startIndex, endIndex){
this.clearSelections();
var dm = this.dataModel;
var ns = this.nodes;
for(var i = startIndex; i <= endIndex; i++){
var d = this.prepareData(dm.getRow(i), i);
if(i < ns.length-1){
var old = ns[i];
this.tpl.insertBefore(old, d);
this.el.dom.removeChild(old);
}else{
this.tpl.append(this.el.dom, d);
}
}
this.updateIndexes(startIndex, endIndex);
},
deleteNodes : function(dm, startIndex, endIndex){
this.clearSelections();
if(startIndex == 0 && endIndex >= this.nodes.length-1){
this.el.update('');
}else{
var el = this.el.dom;
for(var i = startIndex; i <= endIndex; i++){
el.removeChild(this.nodes[startIndex]);
}
this.updateIndexes(startIndex);
}
},
insertNodes : function(dm, startIndex, endIndex){
if(this.nodes.length == 0){
this.refresh();
}else{
this.clearSelections();
var t = this.tpl;
var before = this.nodes[startIndex];
var dm = this.dataModel;
if(before){
for(var i = startIndex; i <= endIndex; i++){
t.insertBefore(before, this.prepareData(dm.getRow(i), i));
}
}else{
var el = this.el.dom;
for(var i = startIndex; i <= endIndex; i++){
t.append(el, this.prepareData(dm.getRow(i), i));
}
}
this.updateIndexes(startIndex);
}
},
updateIndexes : function(dm, startIndex, endIndex){
var ns = this.nodes;
startIndex = startIndex || 0;
endIndex = endIndex || ns.length-1;
for(var i = startIndex; i <= endIndex; i++){
ns[i].nodeIndex = i;
}
},
/**
* Changes the data model this view uses and refresh the view.
* @param {DataModel} dataModel
*/
setDataModel : function(dm){
if(!dm) return;
this.unplugDataModel(this.dataModel);
this.dataModel = dm;
dm.on('cellupdated', this.refreshNode, this, true);
dm.on('datachanged', this.refresh, this, true);
dm.on('rowsdeleted', this.deleteNodes, this, true);
dm.on('rowsinserted', this.insertNodes, this, true);
dm.on('rowsupdated', this.refreshNodes, this, true);
dm.on('rowssorted', this.refresh, this, true);
this.refresh();
},
/**
* Unplug the data model and stop updates.
* @param {DataModel} dataModel
*/
unplugDataModel : function(dm){
if(!dm) return;
dm.removeListener('cellupdated', this.refreshNode, this);
dm.removeListener('datachanged', this.refresh, this);
dm.removeListener('rowsdeleted', this.deleteNodes, this);
dm.removeListener('rowsinserted', this.insertNodes, this);
dm.removeListener('rowsupdated', this.refreshNodes, this);
dm.removeListener('rowssorted', this.refresh, this);
this.dataModel = null;
},
/**
* Returns the template node the passed child belongs to or null if it doesn't belong to one.
* @param {HTMLElement} node
* @return {HTMLElement} The template node
*/
findItemFromChild : function(node){
var el = this.el.dom;
if(!node || node.parentNode == el){
return node;
}
var p = node.parentNode;
while(p && p != el){
if(p.parentNode == el){
return p;
}
p = p.parentNode;
}
return null;
},
/** @ignore */
onClick : function(e){
var item = this.findItemFromChild(e.getTarget());
if(item){
var index = this.indexOf(item);
this.onItemClick(item, index, e);
this.fireEvent('click', this, index, item, e);
}else{
this.clearSelections();
}
},
/** @ignore */
onContextMenu : function(e){
var item = this.findItemFromChild(e.getTarget());
if(item){
this.fireEvent('contextmenu', this, this.indexOf(item), item, e);
}
},
/** @ignore */
onDblClick : function(e){
var item = this.findItemFromChild(e.getTarget());
if(item){
this.fireEvent('dblclick', this, this.indexOf(item), item, e);
}
},
onItemClick : function(item, index, e){
if(this.multiSelect || this.singleSelect){
if(this.multiSelect && e.shiftKey && this.lastSelection){
this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
}else{
this.select(item, this.multiSelect && e.ctrlKey);
this.lastSelection = item;
}
}
},
/**
* Get the number of selected nodes.
* @return {Number}
*/
getSelectionCount : function(){
return this.selections.length;
},
/**
* Get the currently selected nodes.
* @return {Array} An array of HTMLElements
*/
getSelectedNodes : function(){
return this.selections;
},
/**
* Get the indexes of the selected nodes.
* @return {Array}
*/
getSelectedIndexes : function(){
var indexes = [];
for(var i = 0, len = this.selections.length; i < len; i++) {
indexes.push(this.selections[i].nodeIndex);
}
return indexes;
},
/**
* Clear all selections
* @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
*/
clearSelections : function(suppressEvent){
if(this.multiSelect || this.singleSelect){
YAHOO.util.Dom.removeClass(this.selections, this.selectedClass);
this.selections = [];
if(!suppressEvent){
this.fireEvent('selectionchange', this, this.selections);
}
}
},
/**
* Selects nodes.
* @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
* @param {Boolean} keepExisting (optional) true to keep existing selections
* @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
*/
select : function(nodeInfo, keepExisting, suppressEvent){
if(!keepExisting){
this.clearSelections(true);
}
if(nodeInfo instanceof Array){
for(var i = 0, len = nodeInfo.length; i < len; i++) {
this.select(nodeInfo[i], true, true);
}
}else{
var node = this.getNode(nodeInfo);
if(node){
YAHOO.util.Dom.addClass(node, this.selectedClass);
this.selections.push(node);
}
}
if(!suppressEvent){
this.fireEvent('selectionchange', this, this.selections);
}
},
/**
* Gets a template node.
* @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
* @return {HTMLElement} The node or null if it wasn't found
*/
getNode : function(nodeInfo){
if(typeof nodeInfo == 'object'){
return nodeInfo;
}else if(typeof nodeInfo == 'string'){
return document.getElementById(nodeInfo);
}else if(typeof nodeInfo == 'number'){
return this.nodes[nodeInfo];
}
return null;
},
/**
* Gets a range template nodes.
* @param {Number} startIndex
* @param {Number} endIndex
* @return {Array} An array of nodes
*/
getNodes : function(start, end){
var ns = this.nodes;
startIndex = startIndex || 0;
endIndex = typeof endIndex == 'undefined' ? ns.length-1 : endIndex;
var nodes = [];
for(var i = start; i <= end; i++) {
nodes.push(ns[i]);
}
return nodes;
},
/**
* Finds the index of the passed node
* @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
* @return {Number} The index of the node or -1
*/
indexOf : function(node){
node = this.getNode(node);
if(typeof node.nodeIndex == 'number'){
return node.nodeIndex;
}
var ns = this.nodes;
for(var i = 0, len = ns.length; i < len; i++) {
if(ns[i] == node){
return i;
}
}
return -1;
}
});
/**
* @class YAHOO.ext.JsonView
* @extends YAHOO.ext.View
* Shortcut class to create a JSON + UpdateManager template view. Usage:
<pre><code>
var view = new YAHOO.ext.View('my-element',
'&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
{ multiSelect: true, jsonRoot: 'data' });
// listen for node click?
view.on('click', function(vw, index, node, e){
alert('Node "' + node.id + '" at index: ' + index + ' was clicked.');
});
// direct load of JSON data
view.load('foobar.php');
</code></pre>
* @constructor
* Create a new JsonView
* @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
* @param {DomHelper.Template} tpl The rendering template
* @param {Object} config The config object
*/
YAHOO.ext.JsonView = function(container, tpl, config){
var cfg = config || {};
cfg.renderUpdates = true;
YAHOO.ext.JsonView.superclass.constructor.call(this, container, tpl, null, cfg);
};
YAHOO.extendX(YAHOO.ext.JsonView, YAHOO.ext.View, {
/**
* Direct access to the elements UpdateManager update() method (takes the same parameters).
* @param {String/Function} url The url for this request or a function to call to get the url
* @param {<i>String/Object</i>} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
* @param {<i>Function</i>} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
* @param {<i>Boolean</i>} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
*/
load : function(){
var um = this.el.getUpdateManager();
um.update.apply(um, arguments);
}
});

View file

@ -0,0 +1,291 @@
/*
* YUI Extensions 0.33 RC2
* Copyright(c) 2006, Jack Slocum.
*/
/**
* @class YAHOO.ext.Toolbar
* Basic Toolbar used by the Grid to create the paging toolbar. This class is reusable but functionality
* is limited. Look for more functionality in a future version.
*/
YAHOO.ext.Toolbar = function(container){
this.el = getEl(container, true);
var div = document.createElement('div');
div.className = 'ytoolbar';
var tb = document.createElement('table');
tb.border = 0;
tb.cellPadding = 0;
tb.cellSpacing = 0;
div.appendChild(tb);
var tbody = document.createElement('tbody');
tb.appendChild(tbody);
var tr = document.createElement('tr');
tbody.appendChild(tr);
this.el.dom.appendChild(div);
this.tr = tr;
};
YAHOO.ext.Toolbar.prototype = {
/**
* Adds element(s) to the toolbar - this function takes a variable number of
* arguments of mixed type and adds them to the toolbar...
*
* @param {Mixed} arg If arg is a ToolbarButton, it is added. If arg is a string, it is wrapped
* in a ytb-text element and added unless the text is "separator" in which case a separator
* is added. Otherwise, it is assumed the element is an HTMLElement and it is added directly.
*/
add : function(){
for(var i = 0; i < arguments.length; i++){
var el = arguments[i];
var td = document.createElement('td');
this.tr.appendChild(td);
if(el instanceof YAHOO.ext.ToolbarButton){
el.init(td);
}else if(el instanceof Array){
this.addButton(el);
}else if(typeof el == 'string'){
var span = document.createElement('span');
if(el == 'separator'){
span.className = 'ytb-sep';
}else{
span.innerHTML = el;
span.className = 'ytb-text';
}
td.appendChild(span);
}else if(typeof el == 'object'){ // must be element?
td.appendChild(el);
}
}
},
/**
* Returns the element for this toolbar
* @return {YAHOO.ext.Element}
*/
getEl : function(){
return this.el;
},
/**
* Adds a separator
*/
addSeparator : function(){
var td = document.createElement('td');
this.tr.appendChild(td);
var span = document.createElement('span');
span.className = 'ytb-sep';
td.appendChild(span);
},
/**
* Add a button (or buttons), see {@link YAHOO.ext.ToolbarButton} for more info on the config
* @param {Object/Array} config A button config or array of configs
* @return {YAHOO.ext.ToolbarButton/Array}
*/
addButton : function(config){
if(config instanceof Array){
var buttons = [];
for(var i = 0, len = config.length; i < len; i++) {
buttons.push(this.addButton(config[i]));
}
return buttons;
}
var b = config;
if(!(config instanceof YAHOO.ext.ToolbarButton)){
b = new YAHOO.ext.ToolbarButton(config);
}
this.add(b);
return b;
},
/**
* Adds text to the toolbar
* @param {String} text The text to add
* @return {HTMLElement} The span element created which you can use to update the text.
*/
addText : function(text){
var td = document.createElement('td');
this.tr.appendChild(td);
var span = document.createElement('span');
span.className = 'ytb-text';
span.innerHTML = text;
td.appendChild(span);
return span;
},
/**
* Inserts a button (or buttons) at the specified index
* @param {Number} index The index where the buttons are to be inserted
* @param {Object/Array} config A button config or array of configs
* @return {YAHOO.ext.ToolbarButton/Array}
*/
insertButton : function(index, config){
if(config instanceof Array){
var buttons = [];
for(var i = 0, len = config.length; i < len; i++) {
buttons.push(this.insertButton(index + i, config[i]));
}
return buttons;
}
var b = new YAHOO.ext.ToolbarButton(config);
var td = document.createElement('td');
var nextSibling = this.tr.childNodes[index];
if (nextSibling)
this.tr.insertBefore(td, nextSibling);
else
this.tr.appendChild(td);
b.init(td);
return b;
}
};
/**
* @class YAHOO.ext.ToolbarButton
* A toolbar button. The config has the following options:
* <ul>
* <li>className - The CSS class for the button. Use this to attach a background image for an icon.</li>
* <li>text - The button's text</li>
* <li>tooltip - The buttons tooltip text</li>
* <li>click - function to call when the button is clicked</li>
* <li>mouseover - function to call when the mouse moves over the button</li>
* <li>mouseout - function to call when the mouse moves off the button</li>
* <li>scope - The scope of the above event handlers</li>
* <li></li>
* <li></li>
*/
YAHOO.ext.ToolbarButton = function(config){
YAHOO.ext.util.Config.apply(this, config);
};
YAHOO.ext.ToolbarButton.prototype = {
/** @private */
init : function(appendTo){
var element = document.createElement('span');
element.className = 'ytb-button';
if(this.id){
element.id = this.id;
}
this.disabled = (this.disabled === true);
var inner = document.createElement('span');
inner.className = 'ytb-button-inner ' + this.className;
inner.unselectable = 'on';
if(this.tooltip){
element.setAttribute('title', this.tooltip);
}
if(this.style){
YAHOO.ext.DomHelper.applyStyles(inner, this.style);
}
element.appendChild(inner);
appendTo.appendChild(element);
this.el = getEl(element, true);
this.el.unselectable();
inner.innerHTML = (this.text ? this.text : '&#160;');
this.inner = inner;
this.el.mon('click', this.onClick, this, true);
this.el.mon('mouseover', this.onMouseOver, this, true);
this.el.mon('mouseout', this.onMouseOut, this, true);
},
/**
* Sets this buttons click handler
* @param {Function} click The function to call when the button is clicked
* @param {Object} scope (optional) Scope for the function passed above
*/
setHandler : function(click, scope){
this.click = click;
this.scope = scope;
},
/**
* Set this buttons text
* @param {String} text
*/
setText : function(text){
this.inner.innerHTML = text;
},
/**
* Set this buttons tooltip text
* @param {String} text
*/
setTooltip : function(text){
this.el.dom.title = text;
},
/**
* Show this button
*/
show: function(){
this.el.dom.parentNode.style.display = '';
},
/**
* Hide this button
*/
hide: function(){
this.el.dom.parentNode.style.display = 'none';
},
/**
* Disable this button
*/
disable : function(){
this.disabled = true;
if(this.el){
this.el.addClass('ytb-button-disabled');
}
},
/**
* Enable this button
*/
enable : function(){
this.disabled = false;
if(this.el){
this.el.removeClass('ytb-button-disabled');
}
},
/**
* Returns true if this button is disabled.
* @return {Boolean}
*/
isDisabled : function(){
return this.disabled === true;
},
setDisabled : function(disabled){
if(disabled){
this.disable();
}else{
this.enable();
}
},
/** @private */
onClick : function(){
if(!this.disabled && this.click){
this.click.call(this.scope || window, this);
}
},
/** @private */
onMouseOver : function(){
if(!this.disabled){
this.el.addClass('ytb-button-over');
if(this.mouseover){
this.mouseover.call(this.scope || window, this);
}
}
},
/** @private */
onMouseOut : function(){
this.el.removeClass('ytb-button-over');
if(!this.disabled){
if(this.mouseout){
this.mouseout.call(this.scope || window, this);
}
}
}
};