/*
* (c) 2005-2009 Richard Cowin (http://openrico.org)
* (c) 2005-2009 Matt Brown (http://dowdybrown.com)
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
Rico.applyShadow = function(elem,shadowFlag) {
if (typeof shadowFlag=='undefined') shadowFlag=true;
if (shadowFlag) Rico.addClass(elem,'ricoShadow');
return elem;
};
// ensure popups/windows get closed in the right order when the user hits escape key
Rico._OpenPopupList = [];
Rico._RemoveOpenPopup = function(popup) {
if (popup.openIndex >= 0 && popup.openIndex < Rico._OpenPopupList.length) Rico._OpenPopupList.splice(popup.openIndex,1);
popup.openIndex = -1;
};
Rico._AddOpenPopup = function(popup) {
popup.openIndex = Rico._OpenPopupList.push(popup) - 1;
};
Rico._checkEscKey = function(e) {
if (Rico.eventKey(e) != 27) return true;
while (Rico._OpenPopupList.length > 0) {
var popup = Rico._OpenPopupList.pop();
if (popup && popup.visible()) {
popup.openIndex = -1;
Rico.eventStop(e);
popup.closeFunc();
return false;
}
}
return true;
};
Rico.eventBind(document,"keyup", Rico.eventHandle(Rico,'_checkEscKey'));
Rico.Popup = function(containerDiv,options) {
this.initialize(containerDiv,options);
};
Rico.Popup.prototype = {
/**
* @class Class to manage pop-up div windows.
* @constructs
* @param options object may contain any of the following:
* - hideOnClick
- hide popup when mouse button is clicked? default=true
* - ignoreClicks
- if true, mouse clicks within the popup are not allowed to bubble up to parent elements
* - position
- defaults to absolute, use "auto" to auto-detect
* - shadow
- display shadow with popup? default=true
* - zIndex
- which layer? default=1
* - canDrag
- boolean value (or function that returns a boolean) indicating if it is ok to drag/reposition popup, default=false
* - onClose
- function to call when the popup is closed
*
* @param containerDiv if supplied, then setDiv() is called at the end of initialization
*/
initialize: function(containerDiv,options) {
this.options = {
hideOnClick : false,
ignoreClicks : false,
position : 'absolute',
shadow : true,
zIndex : 2,
canDrag : false,
dragElement : false,
closeFunc : false
};
this.openIndex=-1;
if (containerDiv) this.setDiv(containerDiv,options);
},
createContainer: function(options) {
this.setDiv(document.createElement('div'), options);
if (options && options.parent) {
options.parent.appendChild(this.container);
} else {
document.getElementsByTagName("body")[0].appendChild(this.container);
}
},
/**
* Apply popup behavior to a div that already exists in the DOM
* @param containerDiv div element (or element id) in the DOM. If null, then the div is created automatically.
*/
setDiv: function(containerDiv,options) {
Rico.extend(this.options, options || {});
this.container=Rico.$(containerDiv);
if (this.options.position == 'auto') {
this.position=Rico.getStyle(this.container,'position').toLowerCase();
} else {
this.position=this.container.style.position=this.options.position;
}
if (this.position != 'absolute') {
this.content=this.container;
return;
}
if (this.options.zIndex >= 0) this.container.style.zIndex=this.options.zIndex;
if (this.options.closeFunc) {
this.closeFunc=this.options.closeFunc;
} else {
var self=this;
this.closeFunc=function() { self.closePopup(); };
}
//this.container.style.overflow='hidden';
this.container.style.top='0px';
this.container.style.left='0px';
this.container.style.display='none';
this.content=document.createElement('div');
while (this.container.firstChild) {
this.content.appendChild(this.container.firstChild);
}
this.container.appendChild(this.content);
this.content.className='RicoPopupContent';
this.content.style.position='relative';
if (Rico.isIE && Rico.ieVersion < 7) {
// create iframe shim
this.ifr = document.createElement('iframe');
this.ifr.style.position="absolute";
this.ifr.style.top = '0px';
this.ifr.style.left = '0px';
this.ifr.style.width = '2000px';
this.ifr.style.height = '2000px';
this.ifr.style.zIndex = -1;
this.ifr.frameBorder = 0;
this.ifr.src="javascript:false;";
this.content.appendChild(this.ifr);
}
Rico.applyShadow(this.container,this.options.shadow);
if (this.options.hideOnClick)
Rico.eventBind(document,"click", Rico.eventHandle(this,'_docClick'));
this.dragEnabled=false;
this.mousedownHandler = Rico.eventHandle(this,'_startDrag');
this.dragHandler = Rico.eventHandle(this,'_drag');
this.dropHandler = Rico.eventHandle(this,'_endDrag');
if (this.options.canDrag) this.enableDragging();
if (this.options.ignoreClicks || this.options.canDrag) this.ignoreClicks();
},
clearContent: function() {
this.content.innerHTML="";
},
setContent: function(content) {
this.content.innerHTML=content;
},
enableDragging: function() {
if (!this.dragEnabled && this.options.dragElement) {
Rico.eventBind(this.options.dragElement, "mousedown", this.mousedownHandler);
this.dragEnabled=true;
}
return this.dragEnabled;
},
disableDragging: function() {
if (!this.dragEnabled) return;
Rico.eventUnbind(this.options.dragElement, "mousedown", this.mousedownHandler);
this.dragEnabled=false;
},
setZ: function(zIndex) {
this.container.style.zIndex=zIndex;
},
/** @private */
ignoreClicks: function() {
Rico.eventBind(this.container,"click", Rico.eventHandle(this,'_ignoreClick'));
},
_ignoreClick: function(e) {
if (e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
return true;
},
_docClick: function(e) {
this.closeFunc();
return true;
},
/**
* Move popup to specified position
*/
move: function(left,top) {
if (typeof left=='number') this.container.style.left=left+'px';
if (typeof top=='number') this.container.style.top=top+'px';
},
_startDrag : function(event){
var elem=Rico.eventElement(event);
this.container.style.cursor='move';
this.lastMouse = Rico.eventClient(event);
Rico.eventBind(document, "mousemove", this.dragHandler);
Rico.eventBind(document, "mouseup", this.dropHandler);
Rico.eventStop(event);
},
_drag : function(event){
var newMouse = Rico.eventClient(event);
var newLeft = parseInt(this.container.style.left,10) + newMouse.x - this.lastMouse.x;
var newTop = parseInt(this.container.style.top,10) + newMouse.y - this.lastMouse.y;
this.move(newLeft, newTop);
this.lastMouse = newMouse;
Rico.eventStop(event);
},
_endDrag : function(){
this.container.style.cursor='';
Rico.eventUnbind(document, "mousemove", this.dragHandler);
Rico.eventUnbind(document, "mouseup", this.dropHandler);
},
/**
* Display popup at specified position
*/
openPopup: function(left,top) {
this.container.style.display=this.position=='absolute' ? "block" : Rico.isIE && Rico.ieVersion<8 ? "inline" : "inline-block";
if (typeof left=='number') this.container.style.left=left+'px';
if (typeof top=='number') this.container.style.top=top+'px';
if (this.container.id) Rico.log('openPopup '+this.container.id+' at '+left+','+top);
Rico._AddOpenPopup(this);
},
centerPopup: function() {
this.openPopup();
var msgWidth=this.container.offsetWidth;
var msgHeight=this.container.offsetHeight;
var divwi=this.container.parentNode.offsetWidth;
var divht=this.container.parentNode.offsetHeight;
this.move(parseInt(Math.max((divwi-msgWidth)/2,0),10), parseInt(Math.max((divht-msgHeight)/2,0),10));
},
visible: function() {
return Rico.visible(this.container);
},
/**
* Hide popup
*/
closePopup: function() {
Rico._RemoveOpenPopup(this);
if (!Rico.visible(this.container)) return;
if (this.container.id) Rico.log('closePopup '+this.container.id);
if (this.dragEnabled) this._endDrag();
this.container.style.display="none";
if (this.options.onClose) this.options.onClose();
}
};
Rico.closeButton = function(handle) {
var a = document.createElement('a');
a.className='RicoCloseAnchor';
if (Rico.theme.closeAnchor) Rico.addClass(a,Rico.theme.closeAnchor);
var span = a.appendChild(document.createElement('span'));
span.title=Rico.getPhraseById('close');
new Rico.HoverSet([a]);
Rico.addClass(span,Rico.theme.close || 'rico-icon RicoClose');
Rico.eventBind(a,"click", handle);
return a;
};
Rico.floatButton = function(buttonName, handle, title) {
var a=document.createElement("a");
a.className='RicoButtonAnchor'
Rico.addClass(a,Rico.theme.buttonAnchor || 'RicoButtonAnchorNative');
var span=a.appendChild(document.createElement("span"));
if (title) span.title=title;
span.className=Rico.theme[buttonName.toLowerCase()] || 'rico-icon Rico'+buttonName;
Rico.eventBind(a,"click", handle, false);
new Rico.HoverSet([a]);
return a
}
Rico.clearButton = function(handle) {
var span=document.createElement("span");
span.title=Rico.getPhraseById('clear');
span.className='ricoClear';
Rico.addClass(span, Rico.theme.clear || 'rico-icon ricoClearNative');
Rico.eventBind(span,"click", handle);
return span;
}
Rico.Window = function(title, options, contentParam) {
this.initialize(title, options, contentParam);
};
Rico.Window.prototype = {
/**
* Create popup div with a title bar.
*/
initialize: function(title, options, contentParam) {
options=options || {overflow:'auto'};
Rico.extend(this, new Rico.Popup());
this.titleDiv = document.createElement('div');
this.options.canDrag=true;
this.options.dragElement=this.titleDiv;
this.createContainer(options);
this.content.appendChild(this.titleDiv);
contentParam=Rico.$(contentParam);
this.contentDiv=contentParam || document.createElement('div');
this.content.appendChild(this.contentDiv);
// create title area
this.titleDiv.className='ricoTitle';
if (Rico.theme.dialogTitle) Rico.addClass(this.titleDiv,Rico.theme.dialogTitle);
this.titleDiv.style.position='relative';
this.titleContent = document.createElement('span');
this.titleContent.className='ricoTitleSpan';
this.titleDiv.appendChild(this.titleContent);
this.titleDiv.appendChild(Rico.closeButton(Rico.eventHandle(this,'closeFunc')));
if (!title && contentParam) {
title=contentParam.title;
contentParam.title='';
}
this.setTitle(title || ' ');
// create content area
this.contentDiv.className='ricoContent';
if (Rico.theme.dialogContent) Rico.addClass(this.contentDiv,Rico.theme.dialogContent);
this.contentDiv.style.position='relative';
if (options.height) this.contentDiv.style.height=options.height;
if (options.width) this.contentDiv.style.width=options.width;
if (options.overflow) this.contentDiv.style.overflow=options.overflow;
Rico.addClass(this.content,'ricoWindow');
if (Rico.theme.dialog) Rico.addClass(this.content,Rico.theme.dialog);
if (Rico.isIE) {
// fix float'ed content in IE
this.titleDiv.style.zoom=1;
this.contentDiv.style.zoom=1;
}
this.content=this.contentDiv;
},
setTitle: function(title) {
this.titleContent.innerHTML=title;
}
}
Rico.Menu = function(options) {
this.initialize(options);
}
Rico.Menu.prototype = {
/**
* @class Implements popup menus and submenus
* @extends Rico.Popup
* @constructs
*/
initialize: function(options) {
Rico.extend(this, new Rico.Popup());
Rico.extend(this.options, {
width : "15em",
arrowColor : "b", // for submenus: b=black, w=white
showDisabled : false,
hideOnClick : true
});
if (typeof options=='string')
this.options.width=options;
else
Rico.extend(this.options, options || {});
this.hideFunc=null;
this.highlightElem=null;
},
createDiv: function(parentNode) {
if (this.container) return;
var self=this;
var options={ closeFunc: function() { self.cancelmenu(); } };
if (parentNode) options.parent=parentNode;
this.createContainer(options);
this.content.className = Rico.isWebKit ? 'ricoMenuSafari' : 'ricoMenu';
this.content.style.width=this.options.width;
this.direction=Rico.getStyle(this.container,'direction') || 'ltr';
this.direction=this.direction.toLowerCase(); // ltr or rtl
this.hidemenu();
this.itemCount=0;
},
showmenu: function(e,hideFunc){
Rico.eventStop(e);
this.hideFunc=hideFunc;
if (this.content.childNodes.length==0) {
this.cancelmenu();
return false;
}
var mousePos = Rico.eventClient(e);
this.openmenu(mousePos.x,mousePos.y,0,0);
},
openmenu: function(x,y,clickItemWi,clickItemHt,noOffset) {
var newLeft=x + (noOffset ? 0 : Rico.docScrollLeft());
this.container.style.visibility="hidden";
this.container.style.display="block";
var w=this.container.offsetWidth;
var cw=this.content.offsetWidth;
//window.status='openmenu: newLeft='+newLeft+' width='+w+' clickItemWi='+clickItemWi+' windowWi='+Rico.windowWidth();
if (this.direction == 'rtl') {
if (newLeft > w+clickItemWi) newLeft-=cw+clickItemWi;
} else {
if (x+w > Rico.windowWidth()) newLeft-=cw+clickItemWi-2;
}
var scrTop=Rico.docScrollTop();
var newTop=y + (noOffset ? 0 : scrTop);
if (y+this.container.offsetHeight-scrTop > Rico.windowHeight())
newTop=Math.max(newTop-this.content.offsetHeight+clickItemHt,0);
this.openPopup(newLeft,newTop);
this.container.style.visibility ="visible";
return false;
},
clearMenu: function() {
this.clearContent();
this.defaultAction=null;
this.itemCount=0;
},
addMenuHeading: function(hdg) {
var el=document.createElement('div');
el.innerHTML=hdg;
el.className='ricoMenuHeading';
this.content.appendChild(el);
},
addMenuBreak: function() {
var brk=document.createElement('div');
brk.className="ricoMenuBreak";
this.content.appendChild(brk);
},
addSubMenuItem: function(menutext, submenu, translate) {
var dir=this.direction=='rtl' ? 'left' : 'right';
var a=this.addMenuItem(menutext,null,true,null,translate);
a.className='ricoSubMenu';
var arrowdiv = a.appendChild(document.createElement('div'));
arrowdiv.className='rico-icon rico-'+dir+'-'+this.options.arrowColor;
Rico.setStyle(arrowdiv,{position:'absolute',top:'2px'});
arrowdiv.style[dir]='0px';
a.RicoSubmenu=submenu;
Rico.eventBind(a,"mouseover", Rico.eventHandle(this,'showSubMenu'));
Rico.eventBind(a,"mouseout", Rico.eventHandle(this,'subMenuOut'));
},
showSubMenu: function(e) {
if (this.openSubMenu) this.hideSubMenu();
var a=Rico.eventElement(e);
if (!a.RicoSubmenu) a=a.parentNode; // event can happen on arrow div
if (!a.RicoSubmenu) return;
this.openSubMenu=a.RicoSubmenu;
this.openMenuAnchor=a;
if (Rico.hasClass(a,'ricoSubMenu')) {
Rico.removeClass(a,'ricoSubMenu');
Rico.addClass(a,'ricoSubMenuOpen');
}
a.RicoSubmenu.openmenu(parseInt(this.container.style.left)+a.offsetWidth, parseInt(this.container.style.top)+a.offsetTop, a.offsetWidth-2, a.offsetHeight+2,true);
},
subMenuOut: function(e) {
if (!this.openSubMenu) return;
Rico.eventStop(e);
var elem=Rico.eventElement(e);
var reltg = Rico.eventRelatedTarget(e) || e.toElement;
try {
while (reltg != null && reltg != this.openSubMenu.div)
reltg=reltg.parentNode;
} catch(err) {}
if (reltg == this.openSubMenu.div) return;
this.hideSubMenu();
},
hideSubMenu: function() {
if (this.openMenuAnchor) {
Rico.removeClass(this.openMenuAnchor,'ricoSubMenuOpen');
Rico.addClass(this.openMenuAnchor,'ricoSubMenu');
this.openMenuAnchor=null;
}
if (this.openSubMenu) {
this.openSubMenu.hidemenu();
this.openSubMenu=null;
}
},
addMenuItemId: function(phraseId,action,enabled,title,target) {
if ( arguments.length < 3 ) enabled=true;
this.addMenuItem(Rico.getPhraseById(phraseId),action,enabled,title,target);
},
// if action is a string, then it is assumed to be a URL and the target parm can be used indicate which window gets the content
// action can also be a function
// action can also be a Rico.eventHandle, but set target='event' in this case
addMenuItem: function(menutext,action,enabled,title,target) {
if (arguments.length >= 3 && !enabled && !this.options.showDisabled) return null;
this.itemCount++;
var a = document.createElement(typeof action=='string' ? 'a' : 'div');
if ( arguments.length < 3 || enabled ) {
if (typeof action=='string') {
a.href = action;
if (target) a.target = target;
} else if (target=='event') {
Rico.eventBind(a,"click", action);
} else {
a.onclick=action;
}
a.className = 'enabled';
if (this.defaultAction==null) this.defaultAction=action;
} else {
a.disabled = true;
a.className = 'disabled';
}
a.innerHTML = menutext;
if (typeof title=='string')
a.title = title;
a=this.content.appendChild(a);
Rico.eventBind(a,"mouseover", Rico.eventHandle(this,'mouseOver'));
Rico.eventBind(a,"mouseout", Rico.eventHandle(this,'mouseOut'));
return a;
},
mouseOver: function(e) {
if (this.highlightElem && this.highlightElem.className=='enabled-hover') {
// required for Safari
this.highlightElem.className='enabled';
this.highlightElem=null;
}
var elem=Rico.eventElement(e);
if (this.openMenuAnchor && this.openMenuAnchor!=elem)
this.hideSubMenu();
if (elem.className=='enabled') {
elem.className='enabled-hover';
this.highlightElem=elem;
}
},
mouseOut: function(e) {
var elem=Rico.eventElement(e);
if (elem.className=='enabled-hover') elem.className='enabled';
if (this.highlightElem==elem) this.highlightElem=null;
},
cancelmenu: function() {
if (!this.visible()) return;
if (this.hideFunc) this.hideFunc();
this.hideFunc=null;
this.hidemenu();
},
hidemenu: function() {
if (this.openSubMenu) this.openSubMenu.hidemenu();
this.closePopup();
}
}
Rico.SelectionSet = function(selectionSet, options) {
this.initialize(selectionSet, options);
}
Rico.SelectionSet.prototype = {
/**
* @class
* @constructs
* @param selectionSet collection of DOM elements (or a CSS selection string)
* @param options object may contain any of the following:
* - selectedClass
- class name to add when element is selected, default is "selected"
* - selectNode
- optional function that returns the element to be selected
* - onSelect
- optional function that gets called when element is selected
* - onFirstSelect
- optional function that gets called the first time element is selected
* - noDefault
- when true, no element in the set is initially selected, default is false
* - selectedIndex
- index of the element that should be initially selected, default is 0
* - cookieName
- optional name of cookie to use to remember selected element. If specified, and the cookie exists, then the cookie value overrides selectedIndex.
* - cookieDays
- specifies how long cookie should persist (in days). If unspecified, then the cookie persists for the current session.
* - cookiePath
- optional cookie path
* - cookieDomain
- optional cookie domain
*
*/
initialize: function(selectionSet, options){
Rico.log('SelectionSet#initialize');
this.options = options || {};
if (typeof selectionSet == 'string')
selectionSet = Rico.select(selectionSet);
this.previouslySelected = [];
this.selectionSet = [];
this.selectedClassName = this.options.selectedClass || Rico.theme.selected || "selected";
this.selectNode = this.options.selectNode || function(e){return e;};
this.onSelect = this.options.onSelect;
this.onFirstSelect = this.options.onFirstSelect;
var self=this;
this.clickHandler = function(idx) { self.selectIndex(idx); };
this.selectedIndex=-1;
for (var i=0; i= 0) this.selectIndex(i);
},
_notifySelected: function(index){
if (index < 0) return;
var element = this.selectionSet[index];
if (this.options.cookieName)
Rico.setCookie(this.options.cookieName, index, this.options.cookieDays, this.options.cookiePath, this.options.cookieDomain);
if (this.onFirstSelect && !this.previouslySelected[index]){
this.onFirstSelect(element, index);
this.previouslySelected[index] = true;
}
if (this.onSelect)
try{
this.onSelect(index);
} catch (e) {};
},
selectIndex: function(index){
if (this.selectedIndex == index || index >= this.selectionSet.length) return;
this.clearSelected();
this._notifySelected(index);
this.selectedIndex = index;
this.selected=this.selectionSet[index].element;
Rico.addClass(this.selectNode(this.selected), this.selectedClassName);
},
nextSelectIndex: function(){
return (this.selectedIndex + 1) % this.selectionSet.length;
},
nextSelectItem: function(){
return this.selectionSet[this.nextSelectIndex()];
},
selectNext: function(){
this.selectIndex(this.nextSelectIndex());
},
add: function(item){
var index=this.selectionSet.length;
this.selectionSet[index] = new Rico._SelectionItem(item,index,this.clickHandler);
},
remove: function(item){
if (item==this.selected) this.clearSelected();
var i=this.getIndex(item);
if (i < 0) return;
this.selectionSet[i].remove();
this.selectionSet.splice(i,1);
},
removeAll: function(){
this.clearSelected();
while (this.selectionSet.length > 0) {
this.selectionSet.pop().remove();
}
}
};
Rico._SelectionItem=function(element,index,callback) {
this.add(element,index,callback);
};
Rico._SelectionItem.prototype = {
add: function(element,index,callback) {
this.element=element;
this.index=index;
this.callback=callback;
this.handle=Rico.eventHandle(this,'click');
Rico.eventBind(element, "click", this.handle);
},
click: function(ev) {
this.callback(this.index);
},
remove: function() {
Rico.eventUnbind(this.element, "click", this.handle);
}
};
Rico.HoverSet = function(hoverSet, options) {
this.initialize(hoverSet, options);
};
Rico.HoverSet.prototype = {
/**
* @class
* @constructs
* @param hoverSet collection of DOM elements
* @param options object may contain any of the following:
* - hoverClass
- class name to add when mouse is over element, default is "hover"
* - hoverNodes
- optional function to select/filter which nodes are in the set
*
*/
initialize: function(hoverSet, options){
Rico.log('HoverSet#initialize');
options = options || {};
this.hoverClass = options.hoverClass || Rico.theme.hover || "hover";
this.hoverFunc = options.hoverNodes || function(e){return [e];};
this.hoverSet=[];
if (!hoverSet) return;
for (var i=0; i 0) {
this.hoverSet.pop().remove();
}
}
};
Rico._HoverItem=function(element,selectFunc,hoverClass) {
this.add(element,selectFunc,hoverClass);
};
Rico._HoverItem.prototype = {
add: function(element,selectFunc,hoverClass) {
this.element=element;
this.selectFunc=selectFunc;
this.hoverClass=hoverClass;
this.movehandle=Rico.eventHandle(this,'move');
this.outhandle=Rico.eventHandle(this,'mouseout');
Rico.eventBind(element, "mousemove", this.movehandle);
Rico.eventBind(element, "mouseout", this.outhandle);
},
move: function(ev) {
var elems=this.selectFunc(this.element);
for (var i=0; i=2) {
items[0].className=options.titleClass || Rico.theme.accTitle || "Rico_accTitle";
items[1].className=options.contentClass || Rico.theme.accContent || "Rico_accContent";
titles.push(items[0]);
contents.push(items[1]);
var a=Rico.wrapChildren(items[0],'','','a');
a.href="javascript:void(0)";
}
}
Rico.log('creating Rico.Accordion for '+element.id+' with '+titles.length+' panels');
this.initBase(titles, contents, options);
this.selected.style.height = this.options.panelHeight + "px";
this.totSteps=(typeof options.duration =='number' ? options.duration : 200)/25;
},
transition: function(p){
if (!this.options.noAnimate) {
this.closing=this.selected;
this.opening=p;
this.curStep=0;
var self=this;
this.timer=setInterval(function() { self.step(); },25);
} else {
p.style.height = this.options.panelHeight + "px";
if (this.selected) Rico.hide(this.selected);
p.style.display='block';
}
},
step: function() {
this.curStep++;
var oheight=Math.round(this.curStep/this.totSteps*this.options.panelHeight);
this.opening.style.height=oheight+'px';
this.closing.style.height=(this.options.panelHeight - oheight)+'px';
if (this.curStep==1) {
this.opening.style.paddingTop=this.opening.style.paddingBottom='0px';
this.opening.style.display='block';
}
if (this.curStep==this.totSteps) {
clearInterval(this.timer);
this.opening.style.paddingTop=this.opening.style.paddingBottom='';
Rico.hide(this.closing);
}
},
setPanelHeight: function(h) {
this.options.panelHeight = h;
this.selected.style.height = this.options.panelHeight + "px";
}
});
/**
* @class Implements tabbed panel effect
* @see Rico.ContentTransitionBase#initialize for construction parameters
* @extends Rico.ContentTransitionBase
*/
Rico.TabbedPanel = function(element, options) {
this.initialize(element, options);
};
Rico.TabbedPanel.prototype = Rico.extend(new Rico.ContentTransitionBase(),
{
initialize: function(element, options) {
element=Rico.$(element);
options=options || {};
if (typeof options.panelWidth=='number') options.panelWidth+="px";
if (typeof options.panelHeight=='number') options.panelHeight+="px";
element.className=options.tabClass || Rico.theme.tabPanel || "Rico_tabPanel";
if (options.panelWidth) element.style.width = options.panelWidth;
var items = [];
var allKids = element.childNodes;
for( var i = 0 ; i < allKids.length ; i++ ) {
if (allKids[i] && allKids[i].tagName && allKids[i].tagName.match(/^div|ul$/i))
items.push(allKids[i]);
}
if (items.length < 2) return;
var childTag=items[0].tagName.toLowerCase()=='ul' ? 'li' : 'div';
items[0].className=options.navContainerClass || Rico.theme.tabNavContainer || "Rico_tabNavContainer";
items[0].style.listStyle='none';
items[1].className=options.contentContainerClass || Rico.theme.tabContentContainer || "Rico_tabContentContainer";
var titles=Rico.getDirectChildrenByTag(items[0], childTag);
var contents=Rico.getDirectChildrenByTag(items[1],'div');
if (!options.corners) options.corners='top';
for (var i=0; i= 0) return true;
}
return false;
}
};
Rico.toColorPart = function(c) {
return Rico.zFill(c, 2, 16);
};
Rico.Color = function(red, green, blue) {
this.initialize(red, green, blue);
};
Rico.Color.prototype = {
/**
* @class Methods to manipulate color values.
* @constructs
* @param red integer (0-255)
* @param green integer (0-255)
* @param blue integer (0-255)
*/
initialize: function(red, green, blue) {
this.rgb = { r: red, g : green, b : blue };
},
setRed: function(r) {
this.rgb.r = r;
},
setGreen: function(g) {
this.rgb.g = g;
},
setBlue: function(b) {
this.rgb.b = b;
},
setHue: function(h) {
// get an HSB model, and set the new hue...
var hsb = this.asHSB();
hsb.h = h;
// convert back to RGB...
this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
},
setSaturation: function(s) {
// get an HSB model, and set the new hue...
var hsb = this.asHSB();
hsb.s = s;
// convert back to RGB and set values...
this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
},
setBrightness: function(b) {
// get an HSB model, and set the new hue...
var hsb = this.asHSB();
hsb.b = b;
// convert back to RGB and set values...
this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
},
darken: function(percent) {
var hsb = this.asHSB();
this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
},
brighten: function(percent) {
var hsb = this.asHSB();
this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
},
blend: function(other) {
this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
},
isBright: function() {
var hsb = this.asHSB();
return this.asHSB().b > 0.5;
},
isDark: function() {
return ! this.isBright();
},
asRGB: function() {
return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
},
asHex: function() {
return "#" + Rico.toColorPart(this.rgb.r) + Rico.toColorPart(this.rgb.g) + Rico.toColorPart(this.rgb.b);
},
asHSB: function() {
return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
},
toString: function() {
return this.asHex();
}
};
/**
* Factory method for creating a color from an RGB string
* @param hexCode a 3 or 6 digit hex string, optionally preceded by a # symbol
* @returns a Rico.Color object
*/
Rico.Color.createFromHex = function(hexCode) {
if(hexCode.length==4) {
var shortHexCode = hexCode;
hexCode = '#';
for(var i=1;i<4;i++)
hexCode += (shortHexCode.charAt(i) + shortHexCode.charAt(i));
}
if ( hexCode.indexOf('#') == 0 )
hexCode = hexCode.substring(1);
if (!hexCode.match(/^[0-9A-Fa-f]{6}$/)) return null;
var red = hexCode.substring(0,2);
var green = hexCode.substring(2,4);
var blue = hexCode.substring(4,6);
return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
};
/**
* Retrieves the background color of an HTML element
* @param elem the DOM element whose background color should be retreived
* @returns a Rico.Color object
*/
Rico.Color.createColorFromBackground = function(elem) {
if (!elem.style) return new Rico.Color(255,255,255);
var actualColor = Rico.getStyle(elem, "background-color");
// if color is tranparent, check parent
// Safari returns "rgba(0, 0, 0, 0)", which means transparent
if ( actualColor.match(/^(transparent|rgba\(0,\s*0,\s*0,\s*0\))$/i) && elem.parentNode )
return Rico.Color.createColorFromBackground(elem.parentNode);
if (actualColor == null) return new Rico.Color(255,255,255);
if ( actualColor.indexOf("rgb(") == 0 ) {
var colors = actualColor.substring(4, actualColor.length - 1 );
var colorArray = colors.split(",");
return new Rico.Color( parseInt( colorArray[0],10 ),
parseInt( colorArray[1],10 ),
parseInt( colorArray[2],10 ) );
}
else if ( actualColor.indexOf("#") == 0 ) {
return Rico.Color.createFromHex(actualColor);
}
else
return new Rico.Color(255,255,255);
};
/**
* Converts hue/saturation/brightness to RGB
* @returns a 3-element object: r=red, g=green, b=blue.
*/
Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
var red = 0;
var green = 0;
var blue = 0;
if (saturation == 0) {
red = parseInt(brightness * 255.0 + 0.5,10);
green = red;
blue = red;
}
else {
var h = (hue - Math.floor(hue)) * 6.0;
var f = h - Math.floor(h);
var p = brightness * (1.0 - saturation);
var q = brightness * (1.0 - saturation * f);
var t = brightness * (1.0 - (saturation * (1.0 - f)));
switch (parseInt(h,10)) {
case 0:
red = (brightness * 255.0 + 0.5);
green = (t * 255.0 + 0.5);
blue = (p * 255.0 + 0.5);
break;
case 1:
red = (q * 255.0 + 0.5);
green = (brightness * 255.0 + 0.5);
blue = (p * 255.0 + 0.5);
break;
case 2:
red = (p * 255.0 + 0.5);
green = (brightness * 255.0 + 0.5);
blue = (t * 255.0 + 0.5);
break;
case 3:
red = (p * 255.0 + 0.5);
green = (q * 255.0 + 0.5);
blue = (brightness * 255.0 + 0.5);
break;
case 4:
red = (t * 255.0 + 0.5);
green = (p * 255.0 + 0.5);
blue = (brightness * 255.0 + 0.5);
break;
case 5:
red = (brightness * 255.0 + 0.5);
green = (p * 255.0 + 0.5);
blue = (q * 255.0 + 0.5);
break;
}
}
return { r : parseInt(red,10), g : parseInt(green,10) , b : parseInt(blue,10) };
};
/**
* Converts RGB value to hue/saturation/brightness
* @param r integer (0-255)
* @param g integer (0-255)
* @param b integer (0-255)
* @returns a 3-element object: h=hue, s=saturation, b=brightness.
* (unlike some HSB documentation which states hue should be a value 0-360, this routine returns hue values from 0 to 1.0)
*/
Rico.Color.RGBtoHSB = function(r, g, b) {
var hue;
var saturation;
var brightness;
var cmax = (r > g) ? r : g;
if (b > cmax)
cmax = b;
var cmin = (r < g) ? r : g;
if (b < cmin)
cmin = b;
brightness = cmax / 255.0;
if (cmax != 0)
saturation = (cmax - cmin)/cmax;
else
saturation = 0;
if (saturation == 0)
hue = 0;
else {
var redc = (cmax - r)/(cmax - cmin);
var greenc = (cmax - g)/(cmax - cmin);
var bluec = (cmax - b)/(cmax - cmin);
if (r == cmax)
hue = bluec - greenc;
else if (g == cmax)
hue = 2.0 + redc - bluec;
else
hue = 4.0 + greenc - redc;
hue = hue / 6.0;
if (hue < 0)
hue = hue + 1.0;
}
return { h : hue, s : saturation, b : brightness };
};
/**
* Returns a new XML document object
*/
Rico.createXmlDocument = function() {
if (document.implementation && document.implementation.createDocument) {
var doc = document.implementation.createDocument("", "", null);
// some older versions of Moz did not support the readyState property
// and the onreadystate event so we patch it!
if (doc.readyState == null) {
doc.readyState = 1;
doc.addEventListener("load", function () {
doc.readyState = 4;
if (typeof doc.onreadystatechange == "function") {
doc.onreadystatechange();
}
}, false);
}
return doc;
}
if (window.ActiveXObject)
return Rico.tryFunctions(
function() { return new ActiveXObject('MSXML2.DomDocument'); },
function() { return new ActiveXObject('Microsoft.DomDocument');},
function() { return new ActiveXObject('MSXML.DomDocument'); },
function() { return new ActiveXObject('MSXML3.DomDocument'); }
) || false;
return null;
}