add-to-calendar-button 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -14
- package/assets/css/atcb.css +1 -1
- package/npm_dist/atcb_npm.js +94 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -87,9 +87,9 @@ Mind that with Angular, you might need to escape the { with `{{ '{' }}` and } wi
|
|
|
87
87
|
```html
|
|
88
88
|
<div class="atcb" style="display:none;">
|
|
89
89
|
{
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
90
|
+
"name":"Add the title of your event",
|
|
91
|
+
"startDate":"02-21-2022",
|
|
92
|
+
"endDate":"03-24-2022",
|
|
93
93
|
"options":[
|
|
94
94
|
"Google"
|
|
95
95
|
]
|
|
@@ -97,19 +97,19 @@ Mind that with Angular, you might need to escape the { with `{{ '{' }}` and } wi
|
|
|
97
97
|
</div>
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
### Full structure
|
|
100
|
+
### Full structure (without schema.org markup)
|
|
101
101
|
|
|
102
102
|
```html
|
|
103
103
|
<div class="atcb" style="display:none;">
|
|
104
104
|
{
|
|
105
|
-
"
|
|
106
|
-
"title":"Add the title of your event",
|
|
105
|
+
"name":"Add the title of your event",
|
|
107
106
|
"description":"A nice description does not hurt",
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
107
|
+
"startDate":"02-21-2022",
|
|
108
|
+
"endDate":"03-24-2022",
|
|
109
|
+
"startTime":"10:13",
|
|
110
|
+
"endTime":"17:57",
|
|
112
111
|
"location":"Somewhere over the rainbow",
|
|
112
|
+
"label":"Add to Calendar",
|
|
113
113
|
"options":[
|
|
114
114
|
"Apple",
|
|
115
115
|
"Google",
|
|
@@ -125,6 +125,41 @@ Mind that with Angular, you might need to escape the { with `{{ '{' }}` and } wi
|
|
|
125
125
|
}
|
|
126
126
|
</div>
|
|
127
127
|
```
|
|
128
|
+
|
|
129
|
+
### Full structure (with schema.org markup)
|
|
130
|
+
You can save on the `style="display:none;"`, but mind that you should not use dynamic dates (e.g. "today" or "+1") here!
|
|
131
|
+
You can use startTime and endTime in the event block, but it is recommended to rather add it to startDate and endDate with "T" as delimiter here.
|
|
132
|
+
|
|
133
|
+
```html
|
|
134
|
+
<div class="atcb">
|
|
135
|
+
<script type="application/ld+json">
|
|
136
|
+
{
|
|
137
|
+
"event": {
|
|
138
|
+
"@context":"https://schema.org",
|
|
139
|
+
"@type":"Event",
|
|
140
|
+
"name":"Add the title of your event",
|
|
141
|
+
"description":"A nice description does not hurt",
|
|
142
|
+
"startDate":"02-21-2022T10:13",
|
|
143
|
+
"endDate":"03-24-2022T17:57",
|
|
144
|
+
"location":"Somewhere over the rainbow"
|
|
145
|
+
},
|
|
146
|
+
"label":"Add to Calendar",
|
|
147
|
+
"options":[
|
|
148
|
+
"Apple",
|
|
149
|
+
"Google",
|
|
150
|
+
"iCal",
|
|
151
|
+
"Microsoft365",
|
|
152
|
+
"Outlook.com",
|
|
153
|
+
"Yahoo"
|
|
154
|
+
],
|
|
155
|
+
"timeZone":"Europe/Berlin",
|
|
156
|
+
"timeZoneOffset":"+01:00",
|
|
157
|
+
"trigger":"click",
|
|
158
|
+
"iCalFileName":"Reminder-Event"
|
|
159
|
+
}
|
|
160
|
+
</script>
|
|
161
|
+
</div>
|
|
162
|
+
```
|
|
128
163
|
|
|
129
164
|
|
|
130
165
|
### Important information and hidden features
|
|
@@ -164,10 +199,11 @@ The code is available under the [GPU 3.0 license](LICENSE.txt).
|
|
|
164
199
|
|
|
165
200
|
## Changelog (without bug fixes)
|
|
166
201
|
|
|
167
|
-
* v1.
|
|
168
|
-
* v1.
|
|
169
|
-
* v1.
|
|
170
|
-
* v1.
|
|
202
|
+
* v1.4 : schema.org support (also changed some keys in the JSON!)
|
|
203
|
+
* v1.3 : new license (MIT with “Commons Clause”)
|
|
204
|
+
* v1.2 : inline and line break support
|
|
205
|
+
* v1.1 : npm functionality
|
|
206
|
+
* v1.0 : initial release
|
|
171
207
|
|
|
172
208
|
|
|
173
209
|
## Kudos go to
|
package/assets/css/atcb.css
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Add-to-Calendar Button
|
|
4
4
|
* ++++++++++++++++++++++
|
|
5
5
|
*
|
|
6
|
-
* Version: 1.
|
|
6
|
+
* Version: 1.4.0
|
|
7
7
|
* Creator: Jens Kuerschner (https://jenskuerschner.de)
|
|
8
8
|
* Project: https://github.com/jekuer/add-to-calendar-button
|
|
9
9
|
* License: MIT with “Commons Clause” License Condition v1.0
|
package/npm_dist/atcb_npm.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Add-to-Calendar Button
|
|
4
4
|
* ++++++++++++++++++++++
|
|
5
5
|
*/
|
|
6
|
-
const atcbVersion = '1.
|
|
6
|
+
const atcbVersion = '1.4.0';
|
|
7
7
|
/* Creator: Jens Kuerschner (https://jenskuerschner.de)
|
|
8
8
|
* Project: https://github.com/jekuer/add-to-calendar-button
|
|
9
9
|
* License: MIT with “Commons Clause” License Condition v1.0
|
|
@@ -29,13 +29,29 @@ function atcb_init() {
|
|
|
29
29
|
if (atcButtons[i].classList.contains('atcb_initialized')) {
|
|
30
30
|
continue;
|
|
31
31
|
}
|
|
32
|
+
let atcbConfig;
|
|
33
|
+
// check if schema.org markup is present
|
|
34
|
+
let schema = atcButtons[i].querySelector('script');
|
|
32
35
|
// get their JSON content first
|
|
33
|
-
|
|
36
|
+
if (schema && schema.innerHTML) {
|
|
37
|
+
// get schema.org event markup and flatten the event block
|
|
38
|
+
atcbConfig = JSON.parse(schema.innerHTML);
|
|
39
|
+
atcbConfig = atcb_clean_schema_json(atcbConfig);
|
|
40
|
+
// set flag to not delete HTML content later
|
|
41
|
+
atcbConfig['deleteJSON'] = false;
|
|
42
|
+
} else {
|
|
43
|
+
// get JSON from HTML block
|
|
44
|
+
atcbConfig = JSON.parse(atcButtons[i].innerHTML);
|
|
45
|
+
// set flag to delete HTML content later
|
|
46
|
+
atcbConfig['deleteJSON'] = true;
|
|
47
|
+
}
|
|
48
|
+
// rewrite config for backwards compatibility - you can remove this, if you did not use this script before v1.4.0.
|
|
49
|
+
atcbConfig = atcb_rewrite_config(atcbConfig);
|
|
34
50
|
// check, if all required data is available
|
|
35
51
|
if (atcb_check_required(atcbConfig)) {
|
|
36
52
|
// calculate the real date values in case that there are some special rules included (e.g. adding days dynamically)
|
|
37
|
-
atcbConfig['
|
|
38
|
-
atcbConfig['
|
|
53
|
+
atcbConfig['startDate'] = atcb_date_calculation(atcbConfig['startDate']);
|
|
54
|
+
atcbConfig['endDate'] = atcb_date_calculation(atcbConfig['endDate']);
|
|
39
55
|
// validate the JSON ...
|
|
40
56
|
if (atcb_validate(atcbConfig)) {
|
|
41
57
|
// ... and generate the button on success
|
|
@@ -48,6 +64,51 @@ function atcb_init() {
|
|
|
48
64
|
|
|
49
65
|
|
|
50
66
|
|
|
67
|
+
// CLEAN/NORMALIZE JSON FROM SCHEMA.ORG MARKUP
|
|
68
|
+
function atcb_clean_schema_json(atcbConfig) {
|
|
69
|
+
Object.keys(atcbConfig['event']).forEach(key => {
|
|
70
|
+
// move entries one level up, but skip schema types
|
|
71
|
+
if (key.charAt(0) !== '@') {
|
|
72
|
+
atcbConfig[key] = atcbConfig['event'][key];
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
// clean schema date+time format
|
|
76
|
+
const endpoints = ['start', 'end'];
|
|
77
|
+
endpoints.forEach(function(point) {
|
|
78
|
+
if (atcbConfig[point + 'Date'] != null) {
|
|
79
|
+
let tmpSplitStartDate = atcbConfig[point + 'Date'].split('T');
|
|
80
|
+
if (tmpSplitStartDate[1] != null) {
|
|
81
|
+
atcbConfig[point + 'Date'] = tmpSplitStartDate[0];
|
|
82
|
+
atcbConfig[point + 'Time'] = tmpSplitStartDate[1];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
// drop the event block and return
|
|
87
|
+
delete atcbConfig.event;
|
|
88
|
+
return atcbConfig;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
// BACKWARDS COMPATIBILITY REWRITE - you can remove this, if you did not use this script before v1.4.0.
|
|
94
|
+
function atcb_rewrite_config(atcbConfig) {
|
|
95
|
+
const keyChanges = {
|
|
96
|
+
'title': 'name',
|
|
97
|
+
'dateStart': 'startDate',
|
|
98
|
+
'dateEnd': 'endDate',
|
|
99
|
+
'timeStart': 'startTime',
|
|
100
|
+
'timeEnd': 'endTime',
|
|
101
|
+
};
|
|
102
|
+
Object.keys(keyChanges).forEach(key => {
|
|
103
|
+
if (atcbConfig[keyChanges[key]] == null && atcbConfig[key] != null) {
|
|
104
|
+
atcbConfig[keyChanges[key]] = atcbConfig[key];
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
return atcbConfig;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
51
112
|
// CHECK FOR REQUIRED FIELDS
|
|
52
113
|
function atcb_check_required(data) {
|
|
53
114
|
// check for at least 1 option
|
|
@@ -56,7 +117,7 @@ function atcb_check_required(data) {
|
|
|
56
117
|
return false;
|
|
57
118
|
}
|
|
58
119
|
// check for min required data (without "options")
|
|
59
|
-
const requiredField = ['
|
|
120
|
+
const requiredField = ['name', 'startDate', 'endDate']
|
|
60
121
|
return requiredField.every(function(field) {
|
|
61
122
|
if (data[field] == null || data[field] == "") {
|
|
62
123
|
console.log("add-to-calendar button generation failed: required setting missing [" + field + "]");
|
|
@@ -101,7 +162,7 @@ function atcb_validate(data) {
|
|
|
101
162
|
return false;
|
|
102
163
|
}
|
|
103
164
|
// validate date
|
|
104
|
-
const dates = ['
|
|
165
|
+
const dates = ['startDate', 'endDate'];
|
|
105
166
|
let newDate = dates;
|
|
106
167
|
if (!dates.every(function(date) {
|
|
107
168
|
const dateParts = data[date].split('-');
|
|
@@ -115,7 +176,7 @@ function atcb_validate(data) {
|
|
|
115
176
|
return false;
|
|
116
177
|
}
|
|
117
178
|
// validate time
|
|
118
|
-
const times = ['
|
|
179
|
+
const times = ['startTime', 'endTime'];
|
|
119
180
|
if (!times.every(function(time) {
|
|
120
181
|
if (data[time] != null) {
|
|
121
182
|
const timeParts = data[time].split(':');
|
|
@@ -133,23 +194,23 @@ function atcb_validate(data) {
|
|
|
133
194
|
return false;
|
|
134
195
|
}
|
|
135
196
|
// update the date with the time for further validation steps
|
|
136
|
-
if (time == '
|
|
137
|
-
newDate['
|
|
197
|
+
if (time == 'startTime') {
|
|
198
|
+
newDate['startDate'] = new Date(newDate['startDate'].getTime() + (timeParts[0] * 3600000) + (timeParts[1] * 60000))
|
|
138
199
|
}
|
|
139
|
-
if (time == '
|
|
140
|
-
newDate['
|
|
200
|
+
if (time == 'endTime') {
|
|
201
|
+
newDate['endDate'] = new Date(newDate['endDate'].getTime() + (timeParts[0] * 3600000) + (timeParts[1] * 60000))
|
|
141
202
|
}
|
|
142
203
|
}
|
|
143
204
|
return true;
|
|
144
205
|
})) {
|
|
145
206
|
return false;
|
|
146
207
|
}
|
|
147
|
-
if ((data['
|
|
208
|
+
if ((data['startTime'] != null && data['endTime'] == null) || (data['startTime'] == null && data['endTime'] != null)) {
|
|
148
209
|
console.log("add-to-calendar button generation failed: if you set a starting time, you also need to define an end time");
|
|
149
210
|
return false;
|
|
150
211
|
}
|
|
151
212
|
// validate whether end is not before start
|
|
152
|
-
if (newDate['
|
|
213
|
+
if (newDate['endDate'] < newDate['startDate']) {
|
|
153
214
|
console.log("add-to-calendar button generation failed: end date before start date");
|
|
154
215
|
return false;
|
|
155
216
|
}
|
|
@@ -161,8 +222,10 @@ function atcb_validate(data) {
|
|
|
161
222
|
|
|
162
223
|
// GENERATE THE ACTUAL BUTTON
|
|
163
224
|
function atcb_generate(button, buttonId, data) {
|
|
164
|
-
// clean the placeholder
|
|
165
|
-
|
|
225
|
+
// clean the placeholder, if flagged that way
|
|
226
|
+
if (data['deleteJSON']) {
|
|
227
|
+
button.innerHTML = '';
|
|
228
|
+
}
|
|
166
229
|
// generate the wrapper div
|
|
167
230
|
let buttonTriggerWrapper = document.createElement('div');
|
|
168
231
|
buttonTriggerWrapper.classList.add('atcb_button_wrapper');
|
|
@@ -335,8 +398,8 @@ function atcb_generate_google(data) {
|
|
|
335
398
|
if (data['location'] != null && data['location'] != '') {
|
|
336
399
|
url += '&location=' + encodeURIComponent(data['location']);
|
|
337
400
|
}
|
|
338
|
-
if (data['
|
|
339
|
-
url += '&text=' + encodeURIComponent(data['
|
|
401
|
+
if (data['name'] != null && data['name'] != '') {
|
|
402
|
+
url += '&text=' + encodeURIComponent(data['name']);
|
|
340
403
|
}
|
|
341
404
|
window.open(url, '_blank').focus();
|
|
342
405
|
}
|
|
@@ -360,8 +423,8 @@ function atcb_generate_yahoo(data) {
|
|
|
360
423
|
if (data['location'] != null && data['location'] != '') {
|
|
361
424
|
url += '&in_loc=' + encodeURIComponent(data['location']);
|
|
362
425
|
}
|
|
363
|
-
if (data['
|
|
364
|
-
url += '&title=' + encodeURIComponent(data['
|
|
426
|
+
if (data['name'] != null && data['name'] != '') {
|
|
427
|
+
url += '&title=' + encodeURIComponent(data['name']);
|
|
365
428
|
}
|
|
366
429
|
window.open(url, '_blank').focus();
|
|
367
430
|
}
|
|
@@ -391,8 +454,8 @@ function atcb_generate_microsoft(data, type = '365') {
|
|
|
391
454
|
if (data['location'] != null && data['location'] != '') {
|
|
392
455
|
url += '&location=' + encodeURIComponent(data['location']);
|
|
393
456
|
}
|
|
394
|
-
if (data['
|
|
395
|
-
url += '&subject=' + encodeURIComponent(data['
|
|
457
|
+
if (data['name'] != null && data['name'] != '') {
|
|
458
|
+
url += '&subject=' + encodeURIComponent(data['name']);
|
|
396
459
|
}
|
|
397
460
|
window.open(url, '_blank').focus();
|
|
398
461
|
}
|
|
@@ -417,7 +480,7 @@ function atcb_generate_ical(data) {
|
|
|
417
480
|
"DTSTART" + timeslot + ":" + formattedDate['start'],
|
|
418
481
|
"DTEND" + timeslot + ":" + formattedDate['end'],
|
|
419
482
|
"DESCRIPTION:" + data['description'].replace(/\n/g, '\\n'),
|
|
420
|
-
"SUMMARY:" + data['
|
|
483
|
+
"SUMMARY:" + data['name'],
|
|
421
484
|
"LOCATION:" + data['location'],
|
|
422
485
|
"STATUS:CONFIRMED",
|
|
423
486
|
"LAST-MODIFIED:" + now,
|
|
@@ -449,17 +512,17 @@ function atcb_generate_ical(data) {
|
|
|
449
512
|
|
|
450
513
|
// SHARED FUNCTION TO GENERATE A TIME STRING
|
|
451
514
|
function atcb_generate_time(data, style = 'delimiters', targetCal = 'general') {
|
|
452
|
-
let
|
|
453
|
-
let
|
|
515
|
+
let startDate = data['startDate'].split('-');
|
|
516
|
+
let endDate = data['endDate'].split('-');
|
|
454
517
|
let start = '';
|
|
455
518
|
let end = '';
|
|
456
519
|
let allday = false;
|
|
457
|
-
if (data['
|
|
520
|
+
if (data['startTime'] != null && data['endTime'] != null) {
|
|
458
521
|
// Adjust for timezone, if set (see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for either the TZ name or the offset)
|
|
459
522
|
if (data['timeZoneOffset'] != null && data['timeZoneOffset'] != '') {
|
|
460
523
|
// if we have a timezone offset given, consider it
|
|
461
|
-
start = new Date(
|
|
462
|
-
end = new Date(
|
|
524
|
+
start = new Date( startDate[2] + '-' + startDate[0] + '-' + startDate[1] + 'T' + data['startTime'] + ':00.000' + data['timeZoneOffset'] );
|
|
525
|
+
end = new Date( endDate[2] + '-' + endDate[0] + '-' + endDate[1] + 'T' + data['endTime'] + ':00.000' + data['timeZoneOffset'] );
|
|
463
526
|
start = start.toISOString().replace('.000', '');
|
|
464
527
|
end = end.toISOString().replace('.000', '');
|
|
465
528
|
if (style == 'clean') {
|
|
@@ -468,8 +531,8 @@ function atcb_generate_time(data, style = 'delimiters', targetCal = 'general') {
|
|
|
468
531
|
}
|
|
469
532
|
} else {
|
|
470
533
|
// if there is no offset, we prepare the time, assuming it is UTC formatted
|
|
471
|
-
start = new Date(
|
|
472
|
-
end = new Date(
|
|
534
|
+
start = new Date( startDate[2] + '-' + startDate[0] + '-' + startDate[1] + 'T' + data['startTime'] + ':00.000+00:00' );
|
|
535
|
+
end = new Date( endDate[2] + '-' + endDate[0] + '-' + endDate[1] + 'T' + data['endTime'] + ':00.000+00:00' );
|
|
473
536
|
if (data['timeZone'] != null && data['timeZone'] != '') {
|
|
474
537
|
// if a timezone is given, we adjust dynamically with the modern toLocaleString function
|
|
475
538
|
let utcDate = new Date(start.toLocaleString('en-US', { timeZone: "UTC" }));
|
|
@@ -487,10 +550,10 @@ function atcb_generate_time(data, style = 'delimiters', targetCal = 'general') {
|
|
|
487
550
|
}
|
|
488
551
|
} else { // would be an allday event then
|
|
489
552
|
allday = true;
|
|
490
|
-
start = new Date(
|
|
553
|
+
start = new Date( startDate[2], startDate[0] - 1, startDate[1]);
|
|
491
554
|
start.setDate(start.getDate() + 1); // increment the day by 1
|
|
492
555
|
let breakStart = start.toISOString().split('T');
|
|
493
|
-
end = new Date(
|
|
556
|
+
end = new Date( endDate[2], endDate[0] - 1, endDate[1]);
|
|
494
557
|
if (targetCal == 'google' || targetCal == 'microsoft' || targetCal == 'ical') {
|
|
495
558
|
end.setDate(end.getDate() + 2); // increment the day by 2 for Google Calendar, iCal and Outlook
|
|
496
559
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "add-to-calendar-button",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A convenient JavaScript snippet, which lets you create beautiful buttons, where people can add events to their calendars.",
|
|
5
5
|
"main": "npm_dist/atcb_npm.js",
|
|
6
6
|
"types": "index.d.ts",
|