1
1
/**
2
2
* This file is part of Radicale Server - Calendar Server
3
- * Copyright © 2017-2018 Unrud <unrud@outlook.com>
3
+ * Copyright © 2017-2024 Unrud <unrud@outlook.com>
4
4
*
5
5
* This program is free software: you can redistribute it and/or modify
6
6
* it under the terms of the GNU General Public License as published by
@@ -63,6 +63,7 @@ const CollectionType = {
63
63
CALENDAR : "CALENDAR" ,
64
64
JOURNAL : "JOURNAL" ,
65
65
TASKS : "TASKS" ,
66
+ WEBCAL : "WEBCAL" ,
66
67
is_subset : function ( a , b ) {
67
68
let components = a . split ( "_" ) ;
68
69
for ( let i = 0 ; i < components . length ; i ++ ) {
@@ -89,6 +90,9 @@ const CollectionType = {
89
90
if ( a . search ( this . TASKS ) !== - 1 || b . search ( this . TASKS ) !== - 1 ) {
90
91
union . push ( this . TASKS ) ;
91
92
}
93
+ if ( a . search ( this . WEBCAL ) !== - 1 || b . search ( this . WEBCAL ) !== - 1 ) {
94
+ union . push ( this . WEBCAL ) ;
95
+ }
92
96
return union . join ( "_" ) ;
93
97
}
94
98
} ;
@@ -102,12 +106,13 @@ const CollectionType = {
102
106
* @param {string } description
103
107
* @param {string } color
104
108
*/
105
- function Collection ( href , type , displayname , description , color ) {
109
+ function Collection ( href , type , displayname , description , color , source ) {
106
110
this . href = href ;
107
111
this . type = type ;
108
112
this . displayname = displayname ;
109
113
this . color = color ;
110
114
this . description = description ;
115
+ this . source = source ;
111
116
}
112
117
113
118
/**
@@ -183,18 +188,25 @@ function get_collections(user, password, collection, callback) {
183
188
let addressbookcolor_element = response . querySelector ( response_query + " > *|propstat > *|prop > *|addressbook-color" ) ;
184
189
let calendardesc_element = response . querySelector ( response_query + " > *|propstat > *|prop > *|calendar-description" ) ;
185
190
let addressbookdesc_element = response . querySelector ( response_query + " > *|propstat > *|prop > *|addressbook-description" ) ;
191
+ let webcalsource_element = response . querySelector ( response_query + " > *|propstat > *|prop > *|source" ) ;
186
192
let components_query = response_query + " > *|propstat > *|prop > *|supported-calendar-component-set" ;
187
193
let components_element = response . querySelector ( components_query ) ;
188
194
let href = href_element ? href_element . textContent : "" ;
189
195
let displayname = displayname_element ? displayname_element . textContent : "" ;
190
196
let type = "" ;
191
197
let color = "" ;
192
198
let description = "" ;
199
+ let source = "" ;
193
200
if ( resourcetype_element ) {
194
201
if ( resourcetype_element . querySelector ( resourcetype_query + " > *|addressbook" ) ) {
195
202
type = CollectionType . ADDRESSBOOK ;
196
203
color = addressbookcolor_element ? addressbookcolor_element . textContent : "" ;
197
204
description = addressbookdesc_element ? addressbookdesc_element . textContent : "" ;
205
+ } else if ( resourcetype_element . querySelector ( resourcetype_query + " > *|subscribed" ) ) {
206
+ type = CollectionType . union ( type , CollectionType . WEBCAL ) ;
207
+ source = webcalsource_element ? webcalsource_element . textContent : "" ;
208
+ color = calendarcolor_element ? calendarcolor_element . textContent : "" ;
209
+ description = calendardesc_element ? calendardesc_element . textContent : "" ;
198
210
} else if ( resourcetype_element . querySelector ( resourcetype_query + " > *|calendar" ) ) {
199
211
if ( components_element ) {
200
212
if ( components_element . querySelector ( components_query + " > *|comp[name=VEVENT]" ) ) {
@@ -221,7 +233,7 @@ function get_collections(user, password, collection, callback) {
221
233
}
222
234
}
223
235
if ( href . substr ( - 1 ) === "/" && href !== collection . href && type ) {
224
- collections . push ( new Collection ( href , type , displayname , description , sane_color ) ) ;
236
+ collections . push ( new Collection ( href , type , displayname , description , sane_color , source ) ) ;
225
237
}
226
238
}
227
239
collections . sort ( function ( a , b ) {
@@ -235,11 +247,15 @@ function get_collections(user, password, collection, callback) {
235
247
}
236
248
} ;
237
249
request . send ( '<?xml version="1.0" encoding="utf-8" ?>' +
238
- '<propfind xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" ' +
250
+ '<propfind ' +
251
+ 'xmlns="DAV:" ' +
252
+ 'xmlns:C="urn:ietf:params:xml:ns:caldav" ' +
239
253
'xmlns:CR="urn:ietf:params:xml:ns:carddav" ' +
254
+ 'xmlns:CS="http://calendarserver.org/ns/" ' +
240
255
'xmlns:I="http://apple.com/ns/ical/" ' +
241
256
'xmlns:INF="http://inf-it.com/ns/ab/" ' +
242
- 'xmlns:RADICALE="http://radicale.org/ns/">' +
257
+ 'xmlns:RADICALE="http://radicale.org/ns/"' +
258
+ '>' +
243
259
'<prop>' +
244
260
'<resourcetype />' +
245
261
'<RADICALE:displayname />' +
@@ -248,6 +264,7 @@ function get_collections(user, password, collection, callback) {
248
264
'<C:calendar-description />' +
249
265
'<C:supported-calendar-component-set />' +
250
266
'<CR:addressbook-description />' +
267
+ '<CS:source />' +
251
268
'</prop>' +
252
269
'</propfind>' ) ;
253
270
return request ;
@@ -329,12 +346,18 @@ function create_edit_collection(user, password, collection, create, callback) {
329
346
let addressbook_color = "" ;
330
347
let calendar_description = "" ;
331
348
let addressbook_description = "" ;
349
+ let calendar_source = "" ;
332
350
let resourcetype ;
333
351
let components = "" ;
334
352
if ( collection . type === CollectionType . ADDRESSBOOK ) {
335
353
addressbook_color = escape_xml ( collection . color + ( collection . color ? "ff" : "" ) ) ;
336
354
addressbook_description = escape_xml ( collection . description ) ;
337
355
resourcetype = '<CR:addressbook />' ;
356
+ } else if ( collection . type === CollectionType . WEBCAL ) {
357
+ calendar_color = escape_xml ( collection . color + ( collection . color ? "ff" : "" ) ) ;
358
+ calendar_description = escape_xml ( collection . description ) ;
359
+ resourcetype = '<CS:subscribed />' ;
360
+ calendar_source = collection . source ;
338
361
} else {
339
362
calendar_color = escape_xml ( collection . color + ( collection . color ? "ff" : "" ) ) ;
340
363
calendar_description = escape_xml ( collection . description ) ;
@@ -351,7 +374,7 @@ function create_edit_collection(user, password, collection, create, callback) {
351
374
}
352
375
let xml_request = create ? "mkcol" : "propertyupdate" ;
353
376
request . send ( '<?xml version="1.0" encoding="UTF-8" ?>' +
354
- '<' + xml_request + ' xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:CR="urn:ietf:params:xml:ns:carddav" xmlns:I="http://apple.com/ns/ical/" xmlns:INF="http://inf-it.com/ns/ab/">' +
377
+ '<' + xml_request + ' xmlns="DAV:" xmlns:D="DAV:" xmlns: C="urn:ietf:params:xml:ns:caldav" xmlns:CR="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/ " xmlns:I="http://apple.com/ns/ical/" xmlns:INF="http://inf-it.com/ns/ab/">' +
355
378
'<set>' +
356
379
'<prop>' +
357
380
( create ? '<resourcetype><collection />' + resourcetype + '</resourcetype>' : '' ) +
@@ -361,6 +384,7 @@ function create_edit_collection(user, password, collection, create, callback) {
361
384
( addressbook_color ? '<INF:addressbook-color>' + addressbook_color + '</INF:addressbook-color>' : '' ) +
362
385
( addressbook_description ? '<CR:addressbook-description>' + addressbook_description + '</CR:addressbook-description>' : '' ) +
363
386
( calendar_description ? '<C:calendar-description>' + calendar_description + '</C:calendar-description>' : '' ) +
387
+ ( calendar_source ? '<CS:source>' + calendar_source + '</CS:source>' : '' ) +
364
388
'</prop>' +
365
389
'</set>' +
366
390
( ! create ? ( '<remove>' +
@@ -692,7 +716,7 @@ function CollectionsScene(user, password, collection, onerror) {
692
716
if ( collection . color ) {
693
717
color_form . style . background = collection . color ;
694
718
}
695
- let possible_types = [ CollectionType . ADDRESSBOOK ] ;
719
+ let possible_types = [ CollectionType . ADDRESSBOOK , CollectionType . WEBCAL ] ;
696
720
[ CollectionType . CALENDAR , "" ] . forEach ( function ( e ) {
697
721
[ CollectionType . union ( e , CollectionType . JOURNAL ) , e ] . forEach ( function ( e ) {
698
722
[ CollectionType . union ( e , CollectionType . TASKS ) , e ] . forEach ( function ( e ) {
@@ -1005,12 +1029,19 @@ function CreateEditCollectionScene(user, password, collection) {
1005
1029
let title_form = edit ? html_scene . querySelector ( "[data-name=title]" ) : null ;
1006
1030
let error_form = html_scene . querySelector ( "[data-name=error]" ) ;
1007
1031
let displayname_form = html_scene . querySelector ( "[data-name=displayname]" ) ;
1032
+ let displayname_label = html_scene . querySelector ( "label[for=displayname]" ) ;
1008
1033
let description_form = html_scene . querySelector ( "[data-name=description]" ) ;
1034
+ let description_label = html_scene . querySelector ( "label[for=description]" ) ;
1035
+ let source_form = html_scene . querySelector ( "[data-name=source]" ) ;
1036
+ let source_label = html_scene . querySelector ( "label[for=source]" ) ;
1009
1037
let type_form = html_scene . querySelector ( "[data-name=type]" ) ;
1038
+ let type_label = html_scene . querySelector ( "label[for=type]" ) ;
1010
1039
let color_form = html_scene . querySelector ( "[data-name=color]" ) ;
1040
+ let color_label = html_scene . querySelector ( "label[for=color]" ) ;
1011
1041
let submit_btn = html_scene . querySelector ( "[data-name=submit]" ) ;
1012
1042
let cancel_btn = html_scene . querySelector ( "[data-name=cancel]" ) ;
1013
1043
1044
+
1014
1045
/** @type {?number } */ let scene_index = null ;
1015
1046
/** @type {?XMLHttpRequest } */ let create_edit_req = null ;
1016
1047
let error = "" ;
@@ -1019,6 +1050,7 @@ function CreateEditCollectionScene(user, password, collection) {
1019
1050
let href = edit ? collection . href : collection . href + random_uuid ( ) + "/" ;
1020
1051
let displayname = edit ? collection . displayname : "" ;
1021
1052
let description = edit ? collection . description : "" ;
1053
+ let source = edit ? collection . source : "" ;
1022
1054
let type = edit ? collection . type : CollectionType . CALENDAR_JOURNAL_TASKS ;
1023
1055
let color = edit && collection . color ? collection . color : "#" + random_hex ( 6 ) ;
1024
1056
@@ -1038,20 +1070,25 @@ function CreateEditCollectionScene(user, password, collection) {
1038
1070
function read_form ( ) {
1039
1071
displayname = displayname_form . value ;
1040
1072
description = description_form . value ;
1073
+ source = source_form . value ;
1041
1074
type = type_form . value ;
1042
1075
color = color_form . value ;
1043
1076
}
1044
1077
1045
1078
function fill_form ( ) {
1046
1079
displayname_form . value = displayname ;
1047
1080
description_form . value = description ;
1081
+ source_form . value = source ;
1048
1082
type_form . value = type ;
1049
1083
color_form . value = color ;
1050
1084
if ( error ) {
1051
1085
error_form . textContent = "Error: " + error ;
1052
1086
error_form . classList . remove ( "hidden" ) ;
1053
1087
}
1054
1088
error_form . classList . add ( "hidden" ) ;
1089
+
1090
+ onTypeChange ( ) ;
1091
+ type_form . addEventListener ( "change" , onTypeChange ) ;
1055
1092
}
1056
1093
1057
1094
function onsubmit ( ) {
@@ -1069,7 +1106,7 @@ function CreateEditCollectionScene(user, password, collection) {
1069
1106
}
1070
1107
let loading_scene = new LoadingScene ( ) ;
1071
1108
push_scene ( loading_scene ) ;
1072
- let collection = new Collection ( href , type , displayname , description , sane_color ) ;
1109
+ let collection = new Collection ( href , type , displayname , description , sane_color , source ) ;
1073
1110
let callback = function ( error1 ) {
1074
1111
if ( scene_index === null ) {
1075
1112
return ;
@@ -1102,6 +1139,16 @@ function CreateEditCollectionScene(user, password, collection) {
1102
1139
return false ;
1103
1140
}
1104
1141
1142
+ function onTypeChange ( e ) {
1143
+ if ( type_form . value == CollectionType . WEBCAL ) {
1144
+ source_label . classList . remove ( "hidden" ) ;
1145
+ source_form . classList . remove ( "hidden" ) ;
1146
+ } else {
1147
+ source_label . classList . add ( "hidden" ) ;
1148
+ source_form . classList . add ( "hidden" ) ;
1149
+ }
1150
+ }
1151
+
1105
1152
this . show = function ( ) {
1106
1153
this . release ( ) ;
1107
1154
scene_index = scene_stack . length - 1 ;
0 commit comments