/* * (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; } 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 (this.position != 'absolute') return; if (this.options.closeFunc) { this.closeFunc=this.options.closeFunc; } else { var self=this; this.closeFunc=function() { self.closePopup(); }; } this.container.style.top='0px'; this.container.style.left='0px'; this.container.style.display='none'; if (this.options.zIndex >= 0) this.container.style.zIndex=this.options.zIndex; this.content.style.zIndex=2; if (Rico.isIE && Rico.ieVersion < 7) { // create iframe shim this.ifr = document.createElement('iframe'); this.ifr.className='RicoShim'; this.ifr.frameBorder=0; this.ifr.src="javascript:'';"; this.container.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) { if (typeof left=='number') this.container.style.left=left+'px'; if (typeof top=='number') this.container.style.top=top+'px'; this.container.style.display=''; //this.position=='absolute' ? "block" : Rico.isIE && Rico.ieVersion<8 ? "inline" : "inline-block"; 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 (elem.parentNode == this.openMenuAnchor) elem=elem.parentNode; 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; }