resource.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. /*
  2. CardDavMATE - the open source CardDAV Web Client
  3. Copyright (C) 2011-2015
  4. Jan Mate <jan.mate@inf-it.com>
  5. Andrej Lezo <andrej.lezo@inf-it.com>
  6. Matej Mihalik <matej.mihalik@inf-it.com>
  7. This program is free software: you can redistribute it and/or modify
  8. it under the terms of the GNU Affero General Public License as
  9. published by the Free Software Foundation, either version 3 of the
  10. License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Affero General Public License for more details.
  15. You should have received a copy of the GNU Affero General Public License
  16. along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. function handleCardDAVError(isError, inputResource)
  19. {
  20. var collections='';
  21. collections=globalResourceCardDAVList.collections;
  22. for(var i=0; i<collections.length;i++)
  23. {
  24. if(collections[i].uid!=undefined)
  25. {
  26. var tmp=collections[i].accountUID.match(RegExp('^(https?://)([^@/]+(?:@[^@/]+)?)@([^/]+)(.*/)','i'));
  27. var resource_href=tmp[1]+tmp[3]+tmp[4];
  28. var resource_user=tmp[2];
  29. if(inputResource.href==resource_href && inputResource.userAuth.userName==resource_user)
  30. {
  31. if(globalSettingsSaving =='addressbook' && isError)
  32. {
  33. var uidParts=(collections[i].uid).match(RegExp('^(https?://)([^@/]+(?:@[^@/]+)?)@(.*)'));
  34. var checkHref = uidParts[1]+uidParts[3];
  35. var isLoaded=false;
  36. if(typeof globalCrossServerSettingsURL!='undefined'&&globalCrossServerSettingsURL!=null&globalCrossServerSettingsURL)
  37. {
  38. var uidParts=(collections[i].uid).match(RegExp('/([^/]+/[^/]+/)$'));
  39. var tmpParts = uidParts[1].match('^(.*/)([^/]+)/$');
  40. var checkHref3=decodeURIComponent(tmpParts[1])+tmpParts[2]+'/';
  41. var found=false;
  42. for(var l=0;l<globalSettings.loadedaddressbookcollections.value.length;l++)
  43. {
  44. var tmpParts2 = globalSettings.loadedaddressbookcollections.value[l].match('^(.*/)([^/]+)/([^/]+)/$');
  45. var checkHref2=decodeURIComponent(tmpParts2[2])+'/'+tmpParts2[3]+'/';
  46. if(checkHref3==checkHref2)
  47. {
  48. found=true;
  49. break;
  50. }
  51. }
  52. isLoaded=found;
  53. }
  54. else
  55. isLoaded=globalSettings.loadedaddressbookcollections.value.indexOf(checkHref)!=-1;
  56. if(isLoaded && collections[i].oldSyncToken=='')
  57. {
  58. var newObj = $.extend(collections[i],{makeLoaded:true});
  59. globalResourceCardDAVList.insertResource(newObj, collections[i].resourceIndex, true);
  60. CardDAVUpdateMainLoader(collections[i]);
  61. }
  62. }
  63. if(isError)
  64. $('#ResourceCardDAVList').find('[data-id="'+collections[i].uid+'"]').addClass('r_error');
  65. else
  66. $('#ResourceCardDAVList').find('[data-id="'+collections[i].uid+'"]').removeClass('r_error');
  67. }
  68. }
  69. }
  70. }
  71. function unloadCardDAVCollection(unloadArray)
  72. {
  73. var collections = globalResourceCardDAVList.collections;
  74. var unloadedColls=new Array();
  75. var contactsToDelete=new Array();
  76. var collRegex = new RegExp('^(https?://)([^@/]+(?:@[^@/]+)?)@([^/]+)(.*/)([^/]+/)([^/]*)','i');
  77. for(var i=0;i<collections.length;i++)
  78. {
  79. if(collections[i].uid!=undefined)
  80. {
  81. var uidParts=(collections[i].uid).match(RegExp('^(https?://)([^@/]+(?:@[^@/]+)?)@(.*)'));
  82. var checkHref = uidParts[1]+uidParts[3];
  83. if(unloadArray.indexOf(checkHref)!=-1)
  84. {
  85. $('#AddressbookOverlay').children('.loaderInfo').text(localization[globalInterfaceLanguage].unloadingAddressbooks);
  86. unloadedColls.push(collections[i].uid);
  87. globalAddressbookList.vcard_groups[collections[i].uid] = new Array();
  88. collections[i].someChanged=false;
  89. collections[i].makeLoaded=false;
  90. collections[i].syncToken='';
  91. collections[i].oldSyncToken='';
  92. $('#ResourceCardDAVList').find('input[data-id="'+collections[i].uid+'"]').prop('checked',false);
  93. $('#ResourceCardDAVList').find('input[data-id="'+collections[i].uid+'"]').parent().parent().find('.group').each(function(){
  94. $(this).find(':input').prop('checked',false);
  95. });
  96. globalAddressbookList.applyABFilter(collectionChBoxClick($('#ResourceCardDAVList').find('input[data-id="'+collections[i].uid+'"]').get(0), '#ResourceCardDAVList', '.resourceCardDAV_header', '.resourceCardDAV', '.contact_group', true), false);
  97. }
  98. }
  99. }
  100. var contactLoaded = globalAddressbookList.contactLoaded;
  101. if((contactLoaded!=null && typeof globalAddressbookList.contacts_hash[contactLoaded.uid]!= 'undefined' && !globalAddressbookList.contacts_hash[contactLoaded.uid].show) || contactLoaded==null)
  102. for(var contact in globalAddressbookList.contacts_hash)
  103. if(globalAddressbookList.contacts_hash[contact].show)
  104. {
  105. globalAddressbookList.contactLoaded=contact;
  106. break;
  107. }
  108. if(globalSettingsSaving=='addressbook' && !globalFirstHideLoader)
  109. setTimeout(function(){hideUnloadedCardDAVCollectionsCallBack();},300);
  110. }
  111. function addLoadCardDAVCollection(loadingArray)
  112. {
  113. var collections = globalResourceCardDAVList.collections;
  114. for(var i=0;i<collections.length;i++)
  115. {
  116. if(collections[i].uid!=undefined)
  117. {
  118. var uidParts=(collections[i].uid).match(RegExp('^(https?://)([^@/]+(?:@[^@/]+)?)@(.*)'));
  119. var checkHref = uidParts[1]+uidParts[3];
  120. if(loadingArray.indexOf(checkHref)!=-1 && !collections[i].makeLoaded)
  121. {
  122. var resDOMItem=$('#ResourceCardDAVList').find('.resourceCardDAV[data-id="'+jqueryEscapeSelector(collections[i].uid)+'"]');
  123. // if the collection is re-inserted, certain data are still valid and we need to preserve these
  124. collections[i].someChanged=true;
  125. collections[i].makeLoaded=true;
  126. var rex=vCard.pre['accountUidParts'];
  127. var tmp=collections[i].accountUID.match(rex);
  128. var resourceCalDAV_href=tmp[1]+tmp[3]+tmp[4];
  129. var resourceCalDAV_user=tmp[2];
  130. for(var j=0;j<globalAccountSettings.length;j++)
  131. if(globalAccountSettings[j].href==resourceCalDAV_href && globalAccountSettings[j].userAuth.userName==resourceCalDAV_user && globalLoadedPrincipals.indexOf(resourceCalDAV_href)==-1)
  132. {
  133. globalLoadedPrincipals.push(globalAccountSettings[j].href);
  134. break;
  135. }
  136. var resDOMHeader=resDOMItem.parent().prevUntil('.resourceCardDAV_header').last().prev();
  137. if(!resDOMHeader.length)
  138. resDOMHeader=resDOMItem.parent().prev();
  139. resDOMHeader.css('display','block');
  140. resDOMItem.css('display','');
  141. var input=resDOMItem.find('input[type=checkbox]').not('.unloadCheck');
  142. input.prop('checked',true).prop('indeterminate',false);
  143. collectionChBoxClick(input.get(0), '#ResourceCardDAVList', '.resourceCardDAV_header', '.resourceCardDAV', '.contact_group', false);
  144. collections[i].newlyAdded=true;
  145. }
  146. }
  147. }
  148. }
  149. function CardDAVloadResources(resourceList, forceLoad)
  150. {
  151. if(forceLoad!=true && globalWindowFocus==false)
  152. return false;
  153. if(!(resourceList instanceof Array))
  154. resourceList=[resourceList];
  155. // i.pad((resourceList.length+'').length) is used for custom sorting
  156. //for(var i=0;i<resourceList.length;i++)
  157. var i=0;
  158. CardDAVnetFindResource(resourceList[0], i.pad((resourceList.length+'').length), forceLoad, 0);
  159. }
  160. // ResourceCardDAVList Class
  161. function ResourceCardDAVList()
  162. {
  163. this.collections=new Array();
  164. // DONE
  165. this.reset=function()
  166. {
  167. this.collections.splice(0,this.collections.length);
  168. }
  169. // DONE
  170. // resource header value
  171. this.getHeaderValue=function(inputResource)
  172. {
  173. var re=new RegExp('^(https?://)([^@/]+(?:@[^@/]+)?)@([^/]+).*/([^/]*)/','i');
  174. var tmp=inputResource.accountUID.match(re);
  175. var tmp_host=tmp[3]; // hostname [%H]
  176. var tmp_host_wo_port=tmp[3].replace(RegExp(':[0-9]+$'),''); // hostname without port [%h]
  177. var tmp_domain=tmp_host_wo_port.replace(RegExp('^[^.]+\\.'), ''); // domain name [%D]
  178. var tmp_domain_min=tmp_host_wo_port.match(RegExp('^([^.]+\\.)*?((?:[^.]+\\.)?[^.]+)$'))[2]; // domain name min. (only 1 or 2 level domain string) [%d]
  179. var tmp_principal=decodeURIComponent(tmp[4]); // principal username [%P]
  180. var tmp_principal_wo_domain=decodeURIComponent(tmp[4]).replace(RegExp('(@.*)?$'),''); // principal username without @domain.com [%p]
  181. var tmp_user=inputResource.userAuth.userName; // login name [%U]
  182. var tmp_user_wo_domain=inputResource.userAuth.userName.replace(RegExp('@.*$'),''); // login name without @domain.com [%u]
  183. if(typeof inputResource.hrefLabel!='string' || inputResource.hrefLabel=='' || (inputResource.hrefLabel=='%x' && inputResource.headervalue==''))
  184. inputResource.hrefLabel='%d/%p [%u]';
  185. var result=inputResource.hrefLabel;
  186. result=result.replace(RegExp('%H', 'g'), tmp_host);
  187. result=result.replace(RegExp('%h', 'g'), tmp_host_wo_port);
  188. result=result.replace(RegExp('%D', 'g'), tmp_domain);
  189. result=result.replace(RegExp('%d', 'g'), tmp_domain_min);
  190. result=result.replace(RegExp('%P', 'g'), tmp_principal);
  191. result=result.replace(RegExp('%p', 'g'), tmp_principal_wo_domain);
  192. result=result.replace(RegExp('%U', 'g'), tmp_user);
  193. result=result.replace(RegExp('%u', 'g'), tmp_user_wo_domain);
  194. result=result.replace(RegExp('%x', 'g'), inputResource.headervalue);
  195. inputResource.hrefLabel=result;
  196. return result;
  197. }
  198. // DONE
  199. this.getSortKey=function(inputResource, forHeader, inputResourceIndex)
  200. {
  201. var re=new RegExp('^(https?://)([^@/]+(?:@[^@/]+)?)@([^/]+)(.*/)([^/]+/)([^/]+/)([^/]*)','i');
  202. var tmp=inputResource.uid.match(re);
  203. var out='';
  204. // custom sorting (instead of alphabetical)
  205. if(globalSettings.resourcealphabetsorting.value!=true)
  206. out+=inputResourceIndex.pad(String(globalAccountSettings.length).length);
  207. out+=tmp[1]+tmp[3]+'/'+(inputResource.hrefLabel==undefined || inputResource.hrefLabel==null ? tmp[5] : inputResource.hrefLabel)+' '+inputResource.userAuth.userName;
  208. if(forHeader==false)
  209. out+=' '+inputResource.displayvalue;
  210. return out;
  211. }
  212. // DONE
  213. // Resource list is not sorted, instead "insert sort" is performed (todo: add collection hash)
  214. this.insertResource=function(inputCollection, inputCollectionIndex)
  215. {
  216. var makeActive=false;
  217. var makeChecked=false;
  218. var makeIndeterminate=false;
  219. var makeContactGroups=[];
  220. var nameChanged=false;
  221. // do not insert entry with duplicate UID
  222. for(var i=0;i<this.collections.length;i++)
  223. if(this.collections[i].uid!=undefined && this.collections[i].uid==inputCollection.uid) // already loaded
  224. {
  225. // no visual interface change needed
  226. if(this.collections[i].color==inputCollection.color && this.collections[i].displayvalue==inputCollection.displayvalue && this.collections[i].permissions.read_only==inputCollection.permissions.read_only && this.collections[i].headervalue==inputCollection.headervalue)
  227. {
  228. // if the collection is re-inserted, certain data are still valid and we need to preserve these
  229. this.collections[i]=$.extend(inputCollection, {sortkey: this.collections[i].sortkey, newlyAdded: this.collections[i].newlyAdded, syncToken: this.collections[i].syncToken, oldSyncToken: this.collections[i].oldSyncToken, forceSyncPROPFIND: this.collections[i].forceSyncPROPFIND, loaded: this.collections[i].loaded});
  230. return 0;
  231. }
  232. else // visual change => we need to remove and reinsert it
  233. {
  234. nameChanged=true;
  235. makeActive=$('#ResourceCardDAVList').find('[data-id='+jqueryEscapeSelector(inputCollection.uid)+']').hasClass('resourceCardDAV_selected');
  236. makeChecked=$('#ResourceCardDAVList').find('[data-id='+jqueryEscapeSelector(inputCollection.uid)+']').find('input[type=checkbox]').not('.unloadCheck').prop('checked');
  237. makeIndeterminate=$('#ResourceCardDAVList').find('[data-id='+jqueryEscapeSelector(inputCollection.uid)+']').find('input[type=checkbox]').not('.unloadCheck').prop('indeterminate');
  238. // here get the list of vcard groups with the current state (we need to re-add them to the interface)
  239. $('#ResourceCardDAVList').find('.group[data-id^='+jqueryEscapeSelector(inputCollection.uid)+']').not('[data-id='+jqueryEscapeSelector(inputCollection.uid)+']').each(
  240. function(index, element)
  241. {
  242. makeContactGroups.push({uid: $(element).attr('data-id'), isActive: $(element).hasClass('resourceCardDAV_selected'), isChecked: $(element).find('input[type=checkbox]').prop('checked')});
  243. }
  244. );
  245. // the collection name is changed and must be moved to correct place (we first remove it and then reinsert)
  246. this.removeResource(inputCollection.uid, false);
  247. break;
  248. }
  249. }
  250. if(!globalCardDAVInitLoad&&!nameChanged)
  251. {
  252. var uidParts=inputCollection.uid.match(RegExp('^(https?://)([^@/]+(?:@[^@/]+)?)@(.*)'));
  253. var checkHref = uidParts[1]+uidParts[3];
  254. var isLoaded=false;
  255. if(typeof globalCrossServerSettingsURL!='undefined'&&globalCrossServerSettingsURL!=null&globalCrossServerSettingsURL)
  256. {
  257. var uidParts=inputCollection.uid.match(RegExp('/([^/]+/[^/]+/)$'));
  258. var tmpParts = uidParts[1].match('^(.*/)([^/]+)/$');
  259. var checkHref3=decodeURIComponent(tmpParts[1])+tmpParts[2]+'/';
  260. var found=false;
  261. for(var l=0;l<globalSettings.loadedaddressbookcollections.value.length;l++)
  262. {
  263. var tmpParts2 = globalSettings.loadedaddressbookcollections.value[l].match('^(.*/)([^/]+)/([^/]+)/$');
  264. var checkHref2=decodeURIComponent(tmpParts2[2])+'/'+tmpParts2[3]+'/';
  265. if(checkHref3==checkHref2)
  266. {
  267. found=true;
  268. break;
  269. }
  270. }
  271. isLoaded=found;
  272. }
  273. else
  274. isLoaded=(globalSettings.loadedaddressbookcollections.value.indexOf(checkHref)!=-1);
  275. // if(!isLoaded)
  276. // globalSettings.loadedaddressbookcollections.value.push(checkHref);
  277. if(!isLoaded)
  278. {
  279. inputCollection.makeLoaded=false;
  280. inputCollection.newlyAdded=false;
  281. }
  282. else
  283. {
  284. inputCollection.makeLoaded=true;
  285. inputCollection.newlyAdded=true;
  286. }
  287. inputCollection.oldSyncToken = '';
  288. inputCollection.someChanged=false;
  289. makeChecked=true;
  290. }
  291. var oldHrefLabel = inputCollection.hrefLabel;
  292. var headerValue = this.getHeaderValue(inputCollection);
  293. // get sort key for the collection
  294. inputCollection.sortkey=this.getSortKey(inputCollection, false, inputCollectionIndex);
  295. // find the index where to insert the new resource O(n*log(n))
  296. var insertIndex=0;
  297. var low=0;
  298. var high=this.collections.length-1;
  299. if(this.collections.length>0)
  300. while(low<high)
  301. {
  302. insertIndex=low+Math.round((high-low)/2);
  303. var result=(cmp_str=this.collections[insertIndex].sortkey).customCompare(inputCollection.sortkey,globalSortAlphabet,1,false);
  304. if(result==-1)
  305. {
  306. if(insertIndex+1==this.collections.length-1 && typeof this.collections[insertIndex+1]!='undefined' && (cmp_str=this.collections[insertIndex+1].sortkey).customCompare(inputCollection.sortkey,globalSortAlphabet,1,false)==-1)
  307. {
  308. insertIndex+=2;
  309. break;
  310. }
  311. else
  312. low=++insertIndex;
  313. }
  314. else if(result==1)
  315. {
  316. if((cmp_str=this.collections[insertIndex-1].sortkey).customCompare(inputCollection.sortkey,globalSortAlphabet,1,false)==-1)
  317. break;
  318. else
  319. high=--insertIndex;
  320. }
  321. }
  322. // create the header
  323. var headerObject={headerOnly: true, sortkey: this.getSortKey(inputCollection, true, inputCollectionIndex), displayvalue: (oldHrefLabel=='%x' ? headerValue.replace(RegExp('^[^#]+#'),'') : headerValue)};
  324. // check for header existence
  325. var headerMiss=1;
  326. for(var i=0;i<this.collections.length;i++)
  327. if(this.collections[i].headerOnly!=undefined && this.collections[i].headerOnly==true && this.collections[i].displayvalue==headerObject.displayvalue)
  328. {headerMiss=0; break;}
  329. // if header not exists
  330. if(headerMiss)
  331. {
  332. // insert header
  333. this.collections.splice(insertIndex, 0, headerObject);
  334. // insert header to the interface
  335. var newElement=globalTranslCardDAVListHeader.clone();
  336. newElement.append(headerObject.displayvalue);
  337. newElement.find('input[type=checkbox]').click(function(){globalAddressbookList.applyABFilter(resourceChBoxClick(this, '#ResourceCardDAVList', '.resourceCardDAV_header', true), false);});
  338. $('#ResourceCardDAVList').children().eq(insertIndex).after(newElement);
  339. }
  340. // insert the resource
  341. if(!nameChanged)
  342. globalAddressbookList.vcard_groups[inputCollection.uid] = new Array();
  343. this.collections.splice(insertIndex+headerMiss, 0, inputCollection);
  344. // insert the resource to the interface
  345. var newElement=globalTranslCardDAVListItem.clone();
  346. // the onclick event is disabled until the last drag&drop operation is completed
  347. newElement.find('.resourceCardDAV').click(function(e){
  348. if(globalAddressbookCollectionsLoading)
  349. return true;
  350. if(e.shiftKey) {
  351. var uid = $(this).attr('data-id');
  352. $('#ResourceCardDAVList').find('.resourceCardDAV:visible').children('input[type="checkbox"]').each(function(){
  353. var currentUid = $(this).attr('data-id');
  354. if(currentUid===uid)
  355. $(this).prop({'checked':true, 'indeterminate':false});
  356. else
  357. $(this).prop({'checked':false, 'indeterminate':false}).attr('data-ind', 'true');
  358. collectionChBoxClick(this, '#ResourceCardDAVList', '.resourceCardDAV_header', '.resourceCardDAV', '.contact_group', false);
  359. });
  360. globalAddressbookList.applyABFilter([uid], false);
  361. }
  362. globalResourceCardDAVList.resourceOrGroupClick(this.getAttribute('data-id'));
  363. });
  364. newElement.find('.resourceCardDAV').attr('data-id', inputCollection.uid);
  365. if(inputCollection.permissions.read_only)
  366. newElement.find('.resourceCardDAV').addClass('resourceCardDAV_ro');
  367. if(globalCardDAVInitLoad)
  368. newElement.find('.resourceCardDAV').addClass('r_operate');
  369. newElement.find('.resourceCardDAVColor').css('background-color',inputCollection.color);
  370. if(typeof globalAddrColorPropertyXmlns== 'undefined' || globalAddrColorPropertyXmlns== null || globalAddrColorPropertyXmlns==='' || globalAddrColorPropertyXmlns!==false)
  371. bindColorPickerClick(newElement.find('.resourceCardDAVColor'));
  372. newElement.find('.resourceCardDAV').find('input[type=checkbox]').attr({'data-id': inputCollection.uid, 'onclick':'if(globalAddressbookList.contactToReload!=null){if(globalAddressbookList.contactToReload.uid.indexOf("'+inputCollection.uid+'")==0){hideNotVisibleMessage()}}var evt=arguments[0];evt.stopPropagation(); if($(this).parents(\':eq(2)\').find(\'[class^="r_"]\').length>0) return false; else { globalAddressbookList.applyABFilter(collectionChBoxClick(this, \'#ResourceCardDAVList\', \'.resourceCardDAV_header\', \'.resourceCardDAV\', \'.contact_group\', true), false); }'});
  373. newElement.find('.resourceCardDAV').append(inputCollection.displayvalue);
  374. newElement.find('.resourceCardDAV').attr('title',inputCollection.displayvalue);
  375. $('#ResourceCardDAVList').children().eq(insertIndex+headerMiss).after(newElement);
  376. if(inputCollection.makeLoaded)
  377. {
  378. var resDOMHeader=newElement.prevUntil('.resourceCardDAV_header').last().prev();
  379. if(!resDOMHeader.length)
  380. resDOMHeader=newElement.prev();
  381. resDOMHeader.css('display','block');
  382. var rex=vCard.pre['accountUidParts'];
  383. var tmp=inputCollection.accountUID.match(rex);
  384. var resourceCalDAV_href=tmp[1]+tmp[3]+tmp[4];
  385. var resourceCalDAV_user=tmp[2];
  386. for(var i=0;i<globalAccountSettings.length;i++)
  387. if(globalAccountSettings[i].href==resourceCalDAV_href && globalAccountSettings[i].userAuth.userName==resourceCalDAV_user && globalLoadedPrincipals.indexOf(resourceCalDAV_href)==-1)
  388. {
  389. globalLoadedPrincipals.push(globalAccountSettings[i].href);
  390. break;
  391. }
  392. }
  393. else
  394. newElement.css('display','none');
  395. // make the area droppable if the collection is not read-only
  396. if(!inputCollection.permissions.read_only && (typeof globalDisableDragAndDrop=='undefined' || globalDisableDragAndDrop!=true))
  397. $('#ResourceCardDAVList').children().eq(insertIndex+headerMiss+1).find('.resourceCardDAV').droppable({
  398. accept: '.ablist_item',
  399. tolerance: 'pointer',
  400. hoverClass: 'resourceCardDAV_dropped_to',
  401. drop: function(event, ui){
  402. // animate the clone of the dropped (draggable) element
  403. var tmp=ui.helper.clone();
  404. tmp.appendTo('body').animate({opacity: 0, color: 'transparent', height: 0, width: 0, fontSize: 0, lineHeight: 0, paddingLeft: 0, paddingRight: 0}, 750, function(){tmp.remove()});
  405. // disallow to drag the original dropped element until the processing is finished
  406. ui.draggable.draggable('option', 'disabled', true);
  407. // animate the original dropped element
  408. ui.draggable.animate({opacity: 0.3}, 750);
  409. // disallow to drop any new element until the processing is finished
  410. $(this).droppable('option', 'disabled', true);
  411. // show the loader icon
  412. $(this).addClass('r_operate');
  413. // moving contact between different collections in the same resource
  414. if($(this).attr('data-id').replace(RegExp('[^/]+/$'),'')==ui.draggable.attr('data-id').replace(RegExp('[^/]+/[^/]+$'),''))
  415. {
  416. var tmp2=globalAddressbookList.getContactByUID(ui.draggable.attr('data-id'));
  417. // here we generate the destination for MOVE (we don't use the old vCard file name to minimalize the possible conflict situations)
  418. var tmp3=($(this).attr('data-id')+hex_sha256(tmp2.vcard+(new Date().getTime()))+'.vcf').match(RegExp('^(https?://)([^@/]+(?:@[^@/]+)?)@([^/]+)(.*/)([^/]+/)([^/]*)','i'));
  419. tmp2.moveDestUID=$(this).attr('data-id');
  420. tmp2.moveDest=tmp3[1]+tmp3[3]+tmp3[4]+tmp3[5]+tmp3[6];
  421. // we need to store the ui object references for error handling in the GUI
  422. tmp2.uiObjects={contact: ui.draggable, resource: $(this).attr('data-id')};
  423. lockAndPerformToCollection(tmp2, globalRefAddContact.attr('data-filter-url'), 'MOVE');
  424. }
  425. // inter-resource contact "move" (put + delete)
  426. else
  427. {
  428. var tmp2=globalAddressbookList.getContactByUID(ui.draggable.attr('data-id'));
  429. // here we generate the destination for MOVE (we don't use the old vCard file name to minimalize the possible conflict situations)
  430. tmp2.newAccountUID=globalResourceCardDAVList.getCollectionByUID($(this).attr('data-id')).accountUID;
  431. tmp2.newUid=$(this).attr('data-id');
  432. // we need to store the ui object references for error handling in the GUI
  433. tmp2.uiObjects={contact: ui.draggable, resource: $(this).attr('data-id')};
  434. lockAndPerformToCollection(tmp2, globalRefAddContact.attr('data-filter-url'), 'IRM_DELETE');
  435. }
  436. }
  437. });
  438. // restore the active state (we do not need to call this.resourceOrGroupClick() here, because we re-activate the "old active item")
  439. if(makeActive)
  440. {
  441. $('#ResourceCardDAVList').find('.resourceCardDAV_item').find('.resourceCardDAV').removeClass('resourceCardDAV_selected');
  442. $('#ResourceCardDAVList').children().eq(insertIndex+headerMiss+1).find('.resourceCardDAV').addClass('resourceCardDAV_selected');
  443. }
  444. // restore the checked state
  445. if(makeChecked)
  446. $('#ResourceCardDAVList').children().eq(insertIndex+headerMiss+1).find('.resourceCardDAV').find('input[type=checkbox]').prop('checked', true);
  447. // restore the indeterminate state
  448. if(makeIndeterminate)
  449. $('#ResourceCardDAVList').children().eq(insertIndex+headerMiss+1).find('.resourceCardDAV').find('input[type=checkbox]').prop('indeterminate', true);
  450. if(!globalCardDAVInitLoad)
  451. collectionChBoxClick(newElement.find('input[type=checkbox]').get(0), '#ResourceCardDAVList', '.resourceCardDAV_header', '.resourceCardDAV', null, false);
  452. // restore contact groups
  453. if(makeContactGroups.length>0)
  454. for(var i=0;i<makeContactGroups.length;i++)
  455. {
  456. globalAddressbookList.insertContactGroup(globalAddressbookList.getContactGroupByUID(makeContactGroups[i].uid), false, true);
  457. $('#ResourceCardDAVList').find('.group[data-id='+jqueryEscapeSelector(makeContactGroups[i].uid)+']').find('input[type=checkbox]').prop('checked', makeContactGroups[i].isChecked);
  458. if(makeContactGroups[i].isActive)
  459. $('#ResourceCardDAVList').find('.group[data-id='+jqueryEscapeSelector(makeContactGroups[i].uid)+']').addClass('resourceCardDAV_selected');
  460. }
  461. }
  462. // DONE
  463. this.removeResource=function(inputCollectionUID, activateNextIfNeeded)
  464. {
  465. var nextCandidateToActive=null;
  466. for(var i=this.collections.length-1;i>=0;i--)
  467. if(this.collections[i].uid==inputCollectionUID)
  468. {
  469. var uidRemoved=this.collections[i].uid;
  470. var item=$('#ResourceCardDAVList').find('.resourceCardDAV[data-id^="'+jqueryEscapeSelector(this.collections[i].uid)+'"]');
  471. var item_prev=item.parent().prev();
  472. var item_was_selected=item.hasClass('resourceCardDAV_selected');
  473. if(activateNextIfNeeded && item_was_selected)
  474. {
  475. // select the nearest candidate to load
  476. if((i+1)<=(this.collections.length-1))
  477. {
  478. if(this.collections[i+1].headerOnly!=true)
  479. nextCandidateToActive=this.collections[i+1];
  480. else if((i+2)<=(this.collections.length-1))
  481. nextCandidateToActive=this.collections[i+2];
  482. }
  483. if(nextCandidateToActive==null && (i-1)>0)
  484. {
  485. if(this.collections[i-1].headerOnly!=true)
  486. nextCandidateToActive=this.collections[i-1];
  487. else if((i-2)>0)
  488. nextCandidateToActive=this.collections[i-2];
  489. }
  490. }
  491. // remove the item
  492. item.parent().remove();
  493. this.collections.splice(i,1);
  494. // if the next item is undefined or is header, and the previous item is header, then delete the header
  495. if((this.collections[i]==undefined || this.collections[i].headerOnly==true) && this.collections[i-1].headerOnly==true)
  496. {
  497. item_prev.remove();
  498. this.collections.splice(--i,1);
  499. }
  500. // make another resource active
  501. if(activateNextIfNeeded && nextCandidateToActive!=null)
  502. this.resourceOrGroupClick(nextCandidateToActive.uid);
  503. break;
  504. }
  505. }
  506. // DONE
  507. this.removeOldResources=function(inputUidBase, inputTimestamp)
  508. {
  509. for(var i=this.collections.length-1;i>=0;i--)
  510. if(this.collections[i].timestamp!=undefined && this.collections[i].uid.indexOf(inputUidBase)==0 && this.collections[i].timestamp<inputTimestamp)
  511. {
  512. var uidRemoved=this.collections[i].uid;
  513. var item=$('#ResourceCardDAVList').find('.resourceCardDAV[data-id^="'+jqueryEscapeSelector(this.collections[i].uid)+'"]');
  514. var item_header=item.parent().prevUntil('.resourceCardDAV_header').last().prev();
  515. if(!item_header.length)
  516. item_header=item.parent().prev();
  517. // remove the item
  518. item.parent().remove();
  519. this.collections.splice(i,1);
  520. //remove contacts from addressbook
  521. var contactsToRemove = new Array();
  522. for(var c=0;c<globalAddressbookList.contacts.length; c++)
  523. {
  524. if(typeof globalAddressbookList.contacts[c].uid!='undefined'&&globalAddressbookList.contacts[c].uid.replace(RegExp('/[^/]*$',''),'/')==uidRemoved)
  525. contactsToRemove.push(globalAddressbookList.contacts[c].uid);
  526. }
  527. globalAddressbookList.removeContact(contactsToRemove);
  528. // if (next item undefined or is header) and previous item is header delete the header
  529. if((this.collections[i]==undefined || this.collections[i].headerOnly==true) && i>0 && this.collections[i-1].headerOnly==true)
  530. {
  531. item_header.remove();
  532. this.collections.splice(--i,1);
  533. }
  534. else
  535. {
  536. var firstVisibleCollection=null;
  537. for(var vi=i-1;vi>0;vi--)
  538. {
  539. if(this.collections[vi].headerOnly==true)
  540. break;
  541. if(this.collections[vi].makeLoaded)
  542. {
  543. firstVisibleCollection=this.collections[vi];
  544. break;
  545. }
  546. }
  547. if(firstVisibleCollection==null)
  548. {
  549. for(var vi=i;vi<this.collections.length;vi++)
  550. {
  551. if(this.collections[vi].headerOnly==true)
  552. break;
  553. if(this.collections[vi].makeLoaded)
  554. {
  555. firstVisibleCollection=this.collections[vi];
  556. break;
  557. }
  558. }
  559. }
  560. if(firstVisibleCollection==null)
  561. item_header.css('display','none');
  562. else
  563. {
  564. var triggerInput=$('#ResourceCalDAVList').find('.resourceCardDAV[data-id^="'+jqueryEscapeSelector(firstVisibleCollection.uid)+'"]').find('input[type=checkbox]');
  565. collectionChBoxClick(triggerInput.get(0), '#ResourceCardDAVList', '.resourceCardDAV_header', '.resourceCardDAV', null, false);
  566. }
  567. }
  568. }
  569. };
  570. this.resourceOrGroupClick=function(inputUID)
  571. {
  572. // console.log('click na: '+inputUID);
  573. var tmp=inputUID.match(RegExp('(^.*/)(.*)'),'');
  574. for(var i=0;i<this.collections.length;i++)
  575. if(this.collections[i].uid!=undefined && this.collections[i].uid==tmp[1])
  576. {
  577. // YYY check this
  578. this.collections[i].filterUID=inputUID;
  579. if(this.collections[i].permissions.read_only==true)
  580. globalRefAddContact.addClass('element_no_display');
  581. else
  582. globalRefAddContact.removeClass('element_no_display');
  583. globalRefAddContact.attr('data-url', this.collections[i].uid.replace(RegExp('[^/]+$'),''));
  584. globalRefAddContact.attr('data-filter-url',this.collections[i].filterUID); // Set the current addressbook filter uid
  585. globalRefAddContact.attr('data-account-uid',this.collections[i].accountUID);
  586. globalRefAddContact.attr('data-color',this.collections[i].color);
  587. // Make the selected collection active
  588. if(!globalCardDAVInitLoad)
  589. {
  590. if(typeof(globalContactsABChange)=='function')
  591. globalContactsABChange(this.collections[i].uid);
  592. $('#ResourceCardDAVList').find('.resourceCardDAV_item').find('.resourceCardDAV_selected').removeClass('resourceCardDAV_selected');
  593. $('#ResourceCardDAVList').find('[data-id='+jqueryEscapeSelector(this.collections[i].uid)+']').addClass('resourceCardDAV_selected');
  594. if(this.collections[i].filterUID[this.collections[i].filterUID.length-1]!='/')
  595. $('#ResourceCardDAVList').find('[data-id='+jqueryEscapeSelector(this.collections[i].filterUID)+']').addClass('resourceCardDAV_selected');
  596. }
  597. }
  598. };
  599. /*
  600. this.loadAddressbookByUID=function(inputUID)
  601. {
  602. // Show the progress loader ...
  603. if(this.collections[i].loaded==undefined || this.collections[i].loaded==false)
  604. {
  605. this.collections[i].loaded=true; // otazka ci to dat sem alebo tam kre sa to realne nacita (ak to bude na druhom mieste, tak sa mozes stat ze user klikne vela krat a bude vela paralelnych loadov)
  606. }
  607. }
  608. */
  609. this.getCollectionByUID=function(inputUID)
  610. {
  611. for(var i=0;i<this.collections.length;i++)
  612. if(this.collections[i].uid==inputUID)
  613. return this.collections[i];
  614. return null;
  615. };
  616. this.setCollectionFlagByUID=function(inputUID, inputFlagName, inputFlagValue)
  617. {
  618. for(var i=0;i<this.collections.length;i++)
  619. if(this.collections[i].uid==inputUID)
  620. {
  621. this.collections[i][inputFlagName]=inputFlagValue;
  622. return this.collections[i];
  623. }
  624. return null;
  625. };
  626. this.getCollectionPrivByUID=function(inputUID)
  627. {
  628. for(var i=0;i<this.collections.length;i++)
  629. if(this.collections[i].uid!=undefined && this.collections[i].uid==inputUID)
  630. return this.collections[i].permissions.read_only;
  631. return null;
  632. };
  633. }