/* CalDavZAP - the open source CalDAV Web Client Copyright (C) 2011-2015 Jan Mate <jan.mate@inf-it.com> Andrej Lezo <andrej.lezo@inf-it.com> Matej Mihalik <matej.mihalik@inf-it.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ // Used to match XML element names with any namespace jQuery.fn.filterNsNode=function(nameOrRegex) { return this.filter( function() { if(nameOrRegex instanceof RegExp) return (this.nodeName.match(nameOrRegex) || this.nodeName.replace(RegExp('^[^:]+:',''),'').match(nameOrRegex)); else return (this.nodeName===nameOrRegex || this.nodeName.replace(RegExp('^[^:]+:',''),'')===nameOrRegex); } ); }; // Escape jQuery selector function jqueryEscapeSelector(inputValue) { return (inputValue==undefined ? '' : inputValue).toString().replace(/([ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g,'\\$1'); } // Generate random string (UID) function generateUID() { uidChars='0123456789abcdefghijklmnopqrstuvwxyz'; UID=''; for(i=0;i<32;i++) { if(i==8 || i==12 || i==16 || i==20) UID+='-'; UID+=uidChars.charAt(Math.floor(Math.random()*(uidChars.length-1))); } return UID; } // IE compatibility if (typeof window.btoa=='undefined' && typeof base64.encode!='undefined') window.btoa=base64.encode; // Create Basic auth string (for HTTP header) function basicAuth(user, password) { var tok=user+':'+password; var hash=btoa(tok); return 'Basic '+hash; } // multiply regex replace {'regex': value, 'regex': value} String.prototype.multiReplace=function(hash) { var str=this, key; for(key in hash) str=str.replace(new RegExp(key,'g'), hash[key]); return str; }; // Used for sorting the contact and resource list ... String.prototype.customCompare=function(stringB, alphabet, dir, caseSensitive) { var stringA=this; if(alphabet==undefined || alphabet==null) return stringA.localeCompare(stringB); else { var pos=0, min=Math.min(stringA.length, stringB.length); dir=dir || 1; caseSensitive=caseSensitive || false; if(!caseSensitive) { stringA=stringA.toLowerCase(); stringB=stringB.toLowerCase(); } while(stringA.charAt(pos)===stringB.charAt(pos) && pos<min){pos++;} if(stringA.charAt(pos)=='') return -dir; else { var index1=alphabet.indexOf(stringA.charAt(pos)); var index2=alphabet.indexOf(stringB.charAt(pos)); if(index1==-1 || index2==-1) return stringA.localeCompare(stringB); else return (index1<index2 ? -dir : dir); } } }; function customResourceCompare(objA, objB) { return objA.displayValue.customCompare(objB.displayValue, globalSortAlphabet, 1, false); } function checkColorBrightness(hex) { var R=parseInt(hex.substring(0, 2), 16); var G=parseInt(hex.substring(2, 4), 16); var B=parseInt(hex.substring(4, 6), 16); return Math.sqrt(0.241*R*R+0.691*G*G+0.068*B*B); } // Get unique values from array Array.prototype.unique=function() { var o={}, i, l=this.length, r=[]; for(i=0;i<l;i++) o[this[i]]=this[i]; for(i in o) r.push(o[i]); return r; }; // Recursive replaceAll String.prototype.replaceAll=function(stringToFind,stringToReplace) { var temp=this; while(temp.indexOf(stringToFind)!=-1) temp=temp.replace(stringToFind,stringToReplace); return temp; }; // Pad number with leading zeroes Number.prototype.pad=function(size){ var s=String(this); while(s.length<size) s='0'+s; return s; }; // Case insensitive search for attributes // Usage: $('#selector').find(':attrCaseInsensitive(data-type,"'+typeList[i]+'")') jQuery.expr[':'].attrCaseInsensitive=function(elem, index, match) { var matchParams=match[3].split(','), attribute=matchParams[0].replace(/^\s*|\s*$/g,''), value=matchParams[1].replace(/^\s*"|"\s*$/g,'').toLowerCase(); return jQuery(elem)['attr'](attribute)!=undefined && jQuery(elem)['attr'](attribute)==value; }; // Capitalize given string function capitalize(string) { return string.charAt(0).toUpperCase()+string.slice(1).toLowerCase(); } var timezoneKeys = new Array(); function populateTimezoneKeys() { for(var i in timezones) timezoneKeys.push(i); timezoneKeys.push('0local'); timezoneKeys.push('1UTC'); timezoneKeys.sort(); timezoneKeys[0] = timezoneKeys[0].substring(1); timezoneKeys[1] = timezoneKeys[1].substring(1); jQuery.extend(timezones,{'UTC':{}}); } Date.prototype.getWeekNo=function() { var today = this; Year = today.getFullYear(); Month = today.getMonth(); Day = today.getDate(); now = Date.UTC(Year,Month,Day,0,0,0); var Firstday = new Date(); Firstday.setYear(Year); Firstday.setMonth(0); Firstday.setDate(1); then = Date.UTC(Year,0,1,0,0,0); var Compensation = Firstday.getDay(); if(((now-then)/86400000) > 3) NumberOfWeek = Math.round((((now-then)/86400000)+Compensation)/7); else { if(Firstday.getDay()>4 || Firstday.getDay()==0) NumberOfWeek = 53; } return NumberOfWeek; } function zeroPad(n) { return (n < 10 ? '0' : '') + n; } var dateFormatters = { s : function(d) {return d.getSeconds() }, ss : function(d) {return zeroPad(d.getSeconds())}, m : function(d) {return d.getMinutes()}, mm : function(d) {return zeroPad(d.getMinutes())}, h : function(d) {return d.getHours() % 12 || 12}, hh : function(d) {return zeroPad(d.getHours() % 12 || 12)}, H : function(d) {return d.getHours()}, HH : function(d) {return zeroPad(d.getHours())}, d : function(d) {return d.getDate()}, dd : function(d) {return zeroPad(d.getDate())}, ddd : function(d,o) {return o.dayNamesShort[d.getDay()]}, dddd: function(d,o) {return o.dayNames[d.getDay()]}, W : function(d) {return d.getWeekNo()}, M : function(d) {return d.getMonth() + 1}, MM : function(d) {return zeroPad(d.getMonth() + 1)}, MMM : function(d,o) {return o.monthNamesShort[d.getMonth()]}, MMMM: function(d,o) {return o.monthNames[d.getMonth()]}, yy : function(d) {return (d.getFullYear()+'').substring(2)}, yyyy: function(d) {return d.getFullYear()}, t : function(d) {return d.getHours() < 12 ? 'a' : 'p'}, tt : function(d) {return d.getHours() < 12 ? 'am' : 'pm'}, T : function(d) {return d.getHours() < 12 ? 'A' : 'P'}, TT : function(d) {return d.getHours() < 12 ? 'AM' : 'PM'}, u : function(d) {return formatDates(d, null, "yyyy-MM-dd'T'HH:mm:ss'Z'")}, S : function(d) { var date = d.getDate(); if (date > 10 && date < 20) { return 'th'; } return ['st', 'nd', 'rd'][date%10-1] || 'th'; } }; function formatDates(date1, date2, format, options) { options = options; var date = date1, otherDate = date2, i, len = format.length, c, i2, formatter, res = ''; for (i=0; i<len; i++) { c = format.charAt(i); if (c == "'") { for (i2=i+1; i2<len; i2++) { if (format.charAt(i2) == "'") { if (date) { if (i2 == i+1) { res += "'"; }else{ res += format.substring(i+1, i2); } i = i2; } break; } } } else if (c == '(') { for (i2=i+1; i2<len; i2++) { if (format.charAt(i2) == ')') { var subres = formatDates(date, null, format.substring(i+1, i2), options); if (parseInt(subres.replace(/\D/, ''), 10)) { res += subres; } i = i2; break; } } } else if (c == '[') { for (i2=i+1; i2<len; i2++) { if (format.charAt(i2) == ']') { var subformat = format.substring(i+1, i2); var subres = formatDates(date, null, subformat, options); if (subres != formatDates(otherDate, null, subformat, options)) { res += subres; } i = i2; break; } } } else if (c == '{') { date = date2; otherDate = date1; } else if (c == '}') { date = date1; otherDate = date2; } else { for (i2=len; i2>i; i2--) { if (formatter = dateFormatters[format.substring(i, i2)]) { if (date) { res += formatter(date, options); } i = i2 - 1; break; } } if (i2 == i) { if (date) { res += c; } } } } return res; }; function vObjectLineFolding(inputText) { var outputText=''; var maxLineOctetLength=75; var count=0; for(var i=0; inputText[i]!=undefined; i++) { var currentChar=inputText.charCodeAt(i); var nextChar=inputText.charCodeAt(i+1); if(currentChar==0x000D && nextChar==0x000A) { count=0; outputText+='\r\n'; i++; continue; } var surrogatePair=false; if(currentChar<0x0080) var charNum=1; else if(currentChar<0x0800) var charNum=2; else if(currentChar<0xd800 || currentChar>=0xe000) var charNum=3; else { // surrogate pair // UTF-16 encodes 0x10000-0x10FFFF by subtracting 0x10000 and splitting // the 20 bits of 0x0-0xFFFFF into two halves charNum=4; surrogatePair=true; } if(count>maxLineOctetLength-charNum) { outputText+='\r\n '; count=1; } outputText+=String.fromCharCode(currentChar); if(surrogatePair) { outputText+=String.fromCharCode(vCardText.charCodeAt(i+1)); i++; } count+=charNum; } return outputText; } function rgbToHex(rgb) { rgb=rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d*)?|(?:\.\d+)))?\)$/); function hex(x) { return ("0"+parseInt(x).toString(16)).slice(-2); } return "#"+hex(rgb[1])+hex(rgb[2])+hex(rgb[3]); } function hexToRgba(hex, transparency) { var bigint=parseInt(hex.substring(1), 16); var r=(bigint >> 16) & 255; var g=(bigint >> 8) & 255; var b=bigint & 255; return 'rgba('+r+','+g+','+b+','+transparency+')'; } function rgbToRgba(rgb, transparency) { rgb=rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d*)?|(?:\.\d+)))?\)$/); return 'rgba('+rgb[1]+','+rgb[2]+','+rgb[3]+','+transparency+')'; } function dataGetChecked(resourceListSelector) { var checkedArr=$(resourceListSelector).find('input[type=checkbox]:checked').not('.unloadCheck').filter('[data-id]').filter(function(){return this.indeterminate==false}).map(function(){return $(this).attr('data-id')}).get(); for(i=checkedArr.length-1; i>=0; i--) if(checkedArr[i].match(new RegExp('[^/]$'))!=null && checkedArr.indexOf(checkedArr[i].replace(new RegExp('[^/]+$'), ''))!=-1) checkedArr.splice(i, 1); return checkedArr; } function resourceChBoxClick(obj, resourceListSelector, headerSelector, returnChecked) { $(obj).parent().nextUntil(headerSelector).find('input[type=checkbox]:visible').prop('checked', $(obj).prop('checked')).prop('indeterminate', false); if(returnChecked) return dataGetChecked(resourceListSelector); } function collectionChBoxClick(obj, resourceListSelector, headerSelector, collectionSelector, groupSelector, returnChecked) { if(collectionSelector.match('_item$')) { var tmp_coh=$(obj).parent().prevAll(headerSelector).first(); var tmp_co_chbxs=tmp_coh.nextUntil(headerSelector).find('input[type=checkbox]:visible'); } else { var tmp_coh=$(obj).parent().parent().prevAll(headerSelector).first(); var tmp_co_chbxs=tmp_coh.nextUntil(headerSelector).find(collectionSelector).find('input[type=checkbox]:visible'); } if(groupSelector!=null) { if($(obj).prop('checked')==false && $(obj).prop('indeterminate')==false && $(obj).attr('data-ind')=='false' && $(obj).parent().next(groupSelector).height()>0/* note: ':visible' is not working! */) { $(obj).prop('indeterminate', true); $(obj).prop('checked', true); $(obj).attr('data-ind', 'true'); tmp_coh.find('input[type=checkbox]:visible').prop('indeterminate', true).prop('checked', false); if(returnChecked) return dataGetChecked(resourceListSelector); return true; } else if($(obj).attr('data-ind')=='true') $(obj).attr('data-ind', 'false'); $(obj).parent().next(groupSelector).find('input[type=checkbox]').prop('checked', $(obj).prop('checked')); } if(tmp_co_chbxs.length==tmp_co_chbxs.filter(':checked').length) tmp_coh.find('input[type=checkbox]:visible').prop('checked', true).prop('indeterminate', false); else if(tmp_co_chbxs.filter(':checked').length==0 && tmp_co_chbxs.filter(function(){return this.indeterminate==true}).length==0) tmp_coh.find('input[type=checkbox]:visible').prop('checked', false).prop('indeterminate', false); else tmp_coh.find('input[type=checkbox]:visible').prop('indeterminate', true).prop('checked', false); if(returnChecked) return dataGetChecked(resourceListSelector); } function groupChBoxClick(obj, resourceListSelector, headerSelector, collectionSelector, groupSelector, returnChecked) { var tmp_cg=$(obj).closest(groupSelector); var tmp_cg_chbxs=tmp_cg.find('input[type=checkbox]:visible'); var tmp_co_chbxs=tmp_cg.prev().find('input[type=checkbox]:visible'); if(tmp_cg_chbxs.filter(':checked').length==0) tmp_co_chbxs.prop('checked', false).prop('indeterminate', false); else tmp_co_chbxs.prop('indeterminate', true).prop('checked', false); return collectionChBoxClick(tmp_co_chbxs, resourceListSelector, headerSelector, collectionSelector, null, returnChecked); } function loadResourceChBoxClick(obj, resourceListSelector, headerSelector, collectionSelector, resourceItemSelector) { if(collectionSelector.match('_item$')) { var firstCollection=$(obj).parent().nextUntil(headerSelector).first(); if($(obj).prop('checked')) $(obj).parent().nextUntil(headerSelector).addBack().removeClass('unloaded'); else $(obj).parent().nextUntil(headerSelector).addBack().addClass('unloaded'); } else { var firstCollection=$(obj).parent().nextUntil(headerSelector).first().find(collectionSelector); if($(obj).prop('checked')) { $(obj).parent().nextUntil(headerSelector).find(collectionSelector).removeClass('unloaded'); $(obj).parent().removeClass('unloaded'); } else { $(obj).parent().nextUntil(headerSelector).find(collectionSelector).addClass('unloaded'); $(obj).parent().addClass('unloaded'); } } $(resourceListSelector).find(headerSelector).find('.unloadCheckHeader:checked').prop('disabled',false); $(resourceListSelector).find(collectionSelector).find('.unloadCheck:checked').prop('disabled',false); if(!$(resourceListSelector).find(headerSelector).find('.unloadCheckHeader').filter(function(){return $(this).prop('checked') || $(this).prop('indeterminate');}).length) { $(obj).prop({'checked':false,'indeterminate':true}); $(obj).parent().removeClass('unloaded'); $(obj).parent().nextUntil(headerSelector).find('.unloadCheck').prop({'checked':false,'indeterminate':false}); firstCollection.removeClass('unloaded').find('.unloadCheck').prop({'checked':true,'indeterminate':false,'disabled':true}); } else { $(obj).parent().nextUntil(headerSelector).find('.unloadCheck').prop({'checked':$(obj).prop('checked'),'indeterminate':false}); var checkedCollections=$(resourceListSelector).find(collectionSelector).find('.unloadCheck:checked'); if(checkedCollections.length==1) { var collection=checkedCollections.parents(resourceItemSelector); if(!collection.prev().hasClass(resourceItemSelector.slice(1)) && !collection.next().hasClass(resourceItemSelector.slice(1))) collection.prev().find('.unloadCheckHeader').prop('disabled',true); checkedCollections.prop('disabled',true); } } } function loadCollectionChBoxClick(obj, resourceListSelector, headerSelector, collectionSelector, resourceItemSelector) { if($(obj).prop('checked')) $(obj).parent().removeClass('unloaded'); else $(obj).parent().addClass('unloaded'); var checkedCollections=$(resourceListSelector).find(collectionSelector).find('.unloadCheck:checked'); if(checkedCollections.length==1) { var collection=checkedCollections.parents(resourceItemSelector); if(!collection.prev().hasClass(resourceItemSelector.slice(1)) && !collection.next().hasClass(resourceItemSelector.slice(1))) collection.prev().find('.unloadCheckHeader').prop('disabled',true); checkedCollections.prop('disabled',true); } else { $(resourceListSelector).find(headerSelector).find('.unloadCheckHeader:checked').prop('disabled',false); checkedCollections.prop('disabled',false); } if(collectionSelector.match('_item$')) { var tmp_coh=$(obj).parent().prevAll(headerSelector).first(); var tmp_co_chbxs=tmp_coh.nextUntil(headerSelector).find('.unloadCheck'); } else { var tmp_coh=$(obj).parent().parent().prevAll(headerSelector).first(); var tmp_co_chbxs=tmp_coh.nextUntil(headerSelector).find(collectionSelector).find('.unloadCheck'); } if(tmp_co_chbxs.length==tmp_co_chbxs.filter(':checked').length) tmp_coh.removeClass('unloaded').find('.unloadCheckHeader').prop('checked', true).prop('indeterminate', false); else if(tmp_co_chbxs.filter(':checked').length==0 && tmp_co_chbxs.filter(function(){return this.indeterminate==true}).length==0) tmp_coh.addClass('unloaded').find('.unloadCheckHeader').prop('checked', false).prop('indeterminate', false); else tmp_coh.removeClass('unloaded').find('.unloadCheckHeader').prop('indeterminate', true).prop('checked', false); } // Escape vCalendar value - RFC2426 (Section 2.4.2) function vcalendarEscapeValue(inputValue) { return (inputValue==undefined ? '' : inputValue).replace(vCalendar.pre['escapeRex'],"\\$1").replace(vCalendar.pre['escapeRex2'],'\\n'); } // Unescape vCalendar value - RFC2426 (Section 2.4.2) function vcalendarUnescapeValue(inputValue) { var outputValue=''; if(inputValue!=undefined) { for(var i=0;i<inputValue.length;i++) if(inputValue[i]=='\\' && i+1<inputValue.length) { if(inputValue[++i]=='n') outputValue+='\n'; else outputValue+=inputValue[i]; } else outputValue+=inputValue[i]; } return outputValue; } // Split parameters and remove double quotes from values (if parameter values are quoted) function vcalendarSplitParam(inputValue) { var result=vcalendarSplitValue(inputValue, ';'); var index; for(var i=0;i<result.length;i++) { index=result[i].indexOf('='); if(index!=-1 && index+1<result[i].length && result[i][index+1]=='"' && result[i][result[i].length-1]=='"') result[i]=result[i].substring(0,index+1)+result[i].substring(index+2,result[i].length-1); } return result; } // Split string by separator (but not '\' escaped separator) function vcalendarSplitValue(inputValue, inputDelimiter) { var outputArray=new Array(); var i=0; var j=0; for(i=0;i<inputValue.length;i++) { if(inputValue[i]==inputDelimiter) { if(outputArray[j]==undefined) outputArray[j]=''; ++j; continue; } outputArray[j]=(outputArray[j]==undefined ? '' : outputArray[j])+inputValue[i]; if(inputValue[i]=='\\' && i+1<inputValue.length) outputArray[j]=outputArray[j]+inputValue[++i]; } return outputArray; } function dateFormatJqToFc(input) { return input.replaceAll('DD','dddd').replaceAll('D','ddd').replace(/(MM|M)/g, '$1MM').replaceAll('m','M').replace(/y/g,'yy'); }