vcalendar.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. /*
  2. CalDavZAP - the open source CalDAV 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. // EventList Class
  19. function EventList()
  20. {
  21. this.events={};
  22. this.todos={};
  23. this.displayEventsArray={};
  24. this.displayTodosArray={};
  25. this.repeatable={};
  26. this.repeatableTodo={};
  27. this.reset=function()
  28. {
  29. this.events={};
  30. this.todos={};
  31. this.repeatable={};
  32. this.repeatableTodo={};
  33. this.displayEventsArray={};
  34. this.displayTodosArray={};
  35. }
  36. this.getNewUID=function()
  37. {
  38. //we count with uniqueness of generated hash string
  39. var newUID=null;
  40. newUID=generateUID();
  41. return newUID;
  42. }
  43. this.getSortKey=function(vcalendar_clean)
  44. {
  45. var vcalendar_element=('\r\n'+vcalendar_clean).match(RegExp('\r\n'+vCalendar.re['contentline_N'], 'm'));
  46. if(vcalendar_element!=null && vcalendar_element.length==1) // if the N attribute is not present exactly once, vCalendar is considered invalid
  47. {
  48. // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value"
  49. var parsed=vcalendar_element[0].match(RegExp('\r\n'+vCalendar.re['contentline_parse'], 'm'));
  50. // parsed_value = [0]->Family, [1]->Given, [2]->Middle, [3]->Prefix, [4]->Suffix
  51. var parsed_value=vcalendarSplitValue(parsed[4], ';');
  52. // TODO: allow users to set the sorting method
  53. if(parsed_value[0]!='' || parsed_value[1]!='')
  54. {
  55. var sort_value=parsed_value[0];
  56. if (sort_value!='' && parsed_value[1]!='')
  57. sort_value+=' ';
  58. sort_value+=parsed_value[1];
  59. }
  60. else // if no N value present, we use the FN instead
  61. {
  62. var vcalendar_element2=('\r\n'+vcalendar_clean).match(RegExp('\r\n'+vCalendar.re['contentline_FN'], 'm'));
  63. if(vcalendar_element2!=null && vcalendar_element2.length==1) // if the FN attribute is not present exactly once, vCalendar is considered invalid
  64. {
  65. // parsed (contentline_parse) = [1]->"group.", [2]->"name", [3]->";param;param", [4]->"value"
  66. var parsed=vcalendar_element2[0].match(RegExp('\r\n'+vCalendar.re['contentline_parse'], 'm'));
  67. var sort_value=parsed[4];
  68. }
  69. }
  70. return sort_value;
  71. }
  72. else
  73. return false;
  74. }
  75. // Resource list is not sorted, instead "insert sort" is performed
  76. this.insertEvent=function(forceCall,inputCollection, inputEvent, forceReload, isEvent, isFromServer)
  77. {
  78. makeActive=null;
  79. var rid=inputEvent.uid.substring(0, inputEvent.uid.lastIndexOf('/')+1);
  80. var compObject = {};
  81. if(isEvent)
  82. compObject = globalEventList.events;
  83. else
  84. compObject = globalEventList.todos;
  85. // do not insert entry with duplicate UID
  86. if(compObject[rid][inputEvent.uid]!=undefined)
  87. {
  88. if(compObject[rid][inputEvent.uid].etag!=inputEvent.etag)
  89. {
  90. this.removeOldEvent(inputEvent.uid, false, isEvent);
  91. makeActive=inputEvent.uid;
  92. }
  93. else
  94. {
  95. checkEventLoader(globalResourceCalDAVList.counterList[inputCollection.uid+' '+inputCollection.listType], false);
  96. return 0;
  97. }
  98. }
  99. if(isEvent)
  100. {
  101. // find the index where to insert the new event
  102. var res=getvCalendarstart(inputEvent);
  103. if(res!=false && res!=-1 && res!=undefined && res!=null)
  104. inputEvent.sortStart=res;
  105. else
  106. {
  107. console.log("Error: '"+inputEvent.uid+"': unable to parse vEvent");
  108. checkEventLoader(globalResourceCalDAVList.counterList[inputCollection.uid+' '+inputCollection.listType], true);
  109. return false;
  110. }
  111. globalEventList.events[rid][inputEvent.uid]=inputEvent;
  112. }
  113. else
  114. globalEventList.todos[rid][inputEvent.uid]=inputEvent;
  115. if(makeActive!=null)
  116. {
  117. globalEventList.loadEventByUID(makeActive, isEvent,isFromServer);
  118. return 0;
  119. }
  120. var inputUID=inputEvent.uid;
  121. rid=inputUID.substring(0, inputUID.lastIndexOf('/')+1);
  122. // setTimeout(function()
  123. // {
  124. if(!isEvent)
  125. {
  126. if(vcalendarTodoData(inputCollection, inputEvent, true) == false)
  127. console.log("Error: '"+inputEvent.uid+"': unable to parse vTodo");
  128. }
  129. else
  130. {
  131. if(vcalendarToData(inputCollection, inputEvent, true) == false)
  132. console.log("Error: '"+inputEvent.uid+"': unable to parse vEvent");
  133. }
  134. if(isEvent)
  135. {
  136. if(inputEvent.counter==undefined)
  137. {
  138. if(globalVisibleCalDAVCollections.indexOf(rid)!=-1 || globalSettings.displayhiddenevents.value)
  139. refetchCalendarEvents();
  140. else
  141. {
  142. var beforeScroll = $('#main').width()-$('#calendar').width();
  143. $('#calendar').fullCalendar('removeEvents', 'fooUID');
  144. var afterScroll = $('#main').width()-$('#calendar').width();
  145. rerenderCalendar(beforeScroll!=afterScroll);
  146. }
  147. }
  148. }
  149. else
  150. {
  151. if(inputEvent.counter==undefined)
  152. {
  153. if(globalVisibleCalDAVTODOCollections.indexOf(rid)!=-1 || globalSettings.displayhiddenevents.value)
  154. refetchTodoEvents();
  155. }
  156. }
  157. if(inputEvent.counter!=undefined)
  158. checkEventLoader(globalResourceCalDAVList.counterList[inputCollection.uid+' '+inputCollection.listType], true);
  159. if(forceCall && !isEvent)
  160. $('#todoList').fullCalendar('selectEvent',$('[data-id="'+inputEvent.uid+'"]'));
  161. // }, 100);
  162. }
  163. this.checkAndTouchIfExists=function(calendarUID,inputUID,inputEtag,inputTimestamp)
  164. {
  165. if(globalEventList.events[calendarUID]!=undefined && globalEventList.events[calendarUID][inputUID]!=undefined)
  166. {
  167. globalEventList.events[calendarUID][inputUID].timestamp=inputTimestamp;
  168. if(globalEventList.events[calendarUID][inputUID].etag==inputEtag)
  169. return true;
  170. else
  171. return false;
  172. }
  173. else if(globalEventList.todos[calendarUID]!=undefined && globalEventList.todos[calendarUID][inputUID]!=undefined)
  174. {
  175. globalEventList.todos[calendarUID][inputUID].timestamp=inputTimestamp;
  176. if(globalEventList.todos[calendarUID][inputUID].etag==inputEtag)
  177. return true;
  178. else
  179. return false;
  180. }
  181. else
  182. return false;
  183. }
  184. this.removeOldEvents=function(inputUidBase, inputTimestamp, isEvent)
  185. {
  186. if(isEvent)
  187. {
  188. for(var i=0; i<globalResourceCalDAVList.collections.length;i++)
  189. if(globalResourceCalDAVList.collections[i].uid!=undefined)
  190. for(var key in globalEventList.events[globalResourceCalDAVList.collections[i].uid])
  191. {
  192. var event = globalEventList.events[globalResourceCalDAVList.collections[i].uid][key];
  193. if(event.timestamp!=undefined && event.uid.indexOf(inputUidBase)==0 && event.timestamp<inputTimestamp)
  194. globalEventList.removeOldEvent(event.uid, true, isEvent);
  195. }
  196. }
  197. else
  198. {
  199. for(var i=0; i<globalResourceCalDAVList.TodoCollections.length;i++)
  200. if(globalResourceCalDAVList.TodoCollections[i].uid!=undefined)
  201. for(var key in globalEventList.todos[globalResourceCalDAVList.TodoCollections[i].uid])
  202. {
  203. var event = globalEventList.todos[globalResourceCalDAVList.TodoCollections[i].uid][key];
  204. if(event.timestamp!=undefined && event.uid.indexOf(inputUidBase)==0 && event.timestamp<inputTimestamp)
  205. globalEventList.removeOldEvent(event.uid, true, isEvent);
  206. }
  207. }
  208. }
  209. this.removeOldEvent=function(inputUid, fromInterface, isEvent)
  210. {
  211. var rid=inputUid.substring(0, inputUid.lastIndexOf('/')+1);
  212. var uidRemoved=null;
  213. var isEvent=true;
  214. if(globalEventList.events[rid]!=undefined && globalEventList.events[rid][inputUid]!=undefined)
  215. {
  216. uidRemoved=inputUid;
  217. delete globalEventList.events[rid][inputUid];
  218. isEvent=true;
  219. }
  220. else if(globalEventList.todos[rid]!=undefined && globalEventList.todos[rid][inputUid]!=undefined)
  221. {
  222. uidRemoved=inputUid;
  223. delete globalEventList.todos[rid][inputUid];
  224. isEvent=false;
  225. }
  226. if(uidRemoved!=null)
  227. {
  228. if(fromInterface)
  229. {
  230. deleteEventFromArray(uidRemoved);
  231. if(isEvent)
  232. refetchCalendarEvents();
  233. else
  234. {
  235. var prevIndex = '';
  236. if(globalCalTodo!=null)
  237. prevIndex=$('.fc-view-todo .fc-list-day').find('.fc-event:visible').index($('[data-repeat-hash="'+globalCalTodo.repeatHash+'"]'));
  238. refetchTodoEvents();
  239. if(prevIndex!=-1 && $('.fc-view-todo .fc-list-day').find('.fc-event:visible').length > 0 && prevIndex>($('.fc-view-todo .fc-list-day').find('.fc-event:visible').length-1))
  240. $('#todoList').fullCalendar('selectEvent',$($('.fc-view-todo .fc-list-day').find('.fc-event:visible').get($('.fc-view-todo .fc-list-day').find('.fc-event:visible').length-1)));
  241. else if(prevIndex!=-1 && $('.fc-view-todo .fc-list-day').find('.fc-event:visible').length > 0 && prevIndex<=($('.fc-view-todo .fc-list-day').find('.fc-event:visible').length-1))
  242. $('#todoList').fullCalendar('selectEvent',$($('.fc-view-todo .fc-list-day').find('.fc-event:visible').get(prevIndex)));
  243. else
  244. $('#CATodo').attr('style','display:none');
  245. }
  246. }
  247. if(isEvent)
  248. delete globalEventList.repeatable[inputUid];
  249. else
  250. delete globalEventList.repeatableTodo[inputUid];
  251. }
  252. }
  253. this.loadEventByUID=function(inputUID, isEvent,isFromServer)
  254. {
  255. var rid='';
  256. if(inputUID.charAt(inputUID.length-1)!='/')
  257. {
  258. rid=inputUID.substring(0, inputUID.lastIndexOf('/')+1);
  259. if(isEvent)
  260. {
  261. if(globalEventList.events[rid][inputUID].uid!=undefined)
  262. {
  263. var evs='';
  264. if(!globalCalDAVInitLoad)
  265. evs=findEventInArray(globalEventList.events[rid][inputUID].uid, isEvent);
  266. if(evs!='' && evs.etag!=globalEventList.events[rid][inputUID].etag)
  267. {
  268. vcalendarToData(globalResourceCalDAVList.getCollectionByUID(rid), globalEventList.events[rid][inputUID], false);
  269. if(!isFromServer && (globalVisibleCalDAVCollections.indexOf(rid)!=-1 || globalSettings.displayhiddenevents.value))
  270. refetchCalendarEvents();
  271. else if(isFromServer)
  272. checkEventLoader(globalResourceCalDAVList.counterList[rid+' '+globalResourceCalDAVList.getCollectionByUID(rid).listType], true);
  273. }
  274. }
  275. }
  276. else
  277. {
  278. if(globalEventList.todos[rid][inputUID].uid!=undefined)
  279. {
  280. var evs='';
  281. if(!globalCalDAVInitLoad)
  282. evs=findEventInArray(globalEventList.todos[rid][inputUID].uid, isEvent);
  283. if(evs!='' && evs.etag!=globalEventList.todos[rid][inputUID].etag)
  284. {
  285. vcalendarTodoData(globalResourceCalDAVList.getCollectionByUID(rid), globalEventList.todos[rid][inputUID], false);
  286. if(globalVisibleCalDAVTODOCollections.indexOf(rid)!=-1 || globalSettings.displayhiddenevents.value)
  287. {
  288. $('#todoList').fullCalendar('allowSelectEvent',false);
  289. refetchTodoEvents();
  290. $('#todoList').fullCalendar('allowSelectEvent',true);
  291. if($('#showTODO').val()==inputUID)
  292. {
  293. var newTodo = findEventInArray(globalEventList.todos[rid][inputUID].uid,false,globalCalTodo!=null ? globalCalTodo.repeatHash : null);
  294. if(newTodo!='')
  295. {
  296. if(globalCalTodo!=null)
  297. {
  298. if(isFromServer && $('#showTODO').val()==inputUID && ($('#repeatTodo').val()=="true" || $('#recurrenceIDTODO').val()!=''))
  299. {
  300. if(globalCalTodo.repeatHash != newTodo.repeatHash)
  301. {
  302. var name=globalCalTodo.title;
  303. showTodoForm({title: name, id:inputUID}, 'show','', true);
  304. $('#editAllTODO').css('visibility','hidden');
  305. $('#editFutureTODO').css('visibility','hidden');
  306. $('#editOnlyOneTODO').css('visibility','hidden');
  307. $('#repeatConfirmBoxContentTODO').html('<b>'+name+"</b> "+localization[globalInterfaceLanguage].repeatChangeTxt);
  308. $('#repeatConfirmBoxQuestionTODO').html(localization[globalInterfaceLanguage].repeatTodoChangeTxtClose);
  309. }
  310. else
  311. $('#todoList').fullCalendar('selectEvent');
  312. }
  313. else
  314. {
  315. if($($('.fc-view-todo .fc-list-day').find('.fc-event[data-repeat-hash="'+$('#todoList').fullCalendar('getView').selectedElement+'"]')).length>0)
  316. $('#todoList').fullCalendar('selectEvent',$($('.fc-view-todo .fc-list-day').find('.fc-event[data-repeat-hash="'+$('#todoList').fullCalendar('getView').selectedElement+'"]')));
  317. else
  318. showTodoForm(globalCalTodo, 'show');
  319. }
  320. }
  321. }
  322. else
  323. $('#CATodo').attr('style','display:none');
  324. }
  325. else
  326. $('#todoList').fullCalendar('selectEvent',null,true);
  327. }
  328. }
  329. }
  330. }
  331. }
  332. }
  333. }