/* CardDavMATE - the open source CardDAV Web Client Copyright (C) 2011-2015 Jan Mate Andrej Lezo Matej Mihalik 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 . */ // 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=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 vCard value - RFC2426 (Section 2.4.2) function vcardEscapeValue(inputValue) { return (inputValue==undefined ? '' : inputValue).replace(/(,|;|\\)/g,"\\$1").replace(/\n/g,'\\n'); } // Unescape vCard value - RFC2426 (Section 2.4.2) function vcardUnescapeValue(inputValue) { var outputValue=''; if(inputValue!=undefined) { for(var i=0;i!$_:': RegExp('^(?::_\\$!!\\$_:|other)$') }; dataTypes['address_type_store_as']={ '_$!!$_':'_$!!$_' }; dataTypes['phone_type']={ 'work': RegExp('^(?:voice,)?work$'), 'home': RegExp('^home(?:,voice)?$'), 'cell': RegExp('^cell(?:,voice)?$'), 'cell,work': RegExp('^cell(?:,voice)?,work$'), 'cell,home': RegExp('^cell,home(?:,voice)?$'), 'main': RegExp('^main(?:,voice)?$'), 'pager': RegExp('^pager$'), 'fax': RegExp('^fax$'), 'fax,work': RegExp('^fax,work$'), 'fax,home': RegExp('^fax,home$'), 'iphone': RegExp('^(?::_\\$!!\\$_:|(?:cell,)?iphone(?:,voice)?)$'), 'other': RegExp('^(?::_\\$!!\\$_:|other)(?:,voice)?$') }; dataTypes['phone_type_store_as']={ '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_' }; dataTypes['email_type']={ 'internet,work': RegExp('^internet,work$'), 'home,internet': RegExp('^home,internet$'), ':mobileme:,internet': RegExp('^(?::mobileme:,internet|internet,mobileme)$'), ':_$!!$_:,internet': RegExp('^(?::_\\$!!\\$_:,internet|internet,other)$') }; dataTypes['email_type_store_as']={ '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_' }; dataTypes['url_type']={ 'work': RegExp('^work$'), 'home': RegExp('^home$'), ':_$!!$_:': RegExp('^(?::_\\$!!\\$_:|homepage)$'), ':_$!!$_:': RegExp('^(?::_\\$!!\\$_:|other)$') }; dataTypes['url_type_store_as']={ '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_' }; dataTypes['date_type']={ ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$') }; dataTypes['date_store_as']={ '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_' }; dataTypes['person_type']={ ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$'), ':_$!!$_:': RegExp('^:_\\$!!\\$_:$') }; dataTypes['person_type_store_as']={ '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_' }; dataTypes['im_type']={ 'work': RegExp('^work$'), 'home': RegExp('^home$'), ':mobileme:': RegExp('^(?::mobileme:|mobileme)$'), ':_$!!$_:': RegExp('^(?::_\\$!!\\$_:|other)$') }; dataTypes['im_type_store_as']={ '_$!!$_':'_$!!$_', '_$!!$_':'_$!!$_' }; dataTypes['im_service_type_store_as']={ 'aim':'AIM', 'icq':'ICQ', 'irc':'IRC', 'jabber':'Jabber', 'msn':'MSN', 'yahoo':'Yahoo', 'facebook':'Facebook', 'gadugadu':'GaduGadu', 'googletalk':'GoogleTalk', 'qq':'QQ', 'skype':'Skype' }; dataTypes['profile_type']={ 'twitter': RegExp('^twitter$'), 'facebook': RegExp('^facebook$'), 'flickr': RegExp('^flickr$'), 'linkedin': RegExp('^linkedin$'), 'myspace': RegExp('^myspace$'), 'sinaweibo': RegExp('^sinaweibo$') }; dataTypes['profile_type_store_as']={};