/* 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 . */ // AddressbookList Class function AddressbookList() { this.contacts=new Array(); this.contacts_hash=new Object(); this.contacts_hash_uidattr=new Object(); this.companies=new Array(); this.companies_hash=new Object(); this.companies_hash_uidattr=new Object(); this.vcard_groups=new Object(); this.contact_categories=new Object(); this.contact_companies=new Object(); this.contactLoaded=null; this.contactToReload=null; this.vcardGroupLoaded=null; this.reset=function() { this.contacts.splice(0,this.contacts.length); this.contacts_hash=new Object(); this.contacts_hash_uidattr=new Object(); this.companies.splice(0,this.companies.length); this.companies_hash=new Object(); this.companies_hash_uidattr=new Object(); this.vcard_groups=new Object(); // these are not removed from the interface (it's OK) this.contact_categories=new Object(); this.contact_companies=new Object(); this.contactLoaded=null; this.contactToReload=null; this.vcardGroupLoaded=null; }; this.getNewUID=function() { // we count with uniqueness of generated hash string var newUID=null; newUID=generateUID(); return newUID; }; this.getLoadedContactUID=function() { if(this.contactLoaded!=null) return this.contactLoaded.uid; else return ''; }; this.getSortKey=function(inputContact, inputSettings, inputMode) // inputMode (0=sort, 1=display) { var vcard_element=('\r\n'+inputContact.vcard).match(vCard.pre['contentline_N']); if(vcard_element===null || vcard_element.length!==1) // if the N attribute is not present exactly once, vCard is considered invalid return false; var sortKeyCompanyPart=''; if(typeof (getCRMSortKey)== 'function' && inputMode==0) { sortKeyCompanyPart=getCRMSortKey(inputContact); if(inputContact.isCompany!=undefined && inputContact.isCompany) return sortKeyCompanyPart; // for company contact we can return here } else if(typeof globalGroupContactsByCompanies!='undefined' && globalGroupContactsByCompanies==true) { var sortKeyCompanyPart='\u0009'; var vcard_orgname=('\r\n'+inputContact.vcard).match(vCard.pre['contentline_ORG']); if(vcard_orgname!=null && vcard_orgname.length>0) // if more than one ORG is present, use the first one { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" var parsed=vcard_orgname[0].match(vCard.pre['contentline_parse']); var parsed_value=vcardSplitValue(parsed[4], ';'); sortKeyCompanyPart=parsed_value[0]+'\u0009'+(parsed_value[1]!=undefined ? parsed_value[1] : '')+'\u0009'; if(inputMode==0 && inputContact.isCompany!=undefined && inputContact.isCompany) return sortKeyCompanyPart; // for company contact we can return here } } var tmp = []; var isGroup = this.isContactGroup(inputContact.vcard); /* backward compatibility for stupid users (remove it in future) */ if(typeof inputSettings==='string') tmp = inputSettings.replace(RegExp(',','g'), ', ').split(','); else if($.isArray(inputSettings)) /* new configuration options (arrays) */ tmp = inputSettings.slice(); // copy the configuration array // display settings for non-group contacts need some flattening if(inputMode===1 && !isGroup) { tmp = $.map(tmp, function(el) { if($.isPlainObject(el.value)) { return el.value; } else { return [el.value]; } }); } // now flatten the array completely to a company / personal version tmp = $.map(tmp, function(el) { if($.isPlainObject(el)) { if(inputContact.isCompany && el.hasOwnProperty('company')) { return [el.company]; } else if(!inputContact.isCompany && el.hasOwnProperty('personal')) { return [el.personal]; } return []; } return [el]; }); for(var i=0; i"group.", [2]->"name", [3]->";param;param", [4]->"value" var parsed=vcard_element2[0].match(vCard.pre['contentline_parse']); var sort_value=parsed[4]; } } return (inputMode===0 ? sortKeyCompanyPart+sort_value : sort_value); }; this.isContactGroup=function(inputVcard) { var vcard_element=null; if((vcard_element=('\r\n'+inputVcard).match(vCard.pre['X-ADDRESSBOOKSERVER-KIND']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" var parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(parsed[4].toLowerCase()=='group') return true; } return false; }; this.getMyContactGroups=function(inputUid) { if(this.contacts_hash[inputUid]!=undefined) { var myContactGroups=new Array(); if((vcard_element=this.contacts_hash[inputUid].vcard.match(vCard.pre['contentline_UID']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); for(var j=0;j"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); for(var j=0;j"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); var changedContactGroups=new Array(); for(var j=0;j0) return false; else globalAddressbookList.applyABFilter(groupChBoxClick(this, \'#ResourceCardDAVList\', \'.resourceCardDAV_header\', \'.resourceCardDAV\', \'.contact_group\', true), false);'}); newElement.append(vcardUnescapeValue(inputContact.displayvalue)); newElement.css('display',''); if($('#ResourceCardDAVList').find('[data-id="'+jqueryEscapeSelector(inputContact.uid.replace(RegExp('/[^/]*$',''),'/'))+'"]').next('.contact_group').find('[data-id="'+jqueryEscapeSelector(inputContact.uid)+'"]').length==0) $('#ResourceCardDAVList').find('[data-id="'+jqueryEscapeSelector(inputContact.uid.replace(RegExp('/[^/]*$',''),'/'))+'"]').next('.contact_group').children().eq(insertIndex).after(newElement); // make the area droppable if the collection is not read-only if(globalResourceCardDAVList.getCollectionPrivByUID(inputContact.uid.replace(RegExp('[^/]*$',''),''))==false && (typeof globalDisableDragAndDrop=='undefined' || globalDisableDragAndDrop!=true)) $('#ResourceCardDAVList').find('[data-id="'+jqueryEscapeSelector(inputContact.uid.replace(RegExp('[^/]*$',''),''))+'"]').parent().find('.contact_group').children().eq(insertIndex+1).droppable({ accept: '.ablist_item', tolerance: 'pointer', hoverClass: 'group_dropped_to', drop: function(event, ui){ // animate the clone of the dropped (draggable) element var tmp=ui.helper.clone(); tmp.appendTo('body') .animate({opacity: 0, color: 'transparent', height: 0, width: 0, fontSize: 0, lineHeight: 0, paddingLeft: 0, paddingRight: 0},750,function(){tmp.remove()}); // disallow to drag the original dropped element until the processing is finished ui.draggable.draggable('option', 'disabled', true); // animate the original dropped element ui.draggable.animate({opacity: 0.3}, 750); // disallow to drop any new element until the processing is finished $(this).droppable('option', 'disabled', true); // show the loader icon $(this).addClass('r_operate'); var tmp2=globalAddressbookList.getContactByUID(ui.draggable.attr('data-id')); tmp2.addToContactGroupUID=''; tmp2.removeToContactGroupUID=new Array(); tmp2.addToContactGroupUID=$(this).attr('data-id'); tmp2.uiObjects={contact: ui.draggable, resource: $(this).attr('data-id')}; lockAndPerformToCollection(tmp2, globalRefAddContact.attr('data-filter-url'), 'ADD_TO_GROUP'); } }); // if no new makeActive but forceReload is true then reload the current contact group if(makeActive==null && forceReload==true) makeActive=globalRefAddContact.attr('data-filter-url'); // load the contact group if it was selected if(makeActive!=null) { $('#ResourceCardDAVList').find('.resourceCardDAV_item').find('.resourceCardDAV_selected').removeClass('resourceCardDAV_selected'); $('#ResourceCardDAVList').find('[data-id='+jqueryEscapeSelector(makeActive.replace(RegExp('[^/]*$',''),''))+']').addClass('resourceCardDAV_selected'); $('#ResourceCardDAVList').find('[data-id='+jqueryEscapeSelector(makeActive)+']').addClass('resourceCardDAV_selected'); } if(makeChecked!=null) { $('#ResourceCardDAVList').find('[data-id='+jqueryEscapeSelector(makeChecked)+']').find('input[type=checkbox]').prop('checked',true); this.applyABFilter(dataGetChecked('#ResourceCardDAVList'), false); } }; this.removeContactGroup=function(inputUid, loadNext) { for(var i=this.vcard_groups[inputUid.replace(RegExp('/[^/]*$',''),'/')].length-1;i>=0;i--) if(this.vcard_groups[inputUid.replace(RegExp('/[^/]*$',''),'/')][i].uid==inputUid) { var uidRemoved=this.vcard_groups[inputUid.replace(RegExp('/[^/]*$',''),'/')][i].uid; var item=$('#ResourceCardDAVList').find('[data-id^="'+jqueryEscapeSelector(this.vcard_groups[inputUid.replace(RegExp('/[^/]*$',''),'/')][i].uid)+'"]'); // remove the item item.remove(); this.vcard_groups[inputUid.replace(RegExp('/[^/]*$',''),'/')].splice(i,1); // vcardGroupLoaded bolo zrusene, pozriet co s tym if(loadNext && this.vcardGroupLoaded!=null && this.vcardGroupLoaded.uid==inputUid) { this.vcardGroupLoaded=null; // set the whole collection as active var tmp=uidRemoved.match(RegExp('(^.*/)'),''); // XXX it is no longer needed // globalResourceCardDAVList.loadAddressbookByUID(tmp[1]); } break; } }; // hide/show contacts in the interface according to contactGroupOrResourceUid or search filter in the interface (contactGroupOrResourceUid==false) this.applyABFilter=function(contactGroupOrResourceUid, inputForceLoadNext) { if(globalCardDAVInitLoad) return false; // XXX docasne, potom dame prec if(!(contactGroupOrResourceUid instanceof Array)) return false; var vcardGroupOrCollection=[]; for(var i=0;i"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); vcardUIDList[vcardUIDList.length]=parsed[4].replace('urn:uuid:',''); // remove the processed parameter vcard=vcard.replace(vcard_element[0],'\r\n'); } // update the contacts' "show" attribute for(var j=0;j"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(vcardUIDList[j]==parsed[4] && this.contacts[k].search_hide==false) { this.contacts[k].show=true; this.contacts_hash[this.contacts[k].uid].show=true } } } } } var lastActive=null; var prevHeader=null; var lastContactForHeader=this.contacts.length-1; // performance var tmpListRefChildren=globalRefABListTable.children(); // init displayed columns text length cache var columnLengths = []; for(var i=0; i=0;i--) { if(this.contacts[i].headerOnly==undefined) { // find the previous header index for(var j=i-1;j>=0;j--) if(this.contacts[j].headerOnly!=undefined && this.contacts[j].headerOnly==true) { prevHeader=j; break; } // performance var tmpListRefChildren_i=tmpListRefChildren.eq(i); var tmpListRefChildren_prev=tmpListRefChildren.eq(prevHeader); var coll_tmp=this.contacts[i].uid.match(RegExp('^(https?://)([^@/]+(?:@[^@/]+)?)@([^/]+)(.*/)([^/]+/)([^/]*)','i')); var collection_uid=coll_tmp[1]+coll_tmp[2]+'@'+coll_tmp[3]+coll_tmp[4]+coll_tmp[5]; var coll_color=globalResourceCardDAVList.getCollectionByUID(collection_uid).color; this.contacts[i].color = coll_color; tmpListRefChildren_i.find('.ablist_item_color').css('background-color', coll_color); switch(this.contacts[i].show) { case false: tmpListRefChildren_i.css('display','none'); if(tmpListRefChildren_i.hasClass('ablist_item_selected')) lastActive=i; var hideHeader=true; for(j=prevHeader+1;j<=lastContactForHeader;j++) if(this.contacts[j].show==true) { hideHeader=false; break; } if(hideHeader) tmpListRefChildren_prev.css('display','none'); break; case true: // set the contact header to visible tmpListRefChildren_prev.css('display',''); // set the contact to visible tmpListRefChildren_i.css('display',''); // save column text length into cache tmpListRefChildren_i.children().slice(globalFixedContactDataColumnsCount).each(function(ind) { columnLengths[ind].push($(this).text().length); }); break; default: break; } } else lastContactForHeader=i-1; } setDataColumnsWidth(columnLengths); // the previously loaded contact is hidden or not exists we need to select a new one if(inputForceLoadNext==true || $('#vCardEditor').attr('data-editor-state')!='edit' && (lastActive!=null || globalRefABListTable.children('.ablist_item_selected').length==0)) { var nextCandidateToLoad=null; // get the nearest candidate to load // if we can go forward if(this.contactToReload!=null) nextCandidateToLoad=this.contactToReload; else { for(j=(previousActiveIndex==null ? 0 : previousActiveIndex);j=0;j--) if((this.contacts[j].headerOnly==undefined || this.contacts[j].headerOnly==false) && (this.contacts[j].show==true)) { nextCandidateToLoad=this.contacts[j]; break; } } } // make the contact active globalRefABListTable.children('.ablist_item.ablist_item_selected').removeClass('ablist_item_selected'); if(nextCandidateToLoad!=null) { // prevent re-loading the contact if it is already loaded if((this.contactToReload!=null||$('#vCardEditor').attr('data-url')!=nextCandidateToLoad.uid) && !globalCardDAVInitLoad) { this.loadContactByUID(nextCandidateToLoad.uid); } else // because the collection click unselects the active contact we need to re-select it { // Make the selected contact active globalRefABListTable.children('.ablist_item.ablist_item_selected').removeClass('ablist_item_selected'); globalRefABListTable.children('[data-id='+jqueryEscapeSelector(nextCandidateToLoad.uid)+']').addClass('ablist_item_selected'); } // move scrollbar to ensure that the contact is visible in the interface if((selected_contact=globalRefABListTable.children('.ablist_item_selected')).length==1) globalRefABList.scrollTop(globalRefABList.scrollTop()+selected_contact.offset().top-globalRefABList.offset().top-globalRefABList.height()*globalKBNavigationPaddingRate); } else { this.contactLoaded=null; $('#ABContactColor').css('background-color', ''); $('#ABContact').html(''); } } if(this.contactToReload!=null&& (selected_contact=globalRefABListTable.find('[data-id="'+this.contactToReload.uid+'"]')).length==1) { selected_contact.addClass('ablist_item_selected'); globalRefABList.scrollTop(globalRefABList.scrollTop()+selected_contact.offset().top-globalRefABList.offset().top-globalRefABList.height()*globalKBNavigationPaddingRate); } } this.getABCategories=function(returnSorted) { var categoriesArr=[]; for(var category in this.contact_categories) categoriesArr.push(category); if(returnSorted) return categoriesArr.sort(function(x,y){return x.customCompare(y,globalSortAlphabet,1,false)}); else return categoriesArr; } this.getABCompanies=function(returnSorted) { var companiesArr=[]; for(var company in this.contact_companies) companiesArr.push(company); if(returnSorted) return companiesArr.sort(function(x,y){return x.customCompare(y,globalSortAlphabet,1,false)}); else return companiesArr; } this.getABCompanyDepartments=function(inputCompany) { var departmentsArr=[]; if(this.contact_companies[inputCompany]!=undefined) departmentsArr=this.contact_companies[inputCompany].departments.slice(); return departmentsArr.sort(function(x,y){return x.customCompare(y,globalSortAlphabet,1,false)}); } // Contact list is not sorted, instead "insert sort" is performed this.insertContact=function(inputContact, forceReload, disableDOM) { // Apple "group" vCards if(this.isContactGroup(inputContact.vcard)) return this.insertContactGroup(inputContact, forceReload, false); // check for company contact inputContact.isCompany=false; var vcard_element=inputContact.vcard.match(vCard.pre['X-ABShowAs']); if(vcard_element!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(vcardUnescapeValue(parsed[4]).match(RegExp('^company$','i'))) inputContact.isCompany=true; } // check for company contact if((typeof globalContactsExtVcardToData)=='function') { inputContact.isLegacy=false; var vcard_element=inputContact.vcard.match(RegExp('\r\nX-IsLegacy:.*\r\n', 'mi')); if(vcard_element!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" var parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(vcardUnescapeValue(parsed[4]).match(RegExp('^(?:yes|1|true)$', 'i'))) inputContact.isLegacy=true; } } // contact UID attr var vcard_element=inputContact.vcard.match(vCard.pre['contentline_UID']); if(vcard_element!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); inputContact.uidattr=vcardUnescapeValue(parsed[4]); } else // UID attr is REQUIRED return false; // invalud vcard var this_destination=this.contacts; var this_destination_hash=this.contacts_hash; var this_destination_hash_uidattr=this.contacts_hash_uidattr; // search plugin requirement inputContact.search_hide=false; // CATEGORIES suggestion var categoriesArr=(inputContact.categories=='' ? [] : vcardSplitValue(inputContact.categories,',')); var allCategoriesArr=this.getABCategories(false); // The search funcionality uses this ASCII value (you can add additional data here) // ORG attribute var tmp=inputContact.vcard; var orgArr=[]; var depArr=[]; var tmpCurrentCompany=''; var tmpCurrentDepartment=''; while((vcard_element=tmp.match(vCard.pre['contentline_ORG']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" var parsed=vcard_element[0].match(vCard.pre['contentline_parse']); var parsed_valArr=vcardSplitValue(parsed[4], ';'); if(isDataColumnDefined('COMPANY')) { setContactDataColumn(inputContact, 'COMPANY', vcardUnescapeValue(parsed_valArr[0])); } if(isDataColumnDefined('DEPARTMENT')) { setContactDataColumn(inputContact, 'DEPARTMENT', vcardUnescapeValue(parsed_valArr[1])); } tmpCurrentCompany=(parsed_valArr[0]==undefined || parsed_valArr[0]=='' ? '' : parsed_valArr[0]); tmpCurrentDepartment=(parsed_valArr[1]==undefined || parsed_valArr[1]=='' ? '' : parsed_valArr[1]); if(tmpCurrentCompany!='') orgArr[orgArr.length]=vcardUnescapeValue(tmpCurrentCompany); if(tmpCurrentDepartment) depArr[depArr.length]=vcardUnescapeValue(tmpCurrentDepartment); // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } var allOrgArr=this.getABCompanies(false); // N attribute while((vcard_element=tmp.match(vCard.pre['contentline_N']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" var parsed=vcard_element[0].match(vCard.pre['contentline_parse']); var parsed_valArr=vcardSplitValue(parsed[4],';'); if(isDataColumnDefined('LASTNAME')) { setContactDataColumn(inputContact, 'LASTNAME', vcardUnescapeValue(parsed_valArr[0])); } if(isDataColumnDefined('FIRSTNAME')) { setContactDataColumn(inputContact, 'FIRSTNAME', vcardUnescapeValue(parsed_valArr[1])); } if(isDataColumnDefined('MIDDLENAME')) { setContactDataColumn(inputContact, 'MIDDLENAME', vcardUnescapeValue(parsed_valArr[2])); } if(isDataColumnDefined('PREFIX')) { setContactDataColumn(inputContact, 'PREFIX', vcardUnescapeValue(parsed_valArr[3])); } if(isDataColumnDefined('SUFFIX')) { setContactDataColumn(inputContact, 'SUFFIX', vcardUnescapeValue(parsed_valArr[4])); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // NICKNAME attribute while((vcard_element=tmp.match(vCard.pre['contentline_NICKNAME']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('NICKNAME')) { setContactDataColumn(inputContact, 'NICKNAME', parsed[4]); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // X-PHONETIC-LAST-NAME attribute while((vcard_element=tmp.match(vCard.pre['contentline_X-PHONETIC-LAST-NAME']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('PHONETICLASTNAME')) { setContactDataColumn(inputContact, 'PHONETICLASTNAME', parsed[4]); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // X-PHONETIC-FIRST-NAME attribute while((vcard_element=tmp.match(vCard.pre['contentline_X-PHONETIC-FIRST-NAME']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('PHONETICFIRSTNAME')) { setContactDataColumn(inputContact, 'PHONETICFIRSTNAME', parsed[4]); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // BDAY attribute while((vcard_element=tmp.match(vCard.pre['contentline_BDAY']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('BIRTHDAY')) { var bday = null; try { bday = $.datepicker.parseDate('yy-mm-dd', parsed[4]); } catch(e) { } if(bday) { setContactDataColumn(inputContact, 'BIRTHDAY', $.datepicker.formatDate(globalSettings.datepickerformat.value, bday)); } } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // TITLE attribute while((vcard_element=tmp.match(vCard.pre['contentline_TITLE']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('JOBTITLE')) { setContactDataColumn(inputContact, 'JOBTITLE', vcardUnescapeValue(parsed[4])); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // NOTE attribute while((vcard_element=tmp.match(vCard.pre['contentline_NOTE']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('NOTETEXT')) { setContactDataColumn(inputContact, 'NOTETEXT', vcardUnescapeValue(parsed[4])); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // ADR attribute while((vcard_element=tmp.match(vCard.pre['contentline_ADR']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" var parsed=vcard_element[0].match(vCard.pre['contentline_parse']); var parsed_valArr=vcardSplitValue(parsed[4],';'); if(isDataColumnDefined('ADDRESS')) { var unescapedArr = $.map(parsed_valArr, function(el) { if(el) { return vcardUnescapeValue(el); } }); setContactDataColumn(inputContact, 'ADDRESS', unescapedArr.join(' '), {'TYPE': getParamsFromContentlineParse(tmp, parsed, 'TYPE', 'X-ABLabel', 'address_type_store_as')}); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // TEL attribute while((vcard_element=tmp.match(vCard.pre['contentline_TEL']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('PHONE')) { setContactDataColumn(inputContact, 'PHONE', parsed[4], {'TYPE': getParamsFromContentlineParse(tmp, parsed, 'TYPE', 'X-ABLabel', 'phone_type_store_as')}); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // EMAIL attribute while((vcard_element=tmp.match(vCard.pre['contentline_EMAIL']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('EMAIL')) { setContactDataColumn(inputContact, 'EMAIL', parsed[4], {'TYPE': getParamsFromContentlineParse(tmp, parsed, 'TYPE', 'X-ABLabel', 'email_type_store_as')}); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // URL attribute while((vcard_element=tmp.match(vCard.pre['contentline_URL']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('URL')) { setContactDataColumn(inputContact, 'URL', parsed[4], {'TYPE': getParamsFromContentlineParse(tmp, parsed, 'TYPE', 'X-ABLabel', 'url_type_store_as')}); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // X-ABDATE attribute while((vcard_element=tmp.match(vCard.pre['contentline_X-ABDATE']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('DATES')) { var abdate = null; try { abdate = $.datepicker.parseDate('yy-mm-dd', parsed[4]); } catch(e) { } if(abdate) { setContactDataColumn(inputContact, 'DATES', $.datepicker.formatDate(globalSettings.datepickerformat.value, abdate), {'TYPE': getParamsFromContentlineParse(tmp, parsed, 'TYPE', 'X-ABLabel', 'date_store_as')}); } } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // X-ABRELATEDNAMES attribute while((vcard_element=tmp.match(vCard.pre['contentline_X-ABRELATEDNAMES']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('RELATED')) { setContactDataColumn(inputContact, 'RELATED', parsed[4], {'TYPE': getParamsFromContentlineParse(tmp, parsed, 'TYPE', 'X-ABLabel', 'person_type_store_as')}); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // X-SOCIALPROFILE attribute while((vcard_element=tmp.match(vCard.pre['contentline_X-SOCIALPROFILE']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('PROFILE')) { setContactDataColumn(inputContact, 'PROFILE', getParamsFromContentlineParse(tmp, parsed, 'X-USER', null, null, true)[0], {'TYPE': getParamsFromContentlineParse(tmp, parsed, 'TYPE', 'X-ABLabel', 'profile_type_store_as')}); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // IMPP attribute while((vcard_element=tmp.match(vCard.pre['contentline_IMPP']))!=null) { // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); if(isDataColumnDefined('IM')) { setContactDataColumn(inputContact, 'IM', parsed[4].replace(vCard.pre['vcardToData_before_val'], ''), { 'TYPE': getParamsFromContentlineParse(tmp, parsed, 'TYPE', 'X-ABLabel', 'im_type_store_as'), 'SERVICE-TYPE': getParamsFromContentlineParse(tmp, parsed, 'X-SERVICE-TYPE', null, 'im_service_type_store_as') }); } // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } // CATEGORIES attribute (preparsed) if(isDataColumnDefined('CATEGORIES')) { setContactDataColumn(inputContact, 'CATEGORIES', inputContact.categories.splitCustom(',')); } if((inputContact.sortkey=this.getSortKey(inputContact, globalSettings.collectionsort.value || $.map(globalSettings.collectiondisplay.value, function(el) {if($.isPlainObject(el.value)) {return el.value;} else {return [el.value];}}), 0))===false || (inputContact.displayvalue=this.getSortKey(inputContact, globalSettings.collectiondisplay.value, 1))===false) return false; //invalid vcard // if company headers are used add also the header to the searchvalue var companyHeader=''; if(typeof globalGroupContactsByCompanies!='undefined' && globalGroupContactsByCompanies==true) { if(tmpCurrentCompany!='' || tmpCurrentDepartment!='') { if(typeof (getCRMSortKey)=='function') companyHeader=getCRMSortKey(inputContact); else companyHeader=tmpCurrentCompany+'\u0009'+tmpCurrentDepartment+'\u0009'; } } inputContact.searchvalue=(companyHeader+inputContact.displayvalue).multiReplace(globalSearchTransformAlphabet); // CATEGORIES suggestion for(var i=0;i90 && unicodeValue<97) || (unicodeValue>122 && unicodeValue<127)) { headerValue='#'; inputContact.sortkey='#'+inputContact.sortkey; } else headerValue=inputContact.sortkey.charAt(0).toUpperCase(); } else { headerValue='#'; inputContact.sortkey='#'; } headerSortKey=headerValue; } // create the header var headerObject={headerOnly: true, sortkey: headerSortKey, displayvalue: headerValue}; // find the index where to insert the new contact O(n*log(n)) insertIndex=0; low=0; high=this_destination.length-1; if(this_destination.length>0) while(low').text(getContactDataColumn(inputContact, columns[i])).appendTo(newElement); } newElement.click(function() { if($(this).hasClass('ablist_item_selected') || globalObjectLoading) return false; else globalAddressbookList.loadContactByUID(this.getAttribute('data-id')); }); // set the company icon if(inputContact.isCompany==true) newElement.addClass('company'); if(typeof globalDisableDragAndDrop=='undefined' || globalDisableDragAndDrop!=true) newElement.draggable({ delay: 250, revert: 'invalid', scroll: false, opacity: 0.8, stack: '#SystemCardDavMATE', containment: '#SystemCardDavMATE', appendTo: 'body', start: function( event, ui ){ // disallow on read-only collection if(globalResourceCardDAVList.getCollectionPrivByUID($(this).attr('data-id').replace(RegExp('[^/]*$'),''))==true) return false; }, helper: function(){ $('#ResourceCardDAVList').find('.resourceCardDAV.ui-droppable').droppable( 'option', 'accept', false); $('#ResourceCardDAVList').find('.group.ui-droppable').droppable( 'option', 'accept', false); $('#ResourceCardDAVList').find('.resourceCardDAV[data-id!='+jqueryEscapeSelector($(this).attr('data-id').replace(RegExp('[^/]+$'),''))+'].ui-droppable').droppable( 'option', 'accept', '.ablist_item'); var myContactGroups=globalAddressbookList.getMyContactGroups($(this).attr('data-id')); $('#ResourceCardDAVList').find('.group[data-id^='+jqueryEscapeSelector($(this).attr('data-id').replace(RegExp('[^/]+$'),''))+'].ui-droppable').each(function(index, element){ if(myContactGroups.indexOf($(element).attr('data-id'))==-1) $(element).droppable( 'option', 'accept', '.ablist_item'); }); var tmp=$(this).clone(); tmp.addClass('ablist_item_dragged'); // we cannot use .css() here, because we need to add !important (problem with Gecko based browsers) var tmp_style='max-width: '+$(this).outerWidth()+'px;'; if($(this).css('background-image')!='none') tmp_style+='background-image: url(images/company_s_w.svg) !important;'; tmp.attr('style', tmp_style); return tmp; } }); globalRefABListTable.children().eq(insertIndex+headerMiss-1).after(newElement); if($('#vCardEditor').attr('data-editor-state')=='edit') { if((selected_contact=globalRefABListTable.children('.ablist_item_selected')).length==1) globalRefABList.scrollTop(globalRefABList.scrollTop()+selected_contact.offset().top-globalRefABList.offset().top-globalRefABList.height()*globalKBNavigationPaddingRate); } // toto tu asi nahradit zavolanim trigger('click') co vyrazne sprehladni kod // => // load the updated contact (because we first deleted it, we need to set it active) if(makeActive!=null) { // make the contact active globalRefABListTable.children('.ablist_item.ablist_item_selected').removeClass('ablist_item_selected'); globalRefABListTable.children().eq(insertIndex+headerMiss).addClass('ablist_item_selected'); this.loadContactByUID(makeActive); } } } this.renderContacs=function() { var this_destination=this.contacts; var this_destination_hash=this.contacts_hash; var tmpResultObject=[]; for(var i=0;i').text(getContactDataColumn(this_destination[i], columns[j])).appendTo(newElement); } for(; j').appendTo(newElement); } newElement.click(function() { if($(this).hasClass('ablist_item_selected') || globalObjectLoading) return false; else globalAddressbookList.loadContactByUID(this.getAttribute('data-id')); }); // set the company icon if(this_destination[i].isCompany==true) newElement.addClass('company'); if(typeof globalDisableDragAndDrop=='undefined' || globalDisableDragAndDrop!=true) newElement.draggable({ delay: 250, revert: 'invalid', scroll: false, opacity: 0.8, stack: '#SystemCardDavMATE', containment: '#SystemCardDavMATE', appendTo: 'body', start: function( event, ui ){ // disallow on read-only collection if(globalResourceCardDAVList.getCollectionPrivByUID($(this).attr('data-id').replace(RegExp('[^/]*$'),''))==true) return false; }, helper: function(){ $('#ResourceCardDAVList').find('.resourceCardDAV.ui-droppable').droppable( 'option', 'accept', false); $('#ResourceCardDAVList').find('.group.ui-droppable').droppable( 'option', 'accept', false); $('#ResourceCardDAVList').find('.resourceCardDAV[data-id!='+jqueryEscapeSelector($(this).attr('data-id').replace(RegExp('[^/]+$'),''))+'].ui-droppable').droppable( 'option', 'accept', '.ablist_item'); var myContactGroups=globalAddressbookList.getMyContactGroups($(this).attr('data-id')); $('#ResourceCardDAVList').find('.group[data-id^='+jqueryEscapeSelector($(this).attr('data-id').replace(RegExp('[^/]+$'),''))+'].ui-droppable').each(function(index, element){ if(myContactGroups.indexOf($(element).attr('data-id'))==-1) $(element).droppable( 'option', 'accept', '.ablist_item'); }); var tmp=$(this).clone(); tmp.addClass('ablist_item_dragged'); // we cannot use .css() here, because we need to add !important (problem with Gecko based browsers) var tmp_style='max-width: '+$(this).outerWidth()+'px;'; if($(this).css('background-image')!='none') tmp_style+='background-image: url(images/company_s_w.svg) !important;'; tmp.attr('style', tmp_style); return tmp; } }); } tmpResultObject.push(newElement); } globalRefABListTable.empty().append(tmpResultObject); } this.removeContact=function(inputUid, loadNext, isFromPUT) { if(!(inputUid instanceof Array)) inputUid=[inputUid]; var tmpRex=new RegExp('/[^/]*$',''); // Apple "group" vCards for(var i=inputUid.length-1;i>=0;i--) for(var j=this.vcard_groups[inputUid[i].replace(tmpRex,'/')].length-1;j>=0;j--) if(inputUid.indexOf(this.vcard_groups[inputUid[i].replace(tmpRex,'/')][j].uid)!=-1) return this.removeContactGroup(inputUid[i], loadNext); for(var i=this.contacts.length-1;i>=0;i--) if(this.contacts[i]!=undefined&&inputUid.indexOf(this.contacts[i].uid)!=-1) { var inUID=this.contacts[i].uid; // CATEGORIES suggestion var categoriesArr=vcardSplitValue(this.contacts[i].categories,','); for(var j=0;j"group.", [2]->"name", [3]->";param;param", [4]->"value" parsed=vcard_element[0].match(vCard.pre['contentline_parse']); orgArr[orgArr.length]=vcardUnescapeValue(vcardSplitValue(parsed[4],';')[0]); // remove the processed parameter tmp=tmp.replace(vcard_element[0],'\r\n'); } for(var j=0;j=0;j--) if(this.contacts[j].headerOnly!=true && this.contacts[j].show==true) { nextCandidateToLoad=this.contacts[j]; break; } } // remove the item item.remove(); this.contacts.splice(i,1); if(this.contacts_hash[inUID]!=undefined) { delete this.contacts_hash_uidattr[this.contacts_hash[inUID].uidattr]; delete this.contacts_hash[inUID]; } else if(this.companies_hash[inUID]!=undefined) { delete this.companies_hash_uidattr[this.contacts_hash[inUID].uidattr]; delete this.companies_hash[inUID]; } // remove the header if there is no more contact var removeHeader=true; var prevHeader=null; // find the previous header index for(var j=i-1;j>=0;j--) if(this.contacts[j].headerOnly!=undefined && this.contacts[j].headerOnly==true) { prevHeader=j; break; } // check for contact existence for the found header if((prevHeader+1)=0;i--) if(this.contacts[i]!=undefined /* because the header can be deleted with the contact */ && this.contacts[i].timestamp!=undefined && this.contacts[i].uid.indexOf(inputUidBase)==0 && this.contacts[i].timestamp no animation */ globalObjectLoading=false; // re-enable keyboard navigation }); else { $('#ABContactColor').css('background-color', ''); $('#ABContact').empty(); globalDisableAnimationMessageHiding='contactRfcNotCompliant'; var tmpTime=show_editor_message('out','message_error', localization[globalInterfaceLanguage].contactRfcNotCompliant, globalHideInfoMessageAfter); setTimeout(function(){globalObjectLoading=false;}, tmpTime); // re-enable keyboard navigation } // Make the selected contact active globalRefABListTable.children('.ablist_item.ablist_item_selected').removeClass('ablist_item_selected'); globalRefABListTable.children('[data-id='+jqueryEscapeSelector(this.contacts_hash[inputUID].uid)+']').addClass('ablist_item_selected'); this.contactToReload=null; if(globalRefABListTable.children('[data-id='+jqueryEscapeSelector(this.contacts_hash[inputUID].uid)+']:visible').length>0&&$('#ABInMessageEditBox').css('display')!='none') { animate_message('#ABInMessageEditBox', '#ABInMessageTextEditBox', 0, '-='); $('#ABInMessageEditBox').css('display',''); } else if(globalRefABListTable.children('[data-id='+jqueryEscapeSelector(this.contacts_hash[inputUID].uid)+']:visible').length==0&&$('#ABInMessageEditBox').css('display')=='none') { this.contactToReload=this.contacts_hash[inputUID]; globalDisableAnimationMessageHiding='errContactHidden'; $('#ABInMessageEditBox').css('display','block'); $('#ABInMessageTextEditBox').attr('class','message_success'); $('#ABInMessageTextEditBox').text(localization[globalInterfaceLanguage][globalDisableAnimationMessageHiding]); animate_message('#ABInMessageEditBox', '#ABInMessageTextEditBox', globalHideInfoMessageAfter); } if($('#ResourceCardDAVListOverlay').is(':visible')) { if($('#ABContactOverlay').is(':visible')) { var animation = 400; var duration = globalHideInfoMessageAfter + 2*animation; setTimeout(function(){ $('#ResourceCardDAVListOverlay').fadeOut(animation); $('#ABListOverlay').fadeOut(animation,function(){}); $('#ABContactOverlay').fadeOut(animation,function(){globalRefAddContact.prop('disabled',false);}); },duration-animation); } else { $('#ResourceCardDAVListOverlay').fadeOut(globalEditorFadeAnimation); $('#ABListOverlay').fadeOut(globalEditorFadeAnimation,function(){}); } } } else { $('#ABContactColor').css('background-color', ''); $('#ABContact').empty(); // CardDAVeditor_cleanup(false, false); // editor initialization } checkContactFormScrollBar(); } this.loadContactByVcard=function(vcard, color, isCompany, inputEditorMode, inputEditorLockedEntries) { // sem callback pre index.html a v pripade ak pridavame usera (nie firmu) pridat do vcard prislusny atribut if(typeof(globalContactsExtLoadByVcardBefore)=='function') vcard=globalContactsExtLoadByVcardBefore(vcard, isCompany); var loadContact=new Object(); loadContact.vcard=vcard; loadContact.isCompany=isCompany; loadContact.color=color; globalObjectLoading=true; // temporary disable keyboard navigation if(vcardToData(loadContact, false /* XXX check this */, isCompany, inputEditorMode, inputEditorLockedEntries)) $('#EditorBox').fadeTo(0, 1, function(){ /* 0 => no animation */ // append the UID of previous contact into "data-id" for "cancel" functionality $('#vCardEditor').find('[data-type="cancel"]').attr('data-id', globalAddressbookList.getLoadedContactUID()); this.contactLoaded=null; // do not do this earlier globalObjectLoading=false; // re-enable keyboard navigation }); else { // todo: replace with icon or text in the editor div globalDisableAnimationMessageHiding='contactRfcNotCompliant'; show_editor_message('out', 'message_error', localization[globalInterfaceLanguage].contactRfcNotCompliant, globalHideInfoMessageAfter); this.contactLoaded=null; // do not do this earlier globalObjectLoading=false; // re-enable keyboard navigation } checkContactFormScrollBar(); } // DONE this.getContactByUID=function(inputUID) { // find the inputUID contact if(this.contacts_hash[inputUID]!=undefined) return this.contacts_hash[inputUID]; else return null; } // DONE this.getContactGroupByUID=function(inputUID) { var collectionUID=inputUID.replace(RegExp('[^/]*$'),''); for(var i=0;i