/* * Copyright 2005 Sabre Airline Solutions * * 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. */ if (typeof Rico=='undefined') throw("Cannot find the Rico object"); if (typeof Prototype=='undefined') throw("Rico requires the Prototype JavaScript framework"); Rico.prototypeVersion = parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1]); if (Rico.prototypeVersion < 1.3) throw("Rico requires Prototype JavaScript framework version 1.3 or greater"); /** @namespace */ var RicoUtil = { /** * Finds all immediate children of e with tagName * @param e DOM node or node id * @param tagName tag name to search for (case-insensative) * @returns array of matching elements */ getDirectChildrenByTag: function(e, tagName) { tagName=tagName.toLowerCase(); return $(e).childElements().inject([],function(result,child) { if (child.tagName && child.tagName.toLowerCase()==tagName) result.push(child); return result;}); }, /** * Returns a new XML document object */ 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 Try.these( 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; }, /** * Return text within an html element * @param el DOM node * @param xImg true to exclude img tag info * @param xForm true to exclude input, select, and textarea tags * @param xClass exclude elements with a class name of xClass */ getInnerText: function(el,xImg,xForm,xClass) { switch (typeof el) { case 'string': return el; case 'undefined': return el; case 'number': return el.toString(); } var cs = el.childNodes; var l = cs.length; var str = ""; for (var i = 0; i < l; i++) { switch (cs[i].nodeType) { case 1: //ELEMENT_NODE if (Element.getStyle(cs[i],'display')=='none') continue; if (xClass && Element.hasClassName(cs[i],xClass)) continue; switch (cs[i].tagName.toLowerCase()) { case 'img': if (!xImg) str += cs[i].alt || cs[i].title || cs[i].src; break; case 'input': if (cs[i].type=='hidden') continue; case 'select': case 'textarea': if (!xForm) str += $F(cs[i]) || ''; break; default: str += this.getInnerText(cs[i],xImg,xForm,xClass); break; } break; case 3: //TEXT_NODE str += cs[i].nodeValue; break; } } return str; }, /** * Return value of a node in an XML response. * For Konqueror 3.5, isEncoded must be true. */ getContentAsString: function( parentNode, isEncoded ) { if (isEncoded) return this._getEncodedContent(parentNode); if (typeof parentNode.xml != 'undefined') return this._getContentAsStringIE(parentNode); return this._getContentAsStringMozilla(parentNode); }, _getEncodedContent: function(parentNode) { if (parentNode.innerHTML) return parentNode.innerHTML; switch (parentNode.childNodes.length) { case 0: return ""; case 1: return parentNode.firstChild.nodeValue; default: return parentNode.childNodes[1].nodeValue; } }, _getContentAsStringIE: function(parentNode) { var contentStr = ""; for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) { var n = parentNode.childNodes[i]; contentStr += (n.nodeType == 4) ? n.nodeValue : n.xml; } return contentStr; }, _getContentAsStringMozilla: function(parentNode) { var xmlSerializer = new XMLSerializer(); var contentStr = ""; for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) { var n = parentNode.childNodes[i]; if (n.nodeType == 4) { // CDATA node contentStr += n.nodeValue; } else { contentStr += xmlSerializer.serializeToString(n); } } return contentStr; }, /** * @deprecated Will be removed in Rico 3 */ docElement: function() { return (document.compatMode && document.compatMode.indexOf("CSS")!=-1) ? document.documentElement : document.getElementsByTagName("body")[0]; }, /** * @returns available height, excluding scrollbar & margin * @deprecated Use Prototype's document.viewport.getHeight instead */ windowHeight: function() { if (document.viewport) { // use prototype 1.6 function return document.viewport.getHeight(); } else { return window.innerHeight? window.innerHeight : this.docElement().clientHeight; } }, /** * @returns available width, excluding scrollbar & margin * @deprecated Use Prototype's document.viewport.getWidth instead */ windowWidth: function() { if (document.viewport) { // use prototype 1.6 function return document.viewport.getWidth(); } else { return this.docElement().clientWidth; } }, /** * @deprecated Use Prototype's document.viewport.getScrollOffsets instead */ docScrollLeft: function() { if ( window.pageXOffset ) { return window.pageXOffset; } else if ( document.documentElement && document.documentElement.scrollLeft ) { return document.documentElement.scrollLeft; } else if ( document.body ) { return document.body.scrollLeft; } else { return 0; } }, /** * @deprecated Use Prototype's document.viewport.getScrollOffsets instead */ docScrollTop: function() { if ( window.pageYOffset ) { return window.pageYOffset; } else if ( document.documentElement && document.documentElement.scrollTop ) { return document.documentElement.scrollTop; } else if ( document.body ) { return document.body.scrollTop; } else { return 0; } }, /** * @param n a number (or a string to be converted using parseInt) * @returns the integer value of n, or 0 if n is not a number */ nan2zero: function(n) { if (typeof(n)=='string') n=parseInt(n,10); return isNaN(n) || typeof(n)=='undefined' ? 0 : n; }, /** * @param e event object * @returns the key code stored in the event */ eventKey: function(e) { if( typeof( e.keyCode ) == 'number' ) { return e.keyCode; //DOM } else if( typeof( e.which ) == 'number' ) { return e.which; //NS 4 compatible } else if( typeof( e.charCode ) == 'number' ) { return e.charCode; //also NS 6+, Mozilla 0.9+ } return -1; //total failure, we have no way of obtaining the key code }, /** * Return the previous sibling that has the specified tagName */ getPreviosSiblingByTagName: function(el,tagName) { var sib=el.previousSibling; while (sib) { if ((sib.tagName==tagName) && (sib.style.display!='none')) return sib; sib=sib.previousSibling; } return null; }, /** * Return the parent of el that has the specified tagName. * @param el DOM node * @param tagName tag to search for * @param className optional */ getParentByTagName: function(el,tagName,className) { var par=el; tagName=tagName.toLowerCase(); while (par) { if (par.tagName && par.tagName.toLowerCase()==tagName) { if (!className || par.className.indexOf(className)>=0) return par; } par=par.parentNode; } return null; }, /** * Wrap the children of a DOM element in a new element * @param el the element whose children are to be wrapped * @param cls class name of the wrapper (optional) * @param id id of the wrapper (optional) * @param wrapperTag type of wrapper element to be created (optional, defaults to DIV) * @returns new wrapper element */ wrapChildren: function(el,cls,id,wrapperTag) { var wrapper = document.createElement(wrapperTag || 'div'); if (id) wrapper.id=id; if (cls) wrapper.className=cls; while (el.firstChild) { wrapper.appendChild(el.firstChild); } el.appendChild(wrapper); return wrapper; }, /** * Format a positive number (integer or float) * @param posnum number to format * @param decPlaces the number of digits to display after the decimal point * @param thouSep the character to use as the thousands separator * @param decPoint the character to use as the decimal point * @returns formatted string */ formatPosNumber: function(posnum,decPlaces,thouSep,decPoint) { var a=posnum.toFixed(decPlaces).split(/\./); if (thouSep) { var rgx = /(\d+)(\d{3})/; while (rgx.test(a[0])) { a[0]=a[0].replace(rgx, '$1'+thouSep+'$2'); } } return a.join(decPoint); }, /** * Post condition - if childNodes[n] is refChild, than childNodes[n+1] is newChild. * @deprecated Use Prototype's Element#insert instead */ DOMNode_insertAfter: function(newChild,refChild) { var parentx=refChild.parentNode; if (parentx.lastChild==refChild) { return parentx.appendChild(newChild); } else { return parentx.insertBefore(newChild,refChild.nextSibling); } }, /** * Positions ctl over icon * @param ctl (div with position:absolute) * @param icon element (img, button, etc) that ctl should be displayed next to */ positionCtlOverIcon: function(ctl,icon) { var offsets=Position.page(icon); var scrTop=this.docScrollTop(); var winHt=this.windowHeight(); if (ctl.style.display=='none') ctl.style.display='block'; var correction=Prototype.Browser.IE ? 1 : 2; // based on a 1px border var lpad=this.nan2zero(Element.getStyle(icon,'padding-left')); ctl.style.left = (offsets[0]+lpad+correction)+'px'; var newTop=offsets[1] + correction + scrTop; var ctlht=ctl.offsetHeight; var iconht=icon.offsetHeight; var margin=10; // account for shadow if (newTop+iconht+ctlht+margin < winHt+scrTop) { newTop+=iconht; // display below icon } else { newTop=Math.max(newTop-ctlht,scrTop); // display above icon } ctl.style.top = newTop+'px'; }, /** * Creates a form element * @param parent new element will be appended to this node * @param elemTag element to be created (input, button, select, textarea, ...) * @param elemType for input tag this specifies the type (checkbox, radio, text, ...) * @param id id for new element * @param name name for new element, if not specified then name will be the same as the id * @returns new element */ createFormField: function(parent,elemTag,elemType,id,name) { var field; if (typeof name!='string') name=id; if (Prototype.Browser.IE) { // IE cannot set NAME attribute on dynamically created elements var s=elemTag+' id="'+id+'"'; if (elemType) { s+=' type="'+elemType+'"'; } if (elemTag.match(/^(form|input|select|textarea|object|button|img)$/)) { s+=' name="'+name+'"'; } field=document.createElement('<'+s+' />'); } else { field=document.createElement(elemTag); if (elemType) { field.type=elemType; } field.id=id; if (typeof field.name=='string') { field.name=name; } } parent.appendChild(field); return field; }, /** * Adds a new option to the end of a select list * @returns new option element */ addSelectOption: function(elem,value,text) { var opt=document.createElement('option'); if (typeof value=='string') opt.value=value; opt.text=text; if (Prototype.Browser.IE) { elem.add(opt); } else { elem.add(opt,null); } return opt; }, /** * @returns the value of the specified cookie (or null if it doesn't exist) */ getCookie: function(itemName) { var arg = itemName+'='; var alen = arg.length; var clen = document.cookie.length; var i = 0; while (i < clen) { var j = i + alen; if (document.cookie.substring(i, j) == arg) { var endstr = document.cookie.indexOf (';', j); if (endstr == -1) { endstr=document.cookie.length; } return unescape(document.cookie.substring(j, endstr)); } i = document.cookie.indexOf(' ', i) + 1; if (i == 0) break; } return null; }, /** * Write information to a cookie. * For cookies to be retained for the current session only, set daysToKeep=null. * To erase a cookie, pass a negative daysToKeep value. * @see Quirksmode article for more information about cookies. */ setCookie: function(itemName,itemValue,daysToKeep,cookiePath,cookieDomain) { var c = itemName+"="+escape(itemValue); if (typeof(daysToKeep)=='number') { var date = new Date(); date.setTime(date.getTime()+(daysToKeep*24*60*60*1000)); c+="; expires="+date.toGMTString(); } if (typeof(cookiePath)=='string') { c+="; path="+cookiePath; } if (typeof(cookieDomain)=='string') { c+="; domain="+cookieDomain; } document.cookie = c; } }; if (!RicoTranslate) { /** @namespace Translation helper object. Values are set by loading one of the ricoLocale_xx.js files. */ var RicoTranslate = { phrases : {}, phrasesById : {}, /** thousands separator for number formatting */ thouSep : ",", /** decimal point for number formatting */ decPoint: ".", /** target language (2 character code) */ langCode: "en", re : /^(\W*)\b(.*)\b(\W*)$/, /** date format */ dateFmt : "mm/dd/yyyy", /** time format */ timeFmt : "hh:nn:ss a/pm", /** month name array (Jan is at index 0) */ monthNames: ['January','February','March','April','May','June', 'July','August','September','October','November','December'], /** day of week array (Sunday is at index 0) */ dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], /** * @param monthIdx 0-11 * @returns 3 character abbreviation */ monthAbbr: function(monthIdx) { return this.monthNames[monthIdx].substr(0,3); }, /** * @param dayIdx 0-6 (Sunday=0) * @returns 3 character day of week abbreviation */ dayAbbr: function(dayIdx) { return this.dayNames[dayIdx].substr(0,3); }, /** * @deprecated Use addPhraseId instead */ addPhrase: function(fromPhrase, toPhrase) { this.phrases[fromPhrase]=toPhrase; }, /** * @deprecated Use getPhraseById instead * @param fromPhrase may contain multiple words/phrases separated by tabs * and each portion will be looked up separately. * Punctuation & spaces at the beginning or * ending of a phrase are ignored. */ getPhrase: function(fromPhrase) { var words=fromPhrase.split(/\t/); var transWord,translated = ''; for (var i=0; i *
locale or localeDateTime
*
use javascript's built-in toLocaleString() function
*
localeDate
*
use javascript's built-in toLocaleDateString() function
*
translate or translateDateTime
*
use the date and time format specified in the RicoTranslate object
*
translateDate
*
use the date format specified in the RicoTranslate object
*
Otherwise
*
Any combination of: yyyy, yy, mmmm, mmm, mm, m, hh, h, HH, H, nn, ss, a/p
* */ Date.prototype.formatDate = function(fmt) { var d=this; var datefmt=(typeof fmt=='string') ? fmt : 'translateDate'; switch (datefmt) { case 'locale': case 'localeDateTime': return d.toLocaleString(); case 'localeDate': return d.toLocaleDateString(); case 'translate': case 'translateDateTime': datefmt=RicoTranslate.dateFmt+' '+RicoTranslate.timeFmt; break; case 'translateDate': datefmt=RicoTranslate.dateFmt; break; } return datefmt.replace(/(yyyy|yy|mmmm|mmm|mm|dddd|ddd|dd|hh|nn|ss|a\/p)/gi, function($1) { var h; switch ($1) { case 'yyyy': return d.getFullYear(); case 'yy': return d.getFullYear().toString().substr(2); case 'mmmm': return RicoTranslate.monthNames[d.getMonth()]; case 'mmm': return RicoTranslate.monthAbbr(d.getMonth()); case 'mm': return (d.getMonth() + 1).toPaddedString(2); case 'm': return (d.getMonth() + 1); case 'dddd': return RicoTranslate.dayNames[d.getDay()]; case 'ddd': return RicoTranslate.dayAbbr(d.getDay()); case 'dd': return d.getDate().toPaddedString(2); case 'd': return d.getDate(); case 'hh': return ((h = d.getHours() % 12) ? h : 12).toPaddedString(2); case 'h': return ((h = d.getHours() % 12) ? h : 12); case 'HH': return d.getHours().toPaddedString(2); case 'H': return d.getHours(); case 'nn': return d.getMinutes().toPaddedString(2); case 'ss': return d.getSeconds().toPaddedString(2); case 'a/p': return d.getHours() < 12 ? 'a' : 'p'; } } ); }; } if (!Date.prototype.setISO8601) { /** * Converts a string in ISO 8601 format to a date object. * @returns true if string is a valid date or date-time. * @param string value to be converted * @param offset can be used to bias the conversion and must be in minutes if provided * @see Based on delete.me.uk article */ Date.prototype.setISO8601 = function (string,offset) { if (!string) return false; var d = string.match(/(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d)(?:[T ](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|(?:([-+])(\d\d)(?::?(\d\d))?)?)?)?)?)?/); if (!d) return false; if (!offset) offset=0; var date = new Date(d[1], 0, 1); if (d[2]) { date.setMonth(d[2] - 1); } if (d[3]) { date.setDate(d[3]); } if (d[4]) { date.setHours(d[4]); } if (d[5]) { date.setMinutes(d[5]); } if (d[6]) { date.setSeconds(d[6]); } if (d[7]) { date.setMilliseconds(Number("0." + d[7]) * 1000); } if (d[8]) { if (d[10] && d[11]) { offset = (Number(d[10]) * 60) + Number(d[11]); } offset *= ((d[9] == '-') ? 1 : -1); offset -= date.getTimezoneOffset(); } var time = (Number(date) + (offset * 60 * 1000)); this.setTime(Number(time)); return true; }; } if (!Date.prototype.toISO8601String) { /** * Convert date to an ISO 8601 formatted string. * @param format an integer in the range 1-6 (default is 6):
*
1 (year)
*
YYYY (eg 1997)
*
2 (year and month)
*
YYYY-MM (eg 1997-07)
*
3 (complete date)
*
YYYY-MM-DD (eg 1997-07-16)
*
4 (complete date plus hours and minutes)
*
YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
*
5 (complete date plus hours, minutes and seconds)
*
YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
*
6 (complete date plus hours, minutes, seconds and a decimal * fraction of a second)
*
YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
*
* @see Based on: codeproject.com article */ Date.prototype.toISO8601String = function (format, offset) { if (!format) format=6; var date; if (!offset) { offset = 'Z'; date = this; } else { var d = offset.match(/([-+])([0-9]{2}):([0-9]{2})/); var offsetnum = (Number(d[2]) * 60) + Number(d[3]); offsetnum *= ((d[1] == '-') ? -1 : 1); date = new Date(Number(Number(this) + (offsetnum * 60000))); } var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; }; var str = date.getUTCFullYear(); if (format > 1) { str += "-" + zeropad(date.getUTCMonth() + 1); } if (format > 2) { str += "-" + zeropad(date.getUTCDate()); } if (format > 3) { str += "T" + zeropad(date.getUTCHours()) + ":" + zeropad(date.getUTCMinutes()); } if (format > 5) { var secs = Number(date.getUTCSeconds() + "." + ((date.getUTCMilliseconds() < 100) ? '0' : '') + zeropad(date.getUTCMilliseconds())); str += ":" + zeropad(secs); } else if (format > 4) { str += ":" + zeropad(date.getUTCSeconds()); } if (format > 3) { str += offset; } return str; }; } if (!String.prototype.toISO8601Date) { /** * Convert string in ISO 8601 format to a date * @returns new date object */ String.prototype.toISO8601Date = function() { var d = new Date(); return d.setISO8601(this) ? d : null; }; } if (!String.prototype.formatDate) { /** * Format string containing a date * @see Date#formatDate */ String.prototype.formatDate = function(fmt) { var s=this.replace(/-/g,'/'); var d = new Date(s); return isNaN(d) ? this : d.formatDate(fmt); }; } if (!Number.prototype.formatNumber) { /** * Format a number according to the specs in fmt object. * @returns string, wrapped in a span element with a class of: negNumber, zeroNumber, posNumber * These classes can be set in CSS to display negative numbers in red, for example. * * @param fmt may contain any of the following:
*
multiplier
the original number is multiplied by this amount before formatting
*
decPlaces
number of digits to the right of the decimal point
*
decPoint
character to be used as the decimal point
*
thouSep
character to use as the thousands separator
*
prefix
string added to the beginning of the result (e.g. a currency symbol)
*
suffix
string added to the end of the result (e.g. % symbol)
*
negSign
specifies format for negative numbers: L=leading minus, T=trailing minus, P=parens
*
*/ Number.prototype.formatNumber = function(fmt) { if (isNaN(this)) return 'NaN'; var n=this; if (typeof fmt.multiplier=='number') n*=fmt.multiplier; var decPlaces=typeof fmt.decPlaces=='number' ? fmt.decPlaces : 0; var thouSep=typeof fmt.thouSep=='string' ? fmt.thouSep : RicoTranslate.thouSep; var decPoint=typeof fmt.decPoint=='string' ? fmt.decPoint : RicoTranslate.decPoint; var prefix=fmt.prefix || ""; var suffix=fmt.suffix || ""; var negSign=typeof fmt.negSign=='string' ? fmt.negSign : "L"; negSign=negSign.toUpperCase(); var s,cls; if (n<0.0) { s=RicoUtil.formatPosNumber(-n,decPlaces,thouSep,decPoint); if (negSign=="P") s="("+s+")"; s=prefix+s; if (negSign=="L") s="-"+s; if (negSign=="T") s+="-"; cls='negNumber'; } else { cls=n==0.0 ? 'zeroNumber' : 'posNumber'; s=prefix+RicoUtil.formatPosNumber(n,decPlaces,thouSep,decPoint); } return ""+s+suffix+""; }; } if (!String.prototype.formatNumber) { /** * Take a string that can be converted via parseFloat * and format it according to the specs in fmt object. * Number in string may use a period or comma as the decimal point, * but should not contain any thousands separator. */ String.prototype.formatNumber = function(fmt) { var n=parseFloat(this.replace(/,/,'.')); return isNaN(n) ? this : n.formatNumber(fmt); }; } Rico.Shim = Class.create(); /** @lends Rico.Shim# */ if (Prototype.Browser.IE) { Rico.Shim.prototype = { /** * @class Fixes select control bleed-thru on floating divs in IE. Used by Rico.Popup. * @see Based on technique published by Joe King * @constructs */ initialize: function(DivRef) { this.ifr = document.createElement('iframe'); this.ifr.style.position="absolute"; this.ifr.style.display = "none"; this.ifr.style.top = '0px'; this.ifr.style.left = '0px'; this.ifr.src="javascript:false;"; DivRef.parentNode.appendChild(this.ifr); this.DivRef=DivRef; }, hide: function() { this.ifr.style.display = "none"; }, move: function() { this.ifr.style.top = this.DivRef.style.top; this.ifr.style.left = this.DivRef.style.left; }, show: function() { this.ifr.style.width = this.DivRef.offsetWidth; this.ifr.style.height = this.DivRef.offsetHeight; this.move(); this.ifr.style.zIndex = this.DivRef.currentStyle.zIndex - 1; this.ifr.style.display = "block"; } }; } else { Rico.Shim.prototype = { /** @ignore */ initialize: function() {}, /** @ignore */ hide: function() {}, /** @ignore */ move: function() {}, /** @ignore */ show: function() {} }; } Rico.Shadow = Class.create( /** @lends Rico.Shadow# */ { /** * @class Creates a shadow for positioned elements. Used by Rico.Popup. * Uses blur filter in IE, and alpha-transparent png images for all other browsers. * @see Based on positioniseverything article * @constructs */ initialize: function(DivRef) { this.div = document.createElement('div'); this.div.style.position="absolute"; this.div.style.top='0px'; this.div.style.left='0px'; if (typeof this.div.style.filter=='undefined') { new Image().src = Rico.imgDir+"shadow.png"; new Image().src = Rico.imgDir+"shadow_ur.png"; new Image().src = Rico.imgDir+"shadow_ll.png"; this.createShadow(); this.offset=5; } else { this.div.style.backgroundColor='#888'; this.div.style.filter='progid:DXImageTransform.Microsoft.Blur(makeShadow=1, shadowOpacity=0.3, pixelRadius=3)'; this.offset=0; // MS blur filter already does offset } this.div.style.display = "none"; DivRef.parentNode.appendChild(this.div); this.DivRef=DivRef; }, createShadow: function() { var tab = document.createElement('table'); tab.style.height='100%'; tab.style.width='100%'; tab.cellSpacing=0; tab.dir='ltr'; var tr1=tab.insertRow(-1); tr1.style.height='8px'; var td11=tr1.insertCell(-1); td11.style.width='8px'; var td12=tr1.insertCell(-1); td12.style.background="transparent url("+Rico.imgDir+"shadow_ur.png"+") no-repeat right bottom"; var tr2=tab.insertRow(-1); var td21=tr2.insertCell(-1); td21.style.background="transparent url("+Rico.imgDir+"shadow_ll.png"+") no-repeat right bottom"; var td22=tr2.insertCell(-1); td22.style.background="transparent url("+Rico.imgDir+"shadow.png"+") no-repeat right bottom"; this.div.appendChild(tab); }, hide: function() { this.div.style.display = "none"; }, move: function() { this.div.style.top = (parseInt(this.DivRef.style.top || '0',10)+this.offset)+'px'; this.div.style.left = (parseInt(this.DivRef.style.left || '0',10)+this.offset)+'px'; }, show: function() { this.div.style.width = this.DivRef.offsetWidth + 'px'; this.div.style.height= this.DivRef.offsetHeight + 'px'; this.move(); this.div.style.zIndex= parseInt(Element.getStyle(this.DivRef,'z-index'),10) - 1; this.div.style.display = "block"; } }); Rico.Popup = Class.create( /** @lends Rico.Popup# */ { /** * @class Class to manage pop-up div windows. * @constructs * @param options object may contain any of the following:
*
hideOnEscape
hide popup when escape key is pressed? default=true
*
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
*
shadow
display shadow with popup? default=true
*
margin
number of pixels to allow for shadow, default=6
*
zIndex
which layer? default=1
*
overflow
how to handle content that overflows div? default=auto
*
canDragFunc
boolean value (or function that returns a boolean) indicating if it is ok to drag/reposition popup, default=false
*
* @param DivRef if supplied, then setDiv() is called at the end of initialization */ initialize: function(options,DivRef,closeFunc) { this.options = { hideOnEscape : true, hideOnClick : true, ignoreClicks : false, position : 'absolute', shadow : true, margin : 6, zIndex : 1, overflow : 'auto', canDragFunc : false }; Object.extend(this.options, options || {}); if (DivRef) this.setDiv(DivRef,closeFunc); }, /** * Apply popup behavior to a div that already exists in the DOM * @param DivRef div element in the DOM * @param closeFunc optional callback function when popup is closed */ setDiv: function(DivRef,closeFunc) { this.divPopup=$(DivRef); var position=this.options.position == 'auto' ? Element.getStyle(this.divPopup,'position').toLowerCase() : this.options.position; if (!this.divPopup || position != 'absolute') return; this.closeFunc=closeFunc || this.closePopup.bindAsEventListener(this); this.shim=new Rico.Shim(this.divPopup); if (this.options.shadow) this.shadow=new Rico.Shadow(this.divPopup); if (this.options.hideOnClick) Event.observe(document,"click", this.closeFunc); if (this.options.hideOnEscape) Event.observe(document,"keyup", this._checkKey.bindAsEventListener(this)); if (this.options.canDragFunc) Event.observe(this.titleDiv || this.divPopup, "mousedown", this.startDrag.bind(this)); if (this.options.ignoreClicks || this.options.canDragFunc) this.ignoreClicks(); }, /** * create popup div and insert content */ createPopup: function(parentElem, content, ht, wi, className, closeFunc) { var div = document.createElement('div'); div.style.position=this.options.position; div.style.zIndex=this.options.zIndex; div.style.overflow=this.options.overflow; div.style.top='0px'; div.style.left='0px'; div.style.height=ht; div.style.width=wi; div.className=className || 'ricoPopup'; if (content) div.innerHTML=content; parentElem.appendChild(div); this.setDiv(div,closeFunc); this.contentDiv=div; if (this.options.canDragFunc===true) this.options.canDragFunc=this.safeDragTest.bind(this); }, /** * @private Fixes problems with IE when clicking on the scrollbar * Not required when calling createWindow because dragging is only applied to the title bar */ safeDragTest: function(elem,event) { return (elem.componentFromPoint && elem.componentFromPoint(event.clientX,event.clientY)!='') ? false : elem==this.divPopup; }, /** * Create popup div with a title bar. * height (ht) and width (wi) parameters are required and apply to the content (title adds extra height) */ createWindow: function(title, content, ht, wi, className) { var div = document.createElement('div'); this.titleDiv = document.createElement('div'); this.contentDiv = document.createElement('div'); this.titleDiv.className='ricoTitle'; this.titleDiv.innerHTML=title; this.titleDiv.style.position='relative'; var img = document.createElement('img'); img.src=Rico.imgDir+"close.gif"; img.title=RicoTranslate.getPhraseById('close'); img.style.cursor='pointer'; img.style.position='absolute'; img.style.right='0px'; this.titleDiv.appendChild(img); this.contentDiv.className='ricoContent'; this.contentDiv.innerHTML=content; this.contentDiv.style.height=ht; this.contentDiv.style.width=wi; this.contentDiv.style.overflow=this.options.overflow; div.style.position=this.options.position; div.style.zIndex=this.options.zIndex; div.style.top='0px'; div.style.left='0px'; div.style.display='none'; div.className=className || 'ricoWindow'; div.appendChild(this.titleDiv); div.appendChild(this.contentDiv); document.body.appendChild(div); this.setDiv(div); Event.observe(img,"click", this.closePopup.bindAsEventListener(this)); }, /** @private */ ignoreClicks: function() { Event.observe(this.divPopup,"click", this._ignoreClick.bindAsEventListener(this)); }, _ignoreClick: function(e) { if (e.stopPropagation) e.stopPropagation(); else e.cancelBubble = true; return true; }, // event handler to process keyup events (hide menu on escape key) _checkKey: function(e) { if (RicoUtil.eventKey(e)==27) this.closeFunc(); return true; }, /** * Move popup to specified position */ move: function(left,top) { if (typeof left=='number') this.divPopup.style.left=left+'px'; if (typeof top=='number') this.divPopup.style.top=top+'px'; if (this.shim) this.shim.move(); if (this.shadow) this.shadow.move(); }, /** @private */ startDrag : function(event){ var elem=Event.element(event); var canDrag=typeof(this.options.canDragFunc)=='function' ? this.options.canDragFunc(elem,event) : this.options.canDragFunc; if (!canDrag) return; this.divPopup.style.cursor='move'; this.lastMouseX = event.clientX; this.lastMouseY = event.clientY; this.dragHandler = this.drag.bindAsEventListener(this); this.dropHandler = this.endDrag.bindAsEventListener(this); Event.observe(document, "mousemove", this.dragHandler); Event.observe(document, "mouseup", this.dropHandler); Event.stop(event); }, /** @private */ drag : function(event){ var newLeft = parseInt(this.divPopup.style.left,10) + event.clientX - this.lastMouseX; var newTop = parseInt(this.divPopup.style.top,10) + event.clientY - this.lastMouseY; this.move(newLeft, newTop); this.lastMouseX = event.clientX; this.lastMouseY = event.clientY; Event.stop(event); }, /** @private */ endDrag : function(){ this.divPopup.style.cursor=''; Event.stopObserving(document, "mousemove", this.dragHandler); Event.stopObserving(document, "mouseup", this.dropHandler); this.dragHandler=null; this.dropHandler=null; }, /** * Display popup at specified position */ openPopup: function(left,top) { this.divPopup.style.display="block"; if (typeof left=='number') this.divPopup.style.left=left+'px'; if (typeof top=='number') this.divPopup.style.top=top+'px'; if (this.shim) this.shim.show(); if (this.shadow) this.shadow.show(); }, /** * Hide popup */ closePopup: function() { if (this.dragHandler) this.endDrag(); if (this.shim) this.shim.hide(); if (this.shadow) this.shadow.hide(); this.divPopup.style.display="none"; } }); Rico.includeLoaded('ricoCommon.js');