/* http://keith-wood.name/icalendar.html
iCalendar processing for jQuery v1.1.1.
Written by Keith Wood (kbwood{at}iinet.com.au) October 2008.
Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
Please attribute the author if you use it. */
(function($){var p='icalendar';var q='icalendar-flash-copy';function iCalendar(){this._defaults={sites:[],icons:'icalendar.png',iconSize:16,target:'_blank',compact:false,popup:false,popupText:'Send to my calendar...',tipPrefix:'',echoUrl:'',echoField:'',start:null,end:null,title:'',summary:'',description:'',location:'',url:'',contact:'',recurrence:null,copyConfirm:'The event will be copied to your clipboard. Continue?',copySucceeded:'The event has been copied to your clipboard',copyFailed:'Failed to copy the event to the clipboard\n',copyFlash:'clipboard.swf',copyUnavailable:'The clipboard is unavailable, please copy the event details from below:\n'};this._sites={'google':{display:'Google',icon:0,override:null,url:'http://www.google.com/calendar/event?action=TEMPLATE'+'&text={t}&dates={s}/{e}&details={d}&location={l}&sprop=website:{u}'},'icalendar':{display:'iCalendar',icon:1,override:null,url:'echo'},'outlook':{display:'Outlook',icon:2,override:null,url:'echo'},'yahoo':{display:'Yahoo',icon:3,override:yahooOverride,url:'http://calendar.yahoo.com/?v=60&view=d&type=20'+'&title={t}&st={s}&dur={p}&desc={d}&in_loc={l}&url={u}&rpat={r}'}}}var r=[{method:'Seconds',factor:1},{method:'Minutes',factor:60},{method:'Hours',factor:3600},{method:'Date',factor:86400},{method:'Month',factor:1},{method:'FullYear',factor:12},{method:'Date',factor:604800}];var s=0;var t=1;var u=2;var w=3;var x=4;var y=5;var z=6;$.extend(iCalendar.prototype,{markerClassName:'hasICalendar',setDefaults:function(a){extendRemove(this._defaults,a||{});return this},addSite:function(a,b,c,d,e){this._sites[a]={display:b,icon:c,override:e,url:d};return this},getSites:function(){return this._sites},_attachICalendar:function(a,b){a=$(a);if(a.hasClass(this.markerClassName)){return}a.addClass(this.markerClassName);this._updateICalendar(a,b)},_changeICalendar:function(a,b){a=$(a);if(!a.hasClass(this.markerClassName)){return}this._updateICalendar(a,b)},_updateICalendar:function(i,j){j=extendRemove($.extend({},this._defaults,$.data(i[0],p)||{}),j);$.data(i[0],p,j);var k=j.sites||this._defaults.sites;if(k.length==0){$.each(this._sites,function(a){k[k.length]=a})}var l=function(b,c){var d={t:encodeURIComponent(j.title),d:encodeURIComponent(j.description),s:$.icalendar.formatDateTime(j.start),e:$.icalendar.formatDateTime(j.end),p:$.icalendar.calculateDuration(j.start,j.end),l:encodeURIComponent(j.location),u:encodeURIComponent(j.url),c:encodeURIComponent(j.contact),r:makeRecurrence(j.recurrence)};if(b.override){b.override.apply(i,[d,j])}var e=b.url;$.each(d,function(n,v){var a=new RegExp('\\{'+n+'\\}','g');e=e.replace(a,v)});var e=(b.url=='echo'?'#':e);var f=$('
');var g=$('');if(b.url=='echo'){g.click(function(){return $.icalendar._echo(i[0],c)})}var h='';if(b.icon!=null){if(typeof b.icon=='number'){h+=''}else{h+=''}h+=(j.compact?'':' ')}g.html(h+(j.compact?'':b.display));f.append(g);return f};var m=$('');var o=this._sites;$.each(k,function(a,b){m.append(l(o[b],b))});i.empty().append(m);if(j.popup){m.before('').wrap('');i.click(function(){var a=$(this);var b=a.offset();$('.icalendar_popup',a).css('left',b.left).css('top',b.top+a.outerHeight()).toggle()})}},_destroyICalendar:function(a){a=$(a);if(!a.hasClass(this.markerClassName)){return}a.removeClass(this.markerClassName).empty();$.removeData(a[0],p)},_echo:function(a,b){var c=$.data(a,p);var d=makeICalendar(c);if(c.echoUrl){window.location.href=c.echoUrl+'?content='+escape(d)}else if(c.echoField){$(c.echoField).val(d)}else if(!c.copyFlash){alert(c.copyUnavailable+d)}else if(confirm(c.copyConfirm)){var e='';if(e=copyViaFlash(d,c.copyFlash)){alert(c.copyFailed+e)}else{alert(c.copySucceeded)}}return false},_ensureTwo:function(a){return(a<10?'0':'')+a},formatDate:function(a,b){return(!a?'':''+a.getFullYear()+this._ensureTwo(a.getMonth()+1)+this._ensureTwo(a.getDate()))},formatDateTime:function(a,b){return(!a?'':(b?''+a.getFullYear()+this._ensureTwo(a.getMonth()+1)+this._ensureTwo(a.getDate())+'T'+this._ensureTwo(a.getHours())+this._ensureTwo(a.getMinutes())+this._ensureTwo(a.getSeconds()):''+a.getUTCFullYear()+this._ensureTwo(a.getUTCMonth()+1)+this._ensureTwo(a.getUTCDate())+'T'+this._ensureTwo(a.getUTCHours())+this._ensureTwo(a.getUTCMinutes())+this._ensureTwo(a.getUTCSeconds())+'Z'))},calculateDuration:function(a,b){if(!a||!b){return''}var c=Math.abs(b.getTime()-a.getTime())/1000;var d=Math.floor(c/86400);c-=d*86400;var e=Math.floor(c/3600);c-=e*3600;var f=Math.floor(c/60);c-=f*60;return(a.getTime()>b.getTime()?'-':'')+'P'+(d>0?d+'D':'')+(e||f||c?'T'+e+'H':'')+(f||c?f+'M':'')+(c?c+'S':'')},addDuration:function(d,e){if(!e){return d}var f=new Date(d.getTime());var g=I.exec(e);if(!g){throw'Invalid duration';}if(g[2]&&(g[3]||g[5]||g[6]||g[7])){throw'Invalid duration - week must be on its own';}if(!g[4]&&(g[5]||g[6]||g[7])){throw'Invalid duration - missing time marker';}var h=(g[1]=='-'?-1:+1);var i=function(a,b,c){a=parseInt(a);if(!isNaN(a)){f['setUTC'+c](f['getUTC'+c]()+h*a*b)}};if(g[2]){i(g[2],7,'Date')}else{i(g[3],1,'Date');i(g[5],1,'Hours');i(g[6],1,'Minutes');i(g[7],1,'Seconds')}return f},parse:function(a){var b={};var c={};var d=unfoldLines(a);parseGroup(d,0,b,c);if(!b.vcalendar){throw'Invalid iCalendar data';}return b.vcalendar},getWeekOfYear:function(a,b){return getWeekOfYear(a,b)},_parseParams:function(a,b){return parseParams(a,b)}});function extendRemove(a,b){$.extend(a,b);for(var c in b){if(b[c]==null){a[c]=null}}return a}$.fn.icalendar=function(a){var b=Array.prototype.slice.call(arguments,1);return this.each(function(){if(typeof a=='string'){$.icalendar['_'+a+'ICalendar'].apply($.icalendar,[this].concat(b))}else{$.icalendar._attachICalendar(this,a||{})}})};$.icalendar=new iCalendar();function yahooOverride(b,c){var d=function(a){return(a<10?'0':'')+a};var e=(c.end?(c.end.getTime()-c.start.getTime())/60000:0);b.p=(e?d(Math.floor(e/60))+''+d(e%60):'');if(b.r){var f=(c.recurrence.by&&c.recurrence.by[0].type=='day'?c.recurrence.by[0].values.join('').toLowerCase():'');var g={daily:'dy',weekly:'wk',monthly:'mh',yearly:'yr'}[c.recurrence.freq];b.r=(f||g?d(c.recurrence.interval||1)+(f||g):'')}}function makeICalendar(c){var d=function(a){var b='';while(a.length>75){b+=a.substr(0,75)+'\n';a=' '+a.substr(75)}b+=a;return b};return'BEGIN:VCALENDAR\n'+'VERSION:2.0\n'+'PRODID:jquery.icalendar\n'+'METHOD:PUBLISH\n'+'BEGIN:VEVENT\n'+'UID:'+new Date().getTime()+'@'+(window.location.href.replace(/^[^\/]*\/\/([^\/]*)\/.*$/,'$1')||'localhost')+'\n'+'DTSTAMP:'+$.icalendar.formatDateTime(new Date())+'\n'+(c.url?d('URL:'+c.url)+'\n':'')+(c.contact?d('MAILTO:'+c.contact)+'\n':'')+d('TITLE:'+c.title)+'\n'+'DTSTART:'+$.icalendar.formatDateTime(c.start)+'\n'+'DTEND:'+$.icalendar.formatDateTime(c.end)+'\n'+(c.summary?d('SUMMARY:'+c.summary)+'\n':'')+(c.description?d('DESCRIPTION:'+c.description)+'\n':'')+(c.location?d('LOCATION:'+c.location)+'\n':'')+(c.recurrence?makeRecurrence(c.recurrence)+'\n':'')+'END:VEVENT\n'+'END:VCALENDAR'}function makeRecurrence(a){if(!a){return''}var b='';if(a.dates){b='RDATE;VALUE=DATE:';if(!isArray(a.dates)){a.dates=[a.dates]}for(var i=0;i0?',':'')+$.icalendar.formatDate(a.dates[i])}}else if(a.times){b='RDATE;VALUE=DATE-TIME:';if(!isArray(a.times)){a.times=[a.times]}for(var i=0;i0?',':'')+$.icalendar.formatDateTime(a.times[i])}}else if(a.periods){b='RDATE;VALUE=PERIOD:';if(!isArray(a.periods[0])){a.periods=[a.periods]}for(var i=0;i0?',':'')+$.icalendar.formatDateTime(a.periods[i][0])+'/'+(a.periods[i][1].constructor!=Date?a.periods[i][1]:$.icalendar.formatDateTime(a.periods[i][1]))}}else{b='RRULE:FREQ='+(a.freq||'daily').toUpperCase()+(a.interval?';INTERVAL='+a.interval:'')+(a.until?';UNTIL='+$.icalendar.formatDateTime(a.until):(a.count?';COUNT='+a.count:''))+(a.weekStart!=null?';WKST='+['SU','MO','TU','WE','TH','FR','SA'][a.weekStart]:'');if(a.by){if(!isArray(a.by)){a.by=[a.by]}for(var i=0;i');return''}catch(e){return e}}var A=/^\s(.*)$/;var B=/^([A-Za-z0-9-]+)((?:;[A-Za-z0-9-]+=(?:"[^"]+"|[^";:,]+)(?:,(?:"[^"]+"|[^";:,]+))*)*):(.*)$/;var C=/;([A-Za-z0-9-]+)=((?:"[^"]+"|[^";:,]+)(?:,(?:"[^"]+"|[^";:,]+))*)/g;var D=/,?("[^"]+"|[^";:,]+)/g;var E=/^(\d{4})(\d\d)(\d\d)$/;var F=/^(\d{4})(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)(Z?)$/;var G=/^(\d{4})(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)(Z?)\/(\d{4})(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)(Z?)$/;var H=/^([+-])(\d\d)(\d\d)$/;var I=/^([+-])?P(\d+W)?(\d+D)?(T)?(\d+H)?(\d+M)?(\d+S)?$/;var J=['class'];function unfoldLines(b){var c=b.replace(/\r\n/g,'\n').split('\n');for(var i=c.length-1;i>0;i--){var d=A.exec(c[i]);if(d){c[i-1]+=d[1];c[i]=''}}return $.map(c,function(a,i){return(a?a:null)})}function parseGroup(a,b,c,d){if(b>=a.length||a[b].indexOf('BEGIN:')!=0){throw'Missing group start';}var e={};var f=a[b].substr(6);addEntry(c,f.toLowerCase(),e);b++;while(b-1){b+='_'}if(a[b]){if(!isArray(a[b])||a['_'+b+'IsArray']){a[b]=[a[b]]}a[b][a[b].length]=c;if(a['_'+b+'IsArray']){a['_'+b+'IsArray']=undefined}}else{a[b]=c;if(isArray(c)){a['_'+b+'IsArray']=true}}}function parseEntry(a){var b={};var c=B.exec(a);if(!c){throw'Missing entry name: '+a;}b._name=c[1].toLowerCase();b._value=checkDate(c[3]);b._simple=true;parseParams(b,c[2]);return b}function parseParams(a,b){var c=C.exec(b);while(c){var d=[];var e=D.exec(c[2]);while(e){d.push(checkDate(e[1].replace(/^"(.*)"$/,'$1')));e=D.exec(c[2])}a[c[1].toLowerCase()]=(d.length>1?d:d[0]);a._simple=false;c=C.exec(b)}}function checkDate(a){var b=F.exec(a);if(b){return makeDate(b)}b=G.exec(a);if(b){return{start:makeDate(b),end:makeDate(b.slice(7))}}b=E.exec(a);if(b){return makeDate(b.concat([0,0,0,'']))}return a}function makeDate(a){var b=new Date(a[1],a[2]-1,a[3],a[4],a[5],a[6]);b._type=(a[7]?'UTC':'float');return utcDate(b)}function utcDate(a){a.setMinutes(a.getMinutes()-a.getTimezoneOffset());return a}function getWeekOfYear(a,b){b=(b||b==0?b:1);var c=new Date(a.getFullYear(),a.getMonth(),a.getDate(),(a.getTimezoneOffset()/-60));var d=new Date(c.getFullYear(),1-1,4);var e=d.getDay();d.setDate(4+b-e-(b>e?7:0));if(cnew Date(c.getFullYear(),12-1,28)){var f=new Date(c.getFullYear()+1,1-1,4);e=f.getDay();f.setDate(4+b-e-(b>e?7:0));if(c>=f){return 1}}return Math.floor(((c-d)/(r[w].factor*1000))/7)+1}function isArray(a){return(a&&a.constructor==Array)}})(jQuery);