2 * (c) 2005-2011 Richard Cowin (http://openrico.org)
3 * (c) 2005-2011 Matt Brown (http://dowdybrown.com)
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
6 * file except in compliance with the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software distributed under the
11 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
12 * either express or implied. See the License for the specific language governing permissions
13 * and limitations under the License.
17 * @namespace Main Rico object
24 try { // fix IE background image flicker (credit: www.mister-pixel.com)
25 document.execCommand("BackgroundImageCache", false, true);
27 if (typeof Rico_CONFIG == 'object') {
28 if (Rico_CONFIG.jsDir) this.setPaths(Rico_CONFIG.jsDir);
29 this.setBackgroundStyles();
30 if (Rico_CONFIG.enableLogging) this.enableLogging();
33 this.baseHref= location.protocol + "//" + location.host;
34 this.windowIsLoaded=false;
35 this.onLoadCallbacks=[];
36 this.onLoad(function() { Rico.log('Pre-load messages:\n'+Rico.preloadMsgs); });
39 _bindLoadEvent : function() {
40 Rico.eventBind(window,"load", Rico.eventHandle(Rico,'windowLoaded'));
43 setPaths : function(jsDir) {
47 setBackgroundStyles: function() {
48 var el = document.createElement('style');
49 document.getElementsByTagName('head')[0].appendChild(el);
50 if (!window.createPopup) { /* For Safari */
51 el.appendChild(document.createTextNode(''));
53 var s = document.styleSheets[document.styleSheets.length - 1];
54 this.addCssRule(s,'.rico-icon',Rico_CONFIG.imgIcons,'no-repeat');
55 this.addCssRule(s,'.ricoLG_Resize',Rico_CONFIG.imgResize,'repeat');
56 if (Rico_CONFIG.imgHeading) {
57 this.addCssRule(s,'tr.ricoLG_hdg th, tr.ricoLG_hdg td, table.ricoLiveGrid thead td, table.ricoLiveGrid thead th, .ricoTitle, .Rico_accTitle',Rico_CONFIG.imgHeading,'repeat-x scroll center left');
61 addCssRule: function(sheet,selector,imageUrl,repeat) {
62 if (!imageUrl) return;
63 var rule="background:url('"+imageUrl+"') "+repeat;
65 sheet.addRule(selector, rule);
66 } else if (sheet.insertRule) {
67 sheet.insertRule (selector+" { "+rule+" }", 0);
69 alert('unable to add rule: '+rule);
73 languageInclude : function(lang2) {
74 var el = document.createElement('script');
75 el.type = 'text/javascript';
76 el.src = this.jsDir+"ricoLocale_"+lang2+".js";
77 document.getElementsByTagName('head')[0].appendChild(el);
80 // called by the document onload event
81 windowLoaded: function() {
82 this.windowIsLoaded=true;
83 this.addPreloadMsg('Processing callbacks');
84 while (this.onLoadCallbacks.length > 0) {
85 var callback=this.onLoadCallbacks.shift();
86 if (callback) callback();
90 onLoad: function(callback,frontOfQ) {
92 this.onLoadCallbacks.unshift(callback);
94 this.onLoadCallbacks.push(callback);
95 if (this.windowIsLoaded) this.windowLoaded();
98 isKonqueror : navigator.userAgent.toLowerCase().indexOf("konqueror") > -1,
99 isIE: !!(window.attachEvent && navigator.userAgent.indexOf('Opera') === -1),
100 isOpera: navigator.userAgent.indexOf('Opera') > -1,
101 isWebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
102 isGecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') === -1,
103 ieVersion: /MSIE (\d+\.\d+);/.test(navigator.userAgent) ? new Number(RegExp.$1) : null,
107 startTime : new Date(),
109 timeStamp: function() {
110 var stamp = new Date();
111 return (stamp.getTime()-this.startTime.getTime())+": ";
114 setDebugArea: function(id, forceit) {
115 if (!this.debugArea || forceit) {
116 var newarea=document.getElementById(id);
117 if (!newarea) return;
118 this.debugArea=newarea;
123 addPreloadMsg: function(msg) {
124 this.preloadMsgs+=this.timeStamp()+msg+"\n";
129 enableLogging: function() {
130 if (this.debugArea) {
131 this.log = function(msg, resetFlag) {
132 if (resetFlag) this.debugArea.value='';
133 this.debugArea.value+=this.timeStamp()+msg+"\n";
135 } else if (window.console) {
136 if (window.console.firebug)
137 this.log = function(msg) { window.console.log(this.timeStamp(),msg); };
139 this.log = function(msg) { window.console.log(this.timeStamp()+msg); };
\r
140 } else if (window.opera) {
141 this.log = function(msg) { window.opera.postError(this.timeStamp()+msg); };
146 return typeof e == 'string' ? document.getElementById(e) : e;
149 runLater: function() {
150 var args = Array.prototype.slice.call(arguments);
151 var msec = args.shift();
152 var object = args.shift();
153 var method = args.shift();
154 return setTimeout(function() { object[method].apply(object,args); },msec);
157 visible: function(element) {
158 return Rico.getStyle(element,"display") != 'none';
161 show: function(element) {
162 element.style.display = '';
165 hide: function(element) {
166 element.style.display = 'none';
169 toggle: function(element) {
170 element.style.display = element.style.display == 'none' ? '' : 'none';
173 viewportOffset: function(element) {
174 var offset=Rico.cumulativeOffset(element);
175 offset.left -= this.docScrollLeft();
176 offset.top -= this.docScrollTop();
181 * Return text within an html element
183 * @param xImg true to exclude img tag info
184 * @param xForm true to exclude input, select, and textarea tags
185 * @param xClass exclude elements with a class name of xClass
187 getInnerText: function(el,xImg,xForm,xClass) {
189 case 'string': return el;
190 case 'undefined': return el;
191 case 'number': return el.toString();
193 var cs = el.childNodes;
196 for (var i = 0; i < l; i++) {
197 switch (cs[i].nodeType) {
198 case 1: //ELEMENT_NODE
199 if (this.getStyle(cs[i],'display')=='none') continue;
200 if (xClass && this.hasClass(cs[i],xClass)) continue;
201 switch (cs[i].tagName.toLowerCase()) {
202 case 'img': if (!xImg) str += cs[i].alt || cs[i].title || cs[i].src; break;
203 case 'input': if (!xForm && !cs[i].disabled && cs[i].type.toLowerCase()=='text') str += cs[i].value; break;
204 case 'select': if (!xForm && cs[i].selectedIndex>=0) str += cs[i].options[cs[i].selectedIndex].text; break;
205 case 'textarea': if (!xForm && !cs[i].disabled) str += cs[i].value; break;
206 default: str += this.getInnerText(cs[i],xImg,xForm,xClass); break;
210 str += cs[i].nodeValue;
218 * Return value of a node in an XML response.
219 * For Konqueror 3.5, isEncoded must be true.
221 getContentAsString: function( parentNode, isEncoded ) {
222 if (isEncoded) return this._getEncodedContent(parentNode);
223 if (typeof parentNode.xml != 'undefined') return this._getContentAsStringIE(parentNode);
224 return this._getContentAsStringMozilla(parentNode);
227 _getEncodedContent: function(parentNode) {
228 if (parentNode.innerHTML) return parentNode.innerHTML;
229 switch (parentNode.childNodes.length) {
231 case 1: return parentNode.firstChild.nodeValue;
232 default: return parentNode.childNodes[1].nodeValue;
236 _getContentAsStringIE: function(parentNode) {
238 for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
239 var n = parentNode.childNodes[i];
240 contentStr += (n.nodeType == 4) ? n.nodeValue : n.xml;
245 _getContentAsStringMozilla: function(parentNode) {
246 var xmlSerializer = new XMLSerializer();
248 for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
249 var n = parentNode.childNodes[i];
250 if (n.nodeType == 4) { // CDATA node
251 contentStr += n.nodeValue;
254 contentStr += xmlSerializer.serializeToString(n);
261 * @param n a number (or a string to be converted using parseInt)
262 * @returns the integer value of n, or 0 if n is not a number
264 nan2zero: function(n) {
265 if (typeof(n)=='string') n=parseInt(n,10);
266 return isNaN(n) || typeof(n)=='undefined' ? 0 : n;
269 stripTags: function(s) {
270 return s.replace(/<\/?[^>]+>/gi, '');
273 truncate: function(s,length) {
274 return s.length > length ? s.substr(0, length - 3) + '...' : s;
277 zFill: function(n,slen, radix) {
278 var s=n.toString(radix || 10);
279 while (s.length<slen) s='0'+s;
283 keys: function(obj) {
291 * @param e event object
292 * @returns the key code stored in the event
294 eventKey: function(e) {
295 if( typeof( e.keyCode ) == 'number' ) {
296 return e.keyCode; //DOM
297 } else if( typeof( e.which ) == 'number' ) {
298 return e.which; //NS 4 compatible
299 } else if( typeof( e.charCode ) == 'number' ) {
300 return e.charCode; //also NS 6+, Mozilla 0.9+
302 return -1; //total failure, we have no way of obtaining the key code
305 eventLeftClick: function(e) {
306 return (((e.which) && (e.which == 1)) ||
307 ((e.button) && (e.button == 1)));
310 eventRelatedTarget: function(e) {
311 return e.relatedTarget;
315 * Return the previous sibling that has the specified tagName
317 getPreviosSiblingByTagName: function(el,tagName) {
318 var sib=el.previousSibling;
320 if ((sib.tagName==tagName) && (sib.style.display!='none')) return sib;
321 sib=sib.previousSibling;
327 * Return the parent of el that has the specified tagName.
329 * @param tagName tag to search for
330 * @param className optional
332 getParentByTagName: function(el,tagName,className) {
334 tagName=tagName.toLowerCase();
336 if (par.tagName && par.tagName.toLowerCase()==tagName) {
337 if (!className || par.className.indexOf(className)>=0) return par;
345 * Wrap the children of a DOM element in a new element
346 * @param el the element whose children are to be wrapped
347 * @param cls class name of the wrapper (optional)
348 * @param id id of the wrapper (optional)
349 * @param wrapperTag type of wrapper element to be created (optional, defaults to DIV)
350 * @returns new wrapper element
352 wrapChildren: function(el,cls,id,wrapperTag) {
353 var wrapper = document.createElement(wrapperTag || 'div');
354 if (id) wrapper.id=id;
355 if (cls) wrapper.className=cls;
356 while (el.firstChild) {
357 wrapper.appendChild(el.firstChild);
359 el.appendChild(wrapper);
364 * Positions ctl over icon
365 * @param ctl (div with position:absolute)
366 * @param icon element (img, button, etc) that ctl should be displayed next to
368 positionCtlOverIcon: function(ctl,icon) {
370 var offsets=this.cumulativeOffset(icon);
371 var scrTop=this.docScrollTop();
372 var winHt=this.windowHeight();
373 if (ctl.style.display=='none') ctl.style.display='block';
374 //var correction=this.isIE ? 1 : 2; // based on a 1px border
375 var correction=2; // based on a 1px border
376 var lpad=this.nan2zero(this.getStyle(icon,'paddingLeft'));
377 ctl.style.left = (offsets.left+lpad+correction)+'px';
378 var newTop=offsets.top + correction;// + scrTop;
379 var ctlht=ctl.offsetHeight;
380 var iconht=icon.offsetHeight;
381 var margin=10; // account for shadow
382 if (newTop+iconht+ctlht+margin < winHt+scrTop) {
383 newTop+=iconht; // display below icon
385 newTop=Math.max(newTop-ctlht,scrTop); // display above icon
387 ctl.style.top = newTop+'px';
391 * Creates a form element
392 * @param parent new element will be appended to this node
393 * @param elemTag element to be created (input, button, select, textarea, ...)
394 * @param elemType for input tag this specifies the type (checkbox, radio, text, ...)
395 * @param id id for new element
396 * @param name name for new element, if not specified then name will be the same as the id
397 * @returns new element
399 createFormField: function(parent,elemTag,elemType,id,name) {
401 if (typeof name!='string') name=id;
402 if (this.isIE && this.ieVersion < 8) {
403 // IE cannot set NAME attribute on dynamically created elements
404 var s=elemTag+' id="'+id+'"';
406 s+=' type="'+elemType+'"';
408 if (elemTag.match(/^(form|input|select|textarea|object|button|img)$/)) {
409 s+=' name="'+name+'"';
411 field=document.createElement('<'+s+' />');
413 field=document.createElement(elemTag);
418 if (typeof field.name=='string') {
422 parent.appendChild(field);
427 * Adds a new option to the end of a select list
428 * @returns new option element
430 addSelectOption: function(elem,value,text) {
431 var opt=document.createElement('option');
432 if (typeof value=='string') opt.value=value;
443 * @returns the value of the specified cookie (or null if it doesn't exist)
445 getCookie: function(itemName) {
446 var arg = itemName+'=';
447 var alen = arg.length;
448 var clen = document.cookie.length;
452 if (document.cookie.substring(i, j) == arg) {
453 var endstr = document.cookie.indexOf (';', j);
455 endstr=document.cookie.length;
457 return unescape(document.cookie.substring(j, endstr));
459 i = document.cookie.indexOf(' ', i) + 1;
465 getTBody: function(tab) {
466 return tab.tBodies.length==0 ? tab.appendChild(document.createElement("tbody")) : tab.tBodies[0];
470 * Write information to a cookie.
471 * For cookies to be retained for the current session only, set daysToKeep=null.
472 * To erase a cookie, pass a negative daysToKeep value.
473 * @see <a href="http://www.quirksmode.org/js/cookies.html">Quirksmode article</a> for more information about cookies.
475 setCookie: function(itemName,itemValue,daysToKeep,cookiePath,cookieDomain) {
476 var c = itemName+"="+escape(itemValue);
477 if (typeof(daysToKeep)=='number') {
478 var date = new Date();
479 date.setTime(date.getTime()+(daysToKeep*24*60*60*1000));
480 c+="; expires="+date.toGMTString();
482 if (typeof(cookiePath)=='string') {
483 c+="; path="+cookiePath;
485 if (typeof(cookieDomain)=='string') {
486 c+="; domain="+cookieDomain;
492 /** thousands separator for number formatting */
494 /** decimal point for number formatting */
496 /** target language (2 character code) */
499 dateFmt : "mm/dd/yyyy",
501 timeFmt : "hh:nn:ss a/pm",
502 /** month name array (Jan is at index 0) */
503 monthNames: ['January','February','March','April','May','June',
504 'July','August','September','October','November','December'],
505 /** day of week array (Sunday is at index 0) */
506 dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
509 * @param monthIdx 0-11
510 * @returns month abbreviation
512 monthAbbr: function(monthIdx) {
513 return this.monthNamesShort ? this.monthNamesShort[monthIdx] : this.monthNames[monthIdx].substr(0,3);
517 * @param dayIdx 0-6 (Sunday=0)
518 * @returns day of week abbreviation
520 dayAbbr: function(dayIdx) {
521 return this.dayNamesShort ? this.dayNamesShort[dayIdx] : this.dayNames[dayIdx].substr(0,3);
524 addPhraseId: function(phraseId, phrase) {
525 this.phrasesById[phraseId]=phrase;
528 getPhraseById: function(phraseId) {
529 var phrase=this.phrasesById[phraseId];
531 alert('Error: missing phrase for '+phraseId);
534 if (arguments.length <= 1) return phrase;
536 return phrase.replace(/(\$\d)/g,
538 var idx=parseInt($1.charAt(1),10);
539 return (idx < a.length) ? a[idx] : '';
545 * Format a positive number (integer or float)
546 * @param posnum number to format
547 * @param decPlaces the number of digits to display after the decimal point
548 * @param thouSep the character to use as the thousands separator
549 * @param decPoint the character to use as the decimal point
550 * @returns formatted string
552 formatPosNumber: function(posnum,decPlaces,thouSep,decPoint) {
553 var a=posnum.toFixed(decPlaces).split(/\./);
555 var rgx = /(\d+)(\d{3})/;
556 while (rgx.test(a[0])) {
557 a[0]=a[0].replace(rgx, '$1'+thouSep+'$2');
560 return a.join(decPoint);
564 * Format a number according to the specs in fmt object.
565 * @returns string, wrapped in a span element with a class of: negNumber, zeroNumber, posNumber
566 * These classes can be set in CSS to display negative numbers in red, for example.
568 * @param n number to be formatted
569 * @param fmt may contain any of the following:<dl>
570 * <dt>multiplier </dt><dd> the original number is multiplied by this amount before formatting</dd>
571 * <dt>decPlaces </dt><dd> number of digits to the right of the decimal point</dd>
572 * <dt>decPoint </dt><dd> character to be used as the decimal point</dd>
573 * <dt>thouSep </dt><dd> character to use as the thousands separator</dd>
574 * <dt>prefix </dt><dd> string added to the beginning of the result (e.g. a currency symbol)</dd>
575 * <dt>suffix </dt><dd> string added to the end of the result (e.g. % symbol)</dd>
576 * <dt>negSign </dt><dd> specifies format for negative numbers: L=leading minus, T=trailing minus, P=parens</dd>
579 formatNumber : function(n,fmt) {
580 if (typeof n=='string') n=parseFloat(n.replace(/,/,'.'),10);
581 if (isNaN(n)) return 'NaN';
582 if (typeof fmt.multiplier=='number') n*=fmt.multiplier;
583 var decPlaces=typeof fmt.decPlaces=='number' ? fmt.decPlaces : 0;
584 var thouSep=typeof fmt.thouSep=='string' ? fmt.thouSep : this.thouSep;
585 var decPoint=typeof fmt.decPoint=='string' ? fmt.decPoint : this.decPoint;
586 var prefix=fmt.prefix || "";
587 var suffix=fmt.suffix || "";
588 var negSign=typeof fmt.negSign=='string' ? fmt.negSign : "L";
589 negSign=negSign.toUpperCase();
592 s=this.formatPosNumber(-n,decPlaces,thouSep,decPoint);
593 if (negSign=="P") s="("+s+")";
595 if (negSign=="L") s="-"+s;
596 if (negSign=="T") s+="-";
599 cls=n==0.0 ? 'zeroNumber' : 'posNumber';
600 s=prefix+this.formatPosNumber(n,decPlaces,thouSep,decPoint);
602 return "<span class='"+cls+"'>"+s+suffix+"</span>";
606 * Converts a date to a string according to specs in fmt
607 * @returns formatted string
608 * @param d date to be formatted
609 * @param fmt string specifying the output format, may be one of the following:<dl>
610 * <dt>locale or localeDateTime</dt>
611 * <dd>use javascript's built-in toLocaleString() function</dd>
612 * <dt>localeDate</dt>
613 * <dd>use javascript's built-in toLocaleDateString() function</dd>
614 * <dt>translate or translateDateTime</dt>
615 * <dd>use the formats specified in the Rico.dateFmt and Rico.timeFmt properties</dd>
616 * <dt>translateDate</dt>
617 * <dd>use the date format specified in the Rico.dateFmt property</dd>
619 * <dd>Any combination of: yyyy, yy, mmmm, mmm, mm, m, dddd, ddd, dd, d, hh, h, HH, H, nn, ss, a/p</dd>
622 formatDate : function(d,fmt) {
623 var datefmt=(typeof fmt=='string') ? fmt : 'translateDate';
626 case 'localeDateTime':
627 return d.toLocaleString();
629 return d.toLocaleDateString();
631 case 'translateDateTime':
632 datefmt=this.dateFmt+' '+this.timeFmt;
634 case 'translateDate':
635 datefmt=this.dateFmt;
638 return datefmt.replace(/(yyyy|yy|mmmm|mmm|mm|dddd|ddd|dd|hh|nn|ss|a\/p)/gi,
642 case 'yyyy': return d.getFullYear();
643 case 'yy': return d.getFullYear().toString().substr(2);
644 case 'mmmm': return Rico.monthNames[d.getMonth()];
645 case 'mmm': return Rico.monthAbbr(d.getMonth());
646 case 'mm': return Rico.zFill(d.getMonth() + 1, 2);
647 case 'm': return (d.getMonth() + 1);
648 case 'dddd': return Rico.dayNames[d.getDay()];
649 case 'ddd': return Rico.dayAbbr(d.getDay());
650 case 'dd': return Rico.zFill(d.getDate(), 2);
651 case 'd': return d.getDate();
652 case 'hh': return Rico.zFill((h = d.getHours() % 12) ? h : 12, 2);
653 case 'h': return ((h = d.getHours() % 12) ? h : 12);
654 case 'HH': return Rico.zFill(d.getHours(), 2);
655 case 'H': return d.getHours();
656 case 'nn': return Rico.zFill(d.getMinutes(), 2);
657 case 'ss': return Rico.zFill(d.getSeconds(), 2);
658 case 'a/p': return d.getHours() < 12 ? 'a' : 'p';
665 * Converts a string in ISO 8601 format to a date object.
666 * @returns date object, or false if string is not a valid date or date-time.
667 * @param string value to be converted
668 * @param offset can be used to bias the conversion and must be in minutes if provided
669 * @see Based on <a href='http://delete.me.uk/2005/03/iso8601.html'>delete.me.uk article</a>
671 setISO8601 : function (string,offset) {
672 if (!string) return false;
673 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))?)?)?)?)?)?/);
674 if (!d) return false;
675 if (!offset) offset=0;
676 var date = new Date(d[1], 0, 1);
678 if (d[2]) { date.setMonth(d[2] - 1); }
679 if (d[3]) { date.setDate(d[3]); }
680 if (d[4]) { date.setHours(d[4]); }
681 if (d[5]) { date.setMinutes(d[5]); }
682 if (d[6]) { date.setSeconds(d[6]); }
683 if (d[7]) { date.setMilliseconds(Number("0." + d[7]) * 1000); }
685 if (d[10] && d[11]) {
686 offset = (Number(d[10]) * 60) + Number(d[11]);
688 offset *= ((d[9] == '-') ? 1 : -1);
689 offset -= date.getTimezoneOffset();
691 var time = (Number(date) + (offset * 60 * 1000));
692 date.setTime(Number(time));
697 * Convert date to an ISO 8601 formatted string.
698 * @param date date object to be converted
699 * @param format an integer in the range 1-6 (default is 6):<dl>
701 * <dd>YYYY (eg 1997)</dd>
702 * <dt>2 (year and month)</dt>
703 * <dd>YYYY-MM (eg 1997-07)</dd>
704 * <dt>3 (complete date)</dt>
705 * <dd>YYYY-MM-DD (eg 1997-07-16)</dd>
706 * <dt>4 (complete date plus hours and minutes)</dt>
707 * <dd>YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)</dd>
708 * <dt>5 (complete date plus hours, minutes and seconds)</dt>
709 * <dd>YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)</dd>
710 * <dt>6 (complete date plus hours, minutes, seconds and a decimal
711 * fraction of a second)</dt>
712 * <dd>YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)</dd>
714 * @see Based on: <a href='http://www.codeproject.com/jscript/dateformat.asp'>codeproject.com article</a>
716 toISO8601String : function (date, format, offset) {
717 if (!format) format=6;
721 var d = offset.match(/([-+])([0-9]{2}):([0-9]{2})/);
722 var offsetnum = (Number(d[2]) * 60) + Number(d[3]);
723 offsetnum *= ((d[1] == '-') ? -1 : 1);
724 date = new Date(Number(Number(date) + (offsetnum * 60000)));
727 var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; };
729 var str = date.getUTCFullYear();
730 if (format > 1) { str += "-" + zeropad(date.getUTCMonth() + 1); }
731 if (format > 2) { str += "-" + zeropad(date.getUTCDate()); }
733 str += "T" + zeropad(date.getUTCHours()) +
734 ":" + zeropad(date.getUTCMinutes());
737 var secs = Number(date.getUTCSeconds() + "." +
738 ((date.getUTCMilliseconds() < 100) ? '0' : '') +
739 zeropad(date.getUTCMilliseconds()));
740 str += ":" + zeropad(secs);
741 } else if (format > 4) {
742 str += ":" + zeropad(date.getUTCSeconds());
745 if (format > 3) { str += offset; }
750 * Returns a new XML document object
752 createXmlDocument : function() {
753 if (document.implementation && document.implementation.createDocument) {
754 var doc = document.implementation.createDocument("", "", null);
755 // some older versions of Moz did not support the readyState property
756 // and the onreadystate event so we patch it!
757 if (doc.readyState == null) {
759 doc.addEventListener("load", function () {
761 if (typeof doc.onreadystatechange == "function") {
762 doc.onreadystatechange();
769 if (window.ActiveXObject)
770 return Rico.tryFunctions(
771 function() { return new ActiveXObject('MSXML2.DomDocument'); },
772 function() { return new ActiveXObject('Microsoft.DomDocument');},
773 function() { return new ActiveXObject('MSXML.DomDocument'); },
774 function() { return new ActiveXObject('MSXML3.DomDocument'); }
782 * Update the contents of an HTML element via an AJAX call
784 Rico.ajaxUpdater = function(elem,url,options) {
785 this.updateSend(elem,url,options);
788 Rico.ajaxUpdater.prototype = {
789 updateSend : function(elem,url,options) {
791 this.onComplete=options.onComplete;
792 options.onComplete=function(xhr) { self.updateComplete(xhr); };
793 new Rico.ajaxRequest(url,options);
796 updateComplete : function(xhr) {
797 this.element.innerHTML=xhr.responseText;
798 if (this.onComplete) this.onComplete(xhr);
802 Rico.writeDebugMsg=Rico.log; // for backwards compatibility