@stacksjs/calendar-api 0.61.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 +60 -0
- package/dist/index.js +642 -0
- package/package.json +53 -0
- package/src/generators/google.ts +34 -0
- package/src/generators/ics.ts +74 -0
- package/src/generators/weboutlook.ts +39 -0
- package/src/generators/yahoo.ts +35 -0
- package/src/index.ts +1 -0
- package/src/links.ts +37 -0
- package/src/types.ts +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Stacks Calendar
|
|
2
|
+
|
|
3
|
+
Stacks Calendar is a framework that allows you to easily interact with calendar APIs.
|
|
4
|
+
|
|
5
|
+
## โ๏ธ Features
|
|
6
|
+
|
|
7
|
+
- ๐
Calendar APIs
|
|
8
|
+
|
|
9
|
+
## ๐ค Usage
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bun install @stacksjs/calendar
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
You may now use it in your project:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import * as calendar from '@stacksjs/calendar'
|
|
19
|
+
|
|
20
|
+
// ...
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Learn more in the docs.
|
|
24
|
+
|
|
25
|
+
## ๐งช Testing
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bun test
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## ๐ Changelog
|
|
32
|
+
|
|
33
|
+
Please see our [releases](https://github.com/stacksjs/stacks/releases) page for more information on what has changed recently.
|
|
34
|
+
|
|
35
|
+
## ๐ Contributing
|
|
36
|
+
|
|
37
|
+
Please review the [Contributing Guide](https://github.com/stacksjs/contributing) for details.
|
|
38
|
+
|
|
39
|
+
## ๐ Community
|
|
40
|
+
|
|
41
|
+
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
|
|
42
|
+
|
|
43
|
+
[Discussions on GitHub](https://github.com/stacksjs/stacks/discussions)
|
|
44
|
+
|
|
45
|
+
For casual chit-chat with others using this package:
|
|
46
|
+
|
|
47
|
+
[Join the Stacks Discord Server](https://discord.gg/stacksjs)
|
|
48
|
+
|
|
49
|
+
## ๐๐ผ Credits
|
|
50
|
+
|
|
51
|
+
Many thanks to the following core technologies & people who have contributed to this package:
|
|
52
|
+
|
|
53
|
+
- [Chris Breuer](https://github.com/chrisbbreuer)
|
|
54
|
+
- [All Contributors](../../contributors)
|
|
55
|
+
|
|
56
|
+
## ๐ License
|
|
57
|
+
|
|
58
|
+
The MIT License (MIT). Please see [LICENSE](https://github.com/stacksjs/stacks/tree/main/LICENSE.md) for more information.
|
|
59
|
+
|
|
60
|
+
Made with ๐
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
19
|
+
|
|
20
|
+
// ../../../../node_modules/crypto-js/core.js
|
|
21
|
+
var require_core = __commonJS((exports, module) => {
|
|
22
|
+
(function(root, factory) {
|
|
23
|
+
if (typeof exports === "object") {
|
|
24
|
+
module.exports = exports = factory();
|
|
25
|
+
} else if (typeof define === "function" && define.amd) {
|
|
26
|
+
define([], factory);
|
|
27
|
+
} else {
|
|
28
|
+
root.CryptoJS = factory();
|
|
29
|
+
}
|
|
30
|
+
})(exports, function() {
|
|
31
|
+
var CryptoJS = CryptoJS || function(Math2, undefined2) {
|
|
32
|
+
var crypto;
|
|
33
|
+
if (typeof window !== "undefined" && window.crypto) {
|
|
34
|
+
crypto = window.crypto;
|
|
35
|
+
}
|
|
36
|
+
if (typeof self !== "undefined" && self.crypto) {
|
|
37
|
+
crypto = self.crypto;
|
|
38
|
+
}
|
|
39
|
+
if (typeof globalThis !== "undefined" && globalThis.crypto) {
|
|
40
|
+
crypto = globalThis.crypto;
|
|
41
|
+
}
|
|
42
|
+
if (!crypto && typeof window !== "undefined" && window.msCrypto) {
|
|
43
|
+
crypto = window.msCrypto;
|
|
44
|
+
}
|
|
45
|
+
if (!crypto && typeof global !== "undefined" && global.crypto) {
|
|
46
|
+
crypto = global.crypto;
|
|
47
|
+
}
|
|
48
|
+
if (!crypto && typeof import.meta.require === "function") {
|
|
49
|
+
try {
|
|
50
|
+
crypto = import.meta.require("crypto");
|
|
51
|
+
} catch (err) {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
var cryptoSecureRandomInt = function() {
|
|
55
|
+
if (crypto) {
|
|
56
|
+
if (typeof crypto.getRandomValues === "function") {
|
|
57
|
+
try {
|
|
58
|
+
return crypto.getRandomValues(new Uint32Array(1))[0];
|
|
59
|
+
} catch (err) {
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (typeof crypto.randomBytes === "function") {
|
|
63
|
+
try {
|
|
64
|
+
return crypto.randomBytes(4).readInt32LE();
|
|
65
|
+
} catch (err) {
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
throw new Error("Native crypto module could not be used to get secure random number.");
|
|
70
|
+
};
|
|
71
|
+
var create = Object.create || function() {
|
|
72
|
+
function F() {
|
|
73
|
+
}
|
|
74
|
+
return function(obj) {
|
|
75
|
+
var subtype;
|
|
76
|
+
F.prototype = obj;
|
|
77
|
+
subtype = new F;
|
|
78
|
+
F.prototype = null;
|
|
79
|
+
return subtype;
|
|
80
|
+
};
|
|
81
|
+
}();
|
|
82
|
+
var C = {};
|
|
83
|
+
var C_lib = C.lib = {};
|
|
84
|
+
var Base = C_lib.Base = function() {
|
|
85
|
+
return {
|
|
86
|
+
extend: function(overrides) {
|
|
87
|
+
var subtype = create(this);
|
|
88
|
+
if (overrides) {
|
|
89
|
+
subtype.mixIn(overrides);
|
|
90
|
+
}
|
|
91
|
+
if (!subtype.hasOwnProperty("init") || this.init === subtype.init) {
|
|
92
|
+
subtype.init = function() {
|
|
93
|
+
subtype.$super.init.apply(this, arguments);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
subtype.init.prototype = subtype;
|
|
97
|
+
subtype.$super = this;
|
|
98
|
+
return subtype;
|
|
99
|
+
},
|
|
100
|
+
create: function() {
|
|
101
|
+
var instance = this.extend();
|
|
102
|
+
instance.init.apply(instance, arguments);
|
|
103
|
+
return instance;
|
|
104
|
+
},
|
|
105
|
+
init: function() {
|
|
106
|
+
},
|
|
107
|
+
mixIn: function(properties) {
|
|
108
|
+
for (var propertyName in properties) {
|
|
109
|
+
if (properties.hasOwnProperty(propertyName)) {
|
|
110
|
+
this[propertyName] = properties[propertyName];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (properties.hasOwnProperty("toString")) {
|
|
114
|
+
this.toString = properties.toString;
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
clone: function() {
|
|
118
|
+
return this.init.prototype.extend(this);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}();
|
|
122
|
+
var WordArray = C_lib.WordArray = Base.extend({
|
|
123
|
+
init: function(words, sigBytes) {
|
|
124
|
+
words = this.words = words || [];
|
|
125
|
+
if (sigBytes != undefined2) {
|
|
126
|
+
this.sigBytes = sigBytes;
|
|
127
|
+
} else {
|
|
128
|
+
this.sigBytes = words.length * 4;
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
toString: function(encoder) {
|
|
132
|
+
return (encoder || Hex).stringify(this);
|
|
133
|
+
},
|
|
134
|
+
concat: function(wordArray) {
|
|
135
|
+
var thisWords = this.words;
|
|
136
|
+
var thatWords = wordArray.words;
|
|
137
|
+
var thisSigBytes = this.sigBytes;
|
|
138
|
+
var thatSigBytes = wordArray.sigBytes;
|
|
139
|
+
this.clamp();
|
|
140
|
+
if (thisSigBytes % 4) {
|
|
141
|
+
for (var i = 0;i < thatSigBytes; i++) {
|
|
142
|
+
var thatByte = thatWords[i >>> 2] >>> 24 - i % 4 * 8 & 255;
|
|
143
|
+
thisWords[thisSigBytes + i >>> 2] |= thatByte << 24 - (thisSigBytes + i) % 4 * 8;
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
for (var j = 0;j < thatSigBytes; j += 4) {
|
|
147
|
+
thisWords[thisSigBytes + j >>> 2] = thatWords[j >>> 2];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
this.sigBytes += thatSigBytes;
|
|
151
|
+
return this;
|
|
152
|
+
},
|
|
153
|
+
clamp: function() {
|
|
154
|
+
var words = this.words;
|
|
155
|
+
var sigBytes = this.sigBytes;
|
|
156
|
+
words[sigBytes >>> 2] &= 4294967295 << 32 - sigBytes % 4 * 8;
|
|
157
|
+
words.length = Math2.ceil(sigBytes / 4);
|
|
158
|
+
},
|
|
159
|
+
clone: function() {
|
|
160
|
+
var clone = Base.clone.call(this);
|
|
161
|
+
clone.words = this.words.slice(0);
|
|
162
|
+
return clone;
|
|
163
|
+
},
|
|
164
|
+
random: function(nBytes) {
|
|
165
|
+
var words = [];
|
|
166
|
+
for (var i = 0;i < nBytes; i += 4) {
|
|
167
|
+
words.push(cryptoSecureRandomInt());
|
|
168
|
+
}
|
|
169
|
+
return new WordArray.init(words, nBytes);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
var C_enc = C.enc = {};
|
|
173
|
+
var Hex = C_enc.Hex = {
|
|
174
|
+
stringify: function(wordArray) {
|
|
175
|
+
var words = wordArray.words;
|
|
176
|
+
var sigBytes = wordArray.sigBytes;
|
|
177
|
+
var hexChars = [];
|
|
178
|
+
for (var i = 0;i < sigBytes; i++) {
|
|
179
|
+
var bite = words[i >>> 2] >>> 24 - i % 4 * 8 & 255;
|
|
180
|
+
hexChars.push((bite >>> 4).toString(16));
|
|
181
|
+
hexChars.push((bite & 15).toString(16));
|
|
182
|
+
}
|
|
183
|
+
return hexChars.join("");
|
|
184
|
+
},
|
|
185
|
+
parse: function(hexStr) {
|
|
186
|
+
var hexStrLength = hexStr.length;
|
|
187
|
+
var words = [];
|
|
188
|
+
for (var i = 0;i < hexStrLength; i += 2) {
|
|
189
|
+
words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << 24 - i % 8 * 4;
|
|
190
|
+
}
|
|
191
|
+
return new WordArray.init(words, hexStrLength / 2);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
var Latin1 = C_enc.Latin1 = {
|
|
195
|
+
stringify: function(wordArray) {
|
|
196
|
+
var words = wordArray.words;
|
|
197
|
+
var sigBytes = wordArray.sigBytes;
|
|
198
|
+
var latin1Chars = [];
|
|
199
|
+
for (var i = 0;i < sigBytes; i++) {
|
|
200
|
+
var bite = words[i >>> 2] >>> 24 - i % 4 * 8 & 255;
|
|
201
|
+
latin1Chars.push(String.fromCharCode(bite));
|
|
202
|
+
}
|
|
203
|
+
return latin1Chars.join("");
|
|
204
|
+
},
|
|
205
|
+
parse: function(latin1Str) {
|
|
206
|
+
var latin1StrLength = latin1Str.length;
|
|
207
|
+
var words = [];
|
|
208
|
+
for (var i = 0;i < latin1StrLength; i++) {
|
|
209
|
+
words[i >>> 2] |= (latin1Str.charCodeAt(i) & 255) << 24 - i % 4 * 8;
|
|
210
|
+
}
|
|
211
|
+
return new WordArray.init(words, latin1StrLength);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
var Utf8 = C_enc.Utf8 = {
|
|
215
|
+
stringify: function(wordArray) {
|
|
216
|
+
try {
|
|
217
|
+
return decodeURIComponent(escape(Latin1.stringify(wordArray)));
|
|
218
|
+
} catch (e) {
|
|
219
|
+
throw new Error("Malformed UTF-8 data");
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
parse: function(utf8Str) {
|
|
223
|
+
return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
|
|
227
|
+
reset: function() {
|
|
228
|
+
this._data = new WordArray.init;
|
|
229
|
+
this._nDataBytes = 0;
|
|
230
|
+
},
|
|
231
|
+
_append: function(data) {
|
|
232
|
+
if (typeof data == "string") {
|
|
233
|
+
data = Utf8.parse(data);
|
|
234
|
+
}
|
|
235
|
+
this._data.concat(data);
|
|
236
|
+
this._nDataBytes += data.sigBytes;
|
|
237
|
+
},
|
|
238
|
+
_process: function(doFlush) {
|
|
239
|
+
var processedWords;
|
|
240
|
+
var data = this._data;
|
|
241
|
+
var dataWords = data.words;
|
|
242
|
+
var dataSigBytes = data.sigBytes;
|
|
243
|
+
var blockSize = this.blockSize;
|
|
244
|
+
var blockSizeBytes = blockSize * 4;
|
|
245
|
+
var nBlocksReady = dataSigBytes / blockSizeBytes;
|
|
246
|
+
if (doFlush) {
|
|
247
|
+
nBlocksReady = Math2.ceil(nBlocksReady);
|
|
248
|
+
} else {
|
|
249
|
+
nBlocksReady = Math2.max((nBlocksReady | 0) - this._minBufferSize, 0);
|
|
250
|
+
}
|
|
251
|
+
var nWordsReady = nBlocksReady * blockSize;
|
|
252
|
+
var nBytesReady = Math2.min(nWordsReady * 4, dataSigBytes);
|
|
253
|
+
if (nWordsReady) {
|
|
254
|
+
for (var offset = 0;offset < nWordsReady; offset += blockSize) {
|
|
255
|
+
this._doProcessBlock(dataWords, offset);
|
|
256
|
+
}
|
|
257
|
+
processedWords = dataWords.splice(0, nWordsReady);
|
|
258
|
+
data.sigBytes -= nBytesReady;
|
|
259
|
+
}
|
|
260
|
+
return new WordArray.init(processedWords, nBytesReady);
|
|
261
|
+
},
|
|
262
|
+
clone: function() {
|
|
263
|
+
var clone = Base.clone.call(this);
|
|
264
|
+
clone._data = this._data.clone();
|
|
265
|
+
return clone;
|
|
266
|
+
},
|
|
267
|
+
_minBufferSize: 0
|
|
268
|
+
});
|
|
269
|
+
var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
|
|
270
|
+
cfg: Base.extend(),
|
|
271
|
+
init: function(cfg) {
|
|
272
|
+
this.cfg = this.cfg.extend(cfg);
|
|
273
|
+
this.reset();
|
|
274
|
+
},
|
|
275
|
+
reset: function() {
|
|
276
|
+
BufferedBlockAlgorithm.reset.call(this);
|
|
277
|
+
this._doReset();
|
|
278
|
+
},
|
|
279
|
+
update: function(messageUpdate) {
|
|
280
|
+
this._append(messageUpdate);
|
|
281
|
+
this._process();
|
|
282
|
+
return this;
|
|
283
|
+
},
|
|
284
|
+
finalize: function(messageUpdate) {
|
|
285
|
+
if (messageUpdate) {
|
|
286
|
+
this._append(messageUpdate);
|
|
287
|
+
}
|
|
288
|
+
var hash = this._doFinalize();
|
|
289
|
+
return hash;
|
|
290
|
+
},
|
|
291
|
+
blockSize: 512 / 32,
|
|
292
|
+
_createHelper: function(hasher) {
|
|
293
|
+
return function(message, cfg) {
|
|
294
|
+
return new hasher.init(cfg).finalize(message);
|
|
295
|
+
};
|
|
296
|
+
},
|
|
297
|
+
_createHmacHelper: function(hasher) {
|
|
298
|
+
return function(message, key) {
|
|
299
|
+
return new C_algo.HMAC.init(hasher, key).finalize(message);
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
var C_algo = C.algo = {};
|
|
304
|
+
return C;
|
|
305
|
+
}(Math);
|
|
306
|
+
return CryptoJS;
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// ../../../../node_modules/crypto-js/md5.js
|
|
311
|
+
var require_md5 = __commonJS((exports, module) => {
|
|
312
|
+
(function(root, factory) {
|
|
313
|
+
if (typeof exports === "object") {
|
|
314
|
+
module.exports = exports = factory(require_core());
|
|
315
|
+
} else if (typeof define === "function" && define.amd) {
|
|
316
|
+
define(["./core"], factory);
|
|
317
|
+
} else {
|
|
318
|
+
factory(root.CryptoJS);
|
|
319
|
+
}
|
|
320
|
+
})(exports, function(CryptoJS) {
|
|
321
|
+
(function(Math2) {
|
|
322
|
+
var C = CryptoJS;
|
|
323
|
+
var C_lib = C.lib;
|
|
324
|
+
var WordArray = C_lib.WordArray;
|
|
325
|
+
var Hasher = C_lib.Hasher;
|
|
326
|
+
var C_algo = C.algo;
|
|
327
|
+
var T = [];
|
|
328
|
+
(function() {
|
|
329
|
+
for (var i = 0;i < 64; i++) {
|
|
330
|
+
T[i] = Math2.abs(Math2.sin(i + 1)) * 4294967296 | 0;
|
|
331
|
+
}
|
|
332
|
+
})();
|
|
333
|
+
var MD5 = C_algo.MD5 = Hasher.extend({
|
|
334
|
+
_doReset: function() {
|
|
335
|
+
this._hash = new WordArray.init([
|
|
336
|
+
1732584193,
|
|
337
|
+
4023233417,
|
|
338
|
+
2562383102,
|
|
339
|
+
271733878
|
|
340
|
+
]);
|
|
341
|
+
},
|
|
342
|
+
_doProcessBlock: function(M, offset) {
|
|
343
|
+
for (var i = 0;i < 16; i++) {
|
|
344
|
+
var offset_i = offset + i;
|
|
345
|
+
var M_offset_i = M[offset_i];
|
|
346
|
+
M[offset_i] = (M_offset_i << 8 | M_offset_i >>> 24) & 16711935 | (M_offset_i << 24 | M_offset_i >>> 8) & 4278255360;
|
|
347
|
+
}
|
|
348
|
+
var H = this._hash.words;
|
|
349
|
+
var M_offset_0 = M[offset + 0];
|
|
350
|
+
var M_offset_1 = M[offset + 1];
|
|
351
|
+
var M_offset_2 = M[offset + 2];
|
|
352
|
+
var M_offset_3 = M[offset + 3];
|
|
353
|
+
var M_offset_4 = M[offset + 4];
|
|
354
|
+
var M_offset_5 = M[offset + 5];
|
|
355
|
+
var M_offset_6 = M[offset + 6];
|
|
356
|
+
var M_offset_7 = M[offset + 7];
|
|
357
|
+
var M_offset_8 = M[offset + 8];
|
|
358
|
+
var M_offset_9 = M[offset + 9];
|
|
359
|
+
var M_offset_10 = M[offset + 10];
|
|
360
|
+
var M_offset_11 = M[offset + 11];
|
|
361
|
+
var M_offset_12 = M[offset + 12];
|
|
362
|
+
var M_offset_13 = M[offset + 13];
|
|
363
|
+
var M_offset_14 = M[offset + 14];
|
|
364
|
+
var M_offset_15 = M[offset + 15];
|
|
365
|
+
var a = H[0];
|
|
366
|
+
var b = H[1];
|
|
367
|
+
var c = H[2];
|
|
368
|
+
var d = H[3];
|
|
369
|
+
a = FF(a, b, c, d, M_offset_0, 7, T[0]);
|
|
370
|
+
d = FF(d, a, b, c, M_offset_1, 12, T[1]);
|
|
371
|
+
c = FF(c, d, a, b, M_offset_2, 17, T[2]);
|
|
372
|
+
b = FF(b, c, d, a, M_offset_3, 22, T[3]);
|
|
373
|
+
a = FF(a, b, c, d, M_offset_4, 7, T[4]);
|
|
374
|
+
d = FF(d, a, b, c, M_offset_5, 12, T[5]);
|
|
375
|
+
c = FF(c, d, a, b, M_offset_6, 17, T[6]);
|
|
376
|
+
b = FF(b, c, d, a, M_offset_7, 22, T[7]);
|
|
377
|
+
a = FF(a, b, c, d, M_offset_8, 7, T[8]);
|
|
378
|
+
d = FF(d, a, b, c, M_offset_9, 12, T[9]);
|
|
379
|
+
c = FF(c, d, a, b, M_offset_10, 17, T[10]);
|
|
380
|
+
b = FF(b, c, d, a, M_offset_11, 22, T[11]);
|
|
381
|
+
a = FF(a, b, c, d, M_offset_12, 7, T[12]);
|
|
382
|
+
d = FF(d, a, b, c, M_offset_13, 12, T[13]);
|
|
383
|
+
c = FF(c, d, a, b, M_offset_14, 17, T[14]);
|
|
384
|
+
b = FF(b, c, d, a, M_offset_15, 22, T[15]);
|
|
385
|
+
a = GG(a, b, c, d, M_offset_1, 5, T[16]);
|
|
386
|
+
d = GG(d, a, b, c, M_offset_6, 9, T[17]);
|
|
387
|
+
c = GG(c, d, a, b, M_offset_11, 14, T[18]);
|
|
388
|
+
b = GG(b, c, d, a, M_offset_0, 20, T[19]);
|
|
389
|
+
a = GG(a, b, c, d, M_offset_5, 5, T[20]);
|
|
390
|
+
d = GG(d, a, b, c, M_offset_10, 9, T[21]);
|
|
391
|
+
c = GG(c, d, a, b, M_offset_15, 14, T[22]);
|
|
392
|
+
b = GG(b, c, d, a, M_offset_4, 20, T[23]);
|
|
393
|
+
a = GG(a, b, c, d, M_offset_9, 5, T[24]);
|
|
394
|
+
d = GG(d, a, b, c, M_offset_14, 9, T[25]);
|
|
395
|
+
c = GG(c, d, a, b, M_offset_3, 14, T[26]);
|
|
396
|
+
b = GG(b, c, d, a, M_offset_8, 20, T[27]);
|
|
397
|
+
a = GG(a, b, c, d, M_offset_13, 5, T[28]);
|
|
398
|
+
d = GG(d, a, b, c, M_offset_2, 9, T[29]);
|
|
399
|
+
c = GG(c, d, a, b, M_offset_7, 14, T[30]);
|
|
400
|
+
b = GG(b, c, d, a, M_offset_12, 20, T[31]);
|
|
401
|
+
a = HH(a, b, c, d, M_offset_5, 4, T[32]);
|
|
402
|
+
d = HH(d, a, b, c, M_offset_8, 11, T[33]);
|
|
403
|
+
c = HH(c, d, a, b, M_offset_11, 16, T[34]);
|
|
404
|
+
b = HH(b, c, d, a, M_offset_14, 23, T[35]);
|
|
405
|
+
a = HH(a, b, c, d, M_offset_1, 4, T[36]);
|
|
406
|
+
d = HH(d, a, b, c, M_offset_4, 11, T[37]);
|
|
407
|
+
c = HH(c, d, a, b, M_offset_7, 16, T[38]);
|
|
408
|
+
b = HH(b, c, d, a, M_offset_10, 23, T[39]);
|
|
409
|
+
a = HH(a, b, c, d, M_offset_13, 4, T[40]);
|
|
410
|
+
d = HH(d, a, b, c, M_offset_0, 11, T[41]);
|
|
411
|
+
c = HH(c, d, a, b, M_offset_3, 16, T[42]);
|
|
412
|
+
b = HH(b, c, d, a, M_offset_6, 23, T[43]);
|
|
413
|
+
a = HH(a, b, c, d, M_offset_9, 4, T[44]);
|
|
414
|
+
d = HH(d, a, b, c, M_offset_12, 11, T[45]);
|
|
415
|
+
c = HH(c, d, a, b, M_offset_15, 16, T[46]);
|
|
416
|
+
b = HH(b, c, d, a, M_offset_2, 23, T[47]);
|
|
417
|
+
a = II(a, b, c, d, M_offset_0, 6, T[48]);
|
|
418
|
+
d = II(d, a, b, c, M_offset_7, 10, T[49]);
|
|
419
|
+
c = II(c, d, a, b, M_offset_14, 15, T[50]);
|
|
420
|
+
b = II(b, c, d, a, M_offset_5, 21, T[51]);
|
|
421
|
+
a = II(a, b, c, d, M_offset_12, 6, T[52]);
|
|
422
|
+
d = II(d, a, b, c, M_offset_3, 10, T[53]);
|
|
423
|
+
c = II(c, d, a, b, M_offset_10, 15, T[54]);
|
|
424
|
+
b = II(b, c, d, a, M_offset_1, 21, T[55]);
|
|
425
|
+
a = II(a, b, c, d, M_offset_8, 6, T[56]);
|
|
426
|
+
d = II(d, a, b, c, M_offset_15, 10, T[57]);
|
|
427
|
+
c = II(c, d, a, b, M_offset_6, 15, T[58]);
|
|
428
|
+
b = II(b, c, d, a, M_offset_13, 21, T[59]);
|
|
429
|
+
a = II(a, b, c, d, M_offset_4, 6, T[60]);
|
|
430
|
+
d = II(d, a, b, c, M_offset_11, 10, T[61]);
|
|
431
|
+
c = II(c, d, a, b, M_offset_2, 15, T[62]);
|
|
432
|
+
b = II(b, c, d, a, M_offset_9, 21, T[63]);
|
|
433
|
+
H[0] = H[0] + a | 0;
|
|
434
|
+
H[1] = H[1] + b | 0;
|
|
435
|
+
H[2] = H[2] + c | 0;
|
|
436
|
+
H[3] = H[3] + d | 0;
|
|
437
|
+
},
|
|
438
|
+
_doFinalize: function() {
|
|
439
|
+
var data = this._data;
|
|
440
|
+
var dataWords = data.words;
|
|
441
|
+
var nBitsTotal = this._nDataBytes * 8;
|
|
442
|
+
var nBitsLeft = data.sigBytes * 8;
|
|
443
|
+
dataWords[nBitsLeft >>> 5] |= 128 << 24 - nBitsLeft % 32;
|
|
444
|
+
var nBitsTotalH = Math2.floor(nBitsTotal / 4294967296);
|
|
445
|
+
var nBitsTotalL = nBitsTotal;
|
|
446
|
+
dataWords[(nBitsLeft + 64 >>> 9 << 4) + 15] = (nBitsTotalH << 8 | nBitsTotalH >>> 24) & 16711935 | (nBitsTotalH << 24 | nBitsTotalH >>> 8) & 4278255360;
|
|
447
|
+
dataWords[(nBitsLeft + 64 >>> 9 << 4) + 14] = (nBitsTotalL << 8 | nBitsTotalL >>> 24) & 16711935 | (nBitsTotalL << 24 | nBitsTotalL >>> 8) & 4278255360;
|
|
448
|
+
data.sigBytes = (dataWords.length + 1) * 4;
|
|
449
|
+
this._process();
|
|
450
|
+
var hash = this._hash;
|
|
451
|
+
var H = hash.words;
|
|
452
|
+
for (var i = 0;i < 4; i++) {
|
|
453
|
+
var H_i = H[i];
|
|
454
|
+
H[i] = (H_i << 8 | H_i >>> 24) & 16711935 | (H_i << 24 | H_i >>> 8) & 4278255360;
|
|
455
|
+
}
|
|
456
|
+
return hash;
|
|
457
|
+
},
|
|
458
|
+
clone: function() {
|
|
459
|
+
var clone = Hasher.clone.call(this);
|
|
460
|
+
clone._hash = this._hash.clone();
|
|
461
|
+
return clone;
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
function FF(a, b, c, d, x, s, t) {
|
|
465
|
+
var n = a + (b & c | ~b & d) + x + t;
|
|
466
|
+
return (n << s | n >>> 32 - s) + b;
|
|
467
|
+
}
|
|
468
|
+
function GG(a, b, c, d, x, s, t) {
|
|
469
|
+
var n = a + (b & d | c & ~d) + x + t;
|
|
470
|
+
return (n << s | n >>> 32 - s) + b;
|
|
471
|
+
}
|
|
472
|
+
function HH(a, b, c, d, x, s, t) {
|
|
473
|
+
var n = a + (b ^ c ^ d) + x + t;
|
|
474
|
+
return (n << s | n >>> 32 - s) + b;
|
|
475
|
+
}
|
|
476
|
+
function II(a, b, c, d, x, s, t) {
|
|
477
|
+
var n = a + (c ^ (b | ~d)) + x + t;
|
|
478
|
+
return (n << s | n >>> 32 - s) + b;
|
|
479
|
+
}
|
|
480
|
+
C.MD5 = Hasher._createHelper(MD5);
|
|
481
|
+
C.HmacMD5 = Hasher._createHmacHelper(MD5);
|
|
482
|
+
})(Math);
|
|
483
|
+
return CryptoJS.MD5;
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
// src/generators/google.ts
|
|
488
|
+
var generateGoogle = function(link) {
|
|
489
|
+
let url = "https://calendar.google.com/calendar/render?action=TEMPLATE";
|
|
490
|
+
const utcStartDateTime = convertTZ(link.from, "UTC");
|
|
491
|
+
const utcEndDateTime = convertTZ(link.to, "UTC");
|
|
492
|
+
const dateTimeFormat = link.allDay ? dateFormat : timeFormat;
|
|
493
|
+
url = `${url}&dates=${useDateFormat(utcStartDateTime, dateTimeFormat).value}/${useDateFormat(utcEndDateTime, dateTimeFormat).value}`;
|
|
494
|
+
if (link.timezone)
|
|
495
|
+
url = `${url}&ctz=${link.timezone}`;
|
|
496
|
+
url = `${url}&text=${encodeURIComponent(link.title)}`;
|
|
497
|
+
if (link.description)
|
|
498
|
+
url = `${url}&details=${encodeURIComponent(link.description)}`;
|
|
499
|
+
if (link.address)
|
|
500
|
+
url = `${url}&location=${encodeURIComponent(link.address)}`;
|
|
501
|
+
return url;
|
|
502
|
+
};
|
|
503
|
+
var convertTZ = function(date, tzString) {
|
|
504
|
+
return new Date((typeof date === "string" ? new Date(date) : date).toLocaleString("en-US", { timeZone: tzString }));
|
|
505
|
+
};
|
|
506
|
+
var dateFormat = "YYYYMMDD";
|
|
507
|
+
var timeFormat = "YYYYMMDDThhmmss";
|
|
508
|
+
var google_default = generateGoogle;
|
|
509
|
+
|
|
510
|
+
// src/generators/ics.ts
|
|
511
|
+
var md5 = __toESM(require_md5(), 1);
|
|
512
|
+
var generateIcs = function(link) {
|
|
513
|
+
const uid = `UID:${generateEventUid(link)}`;
|
|
514
|
+
const summary = `SUMMARY:${link.title}`;
|
|
515
|
+
const url = [
|
|
516
|
+
"BEGIN:VCALENDAR",
|
|
517
|
+
"VERSION:2.0",
|
|
518
|
+
"PRODID:Spatie calendar-links",
|
|
519
|
+
"BEGIN:VEVENT",
|
|
520
|
+
uid,
|
|
521
|
+
summary
|
|
522
|
+
];
|
|
523
|
+
const timezone = link.timezone || "PST";
|
|
524
|
+
const formatTime = `${timezone}:${timeFormat2}`;
|
|
525
|
+
const dateTimeFormat = link.allDay ? dateFormat2 : formatTime;
|
|
526
|
+
if (link.allDay) {
|
|
527
|
+
url.push(`DTSTAMP;TZID=${useDateFormat(link.from, dateTimeFormat).value}`);
|
|
528
|
+
url.push(`DTSTART:${useDateFormat(link.from, dateTimeFormat).value}`);
|
|
529
|
+
url.push(`DURATION:P${useMax(1, dateDiffInDays(link.from, link.to)).value}D`);
|
|
530
|
+
} else {
|
|
531
|
+
url.push(`DTSTAMP;TZID=${useDateFormat(link.from, dateTimeFormat).value}`);
|
|
532
|
+
url.push(`DTSTART;TZID=${useDateFormat(link.from, dateTimeFormat).value}`);
|
|
533
|
+
url.push(`DTEND;TZID=${useDateFormat(link.to, dateTimeFormat).value}`);
|
|
534
|
+
}
|
|
535
|
+
if (link.description)
|
|
536
|
+
url.push(`X-ALT-DESC;FMTTYPE=text/html:${link.description}`);
|
|
537
|
+
if (link.address)
|
|
538
|
+
url.push(`LOCATION:${link.address}`);
|
|
539
|
+
url.push("END:VEVENT");
|
|
540
|
+
url.push("END:VCALENDAR");
|
|
541
|
+
return buildLink(url);
|
|
542
|
+
};
|
|
543
|
+
var buildLink = function(propertiesAndComponents) {
|
|
544
|
+
return `data:text/calendar;charset=utf8;base64,${btoa(propertiesAndComponents.join("\r\n"))}`;
|
|
545
|
+
};
|
|
546
|
+
var dateDiffInDays = function(from, to) {
|
|
547
|
+
const _MS_PER_DAY = 86400000;
|
|
548
|
+
const utc1 = Date.UTC(from.getFullYear(), from.getMonth(), from.getDate());
|
|
549
|
+
const utc2 = Date.UTC(to.getFullYear(), to.getMonth(), to.getDate());
|
|
550
|
+
return Math.floor((utc2 - utc1) / _MS_PER_DAY);
|
|
551
|
+
};
|
|
552
|
+
var generateEventUid = function(link) {
|
|
553
|
+
const from = useDateFormat(link.from, atomicFormat).value;
|
|
554
|
+
const to = useDateFormat(link.to, atomicFormat).value;
|
|
555
|
+
return md5.default(`${from}${to}${link.title}`).toString();
|
|
556
|
+
};
|
|
557
|
+
var dateFormat2 = "YYYYMMDD";
|
|
558
|
+
var timeFormat2 = "YYYYMMDDThhmmss";
|
|
559
|
+
var atomicFormat = "YYYY-MM-DDThh:mm:ss+00:00";
|
|
560
|
+
var ics_default = generateIcs;
|
|
561
|
+
|
|
562
|
+
// src/generators/weboutlook.ts
|
|
563
|
+
var generateOutlook = function(link) {
|
|
564
|
+
let url = BASE_URL;
|
|
565
|
+
const utcStartDateTime = convertTZ2(link.from, "UTC");
|
|
566
|
+
const utcEndDateTime = convertTZ2(link.to, "UTC");
|
|
567
|
+
const dateTimeFormat = link.allDay ? dateFormat3 : timeFormat3;
|
|
568
|
+
url = link.allDay ? `${url}&startdt=${useDateFormat(utcStartDateTime, dateTimeFormat).value}` : `${url}&startdt=${useDateFormat(utcStartDateTime, dateTimeFormat).value}Z`;
|
|
569
|
+
url = link.allDay ? `${url}&enddt=${useDateFormat(utcEndDateTime, dateTimeFormat).value}` : `${url}&enddt=${useDateFormat(utcEndDateTime, dateTimeFormat).value}Z`;
|
|
570
|
+
if (link.allDay)
|
|
571
|
+
url = `${url}&allday=true`;
|
|
572
|
+
url = `${url}&subject=${encodeURIComponent(link.title)}`;
|
|
573
|
+
if (link.description)
|
|
574
|
+
url = `${url}&body=${encodeURIComponent(link.description)}`;
|
|
575
|
+
if (link.address)
|
|
576
|
+
url = `${url}&location=${encodeURIComponent(link.address)}`;
|
|
577
|
+
return url;
|
|
578
|
+
};
|
|
579
|
+
var convertTZ2 = function(date, tzString) {
|
|
580
|
+
return new Date((typeof date === "string" ? new Date(date) : date).toLocaleString("en-US", { timeZone: tzString }));
|
|
581
|
+
};
|
|
582
|
+
var dateFormat3 = "YYYY-MM-DD";
|
|
583
|
+
var timeFormat3 = "YYYY-MM-DDThh:mm:ss";
|
|
584
|
+
var BASE_URL = "https://outlook.live.com/calendar/deeplink/compose?path=/calendar/action/compose&rru=addevent";
|
|
585
|
+
var weboutlook_default = generateOutlook;
|
|
586
|
+
|
|
587
|
+
// src/generators/yahoo.ts
|
|
588
|
+
var generateYahoo = function(link) {
|
|
589
|
+
let url = "https://calendar.yahoo.com/?v=60&view=d&type=20";
|
|
590
|
+
const utcStartDateTime = convertTZ3(link.from, "UTC");
|
|
591
|
+
const utcEndDateTime = convertTZ3(link.to, "UTC");
|
|
592
|
+
const dateTimeFormat = link.allDay ? dateFormat4 : timeFormat4;
|
|
593
|
+
if (link.allDay) {
|
|
594
|
+
url = `${url}&ST=${useDateFormat(link.from, dateTimeFormat).value}`;
|
|
595
|
+
url = `${url}&DUR=allday`;
|
|
596
|
+
url = `${url}&ET=${useDateFormat(link.to, dateTimeFormat).value}`;
|
|
597
|
+
} else {
|
|
598
|
+
url = `${url}&ST=${useDateFormat(utcStartDateTime, dateTimeFormat).value}Z`;
|
|
599
|
+
url = `${url}&ET=${useDateFormat(utcEndDateTime, dateTimeFormat).value}Z`;
|
|
600
|
+
}
|
|
601
|
+
url = `${url}&TITLE=${encodeURIComponent(link.title)}`;
|
|
602
|
+
if (link.description)
|
|
603
|
+
url = `${url}&DESC=${encodeURIComponent(link.description)}`;
|
|
604
|
+
if (link.address)
|
|
605
|
+
url = `${url}&in_loc=${encodeURIComponent(link.address)}`;
|
|
606
|
+
return url;
|
|
607
|
+
};
|
|
608
|
+
var convertTZ3 = function(date, tzString) {
|
|
609
|
+
return new Date((typeof date === "string" ? new Date(date) : date).toLocaleString("en-US", { timeZone: tzString }));
|
|
610
|
+
};
|
|
611
|
+
var dateFormat4 = "YYYYMMDD";
|
|
612
|
+
var timeFormat4 = "YYYYMMDDThhmmss";
|
|
613
|
+
var yahoo_default = generateYahoo;
|
|
614
|
+
|
|
615
|
+
// src/links.ts
|
|
616
|
+
var exportCalendarGoogle = function() {
|
|
617
|
+
return google_default(link);
|
|
618
|
+
};
|
|
619
|
+
var exportCalendarIcs = function() {
|
|
620
|
+
return ics_default(link);
|
|
621
|
+
};
|
|
622
|
+
var exportCalendarOutlook = function() {
|
|
623
|
+
return weboutlook_default(link);
|
|
624
|
+
};
|
|
625
|
+
var exportCalendarYahoo = function() {
|
|
626
|
+
return yahoo_default(link);
|
|
627
|
+
};
|
|
628
|
+
var link = {
|
|
629
|
+
from: new Date("2022-12-12 01:00:00"),
|
|
630
|
+
to: new Date("2022-12-12 05:00:00"),
|
|
631
|
+
allDay: false,
|
|
632
|
+
address: "Playa Vista, Los Angeles, CA, USA",
|
|
633
|
+
title: "test appointment",
|
|
634
|
+
description: "test description",
|
|
635
|
+
timezone: "EDT"
|
|
636
|
+
};
|
|
637
|
+
export {
|
|
638
|
+
exportCalendarYahoo,
|
|
639
|
+
exportCalendarOutlook,
|
|
640
|
+
exportCalendarIcs,
|
|
641
|
+
exportCalendarGoogle
|
|
642
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stacksjs/calendar-api",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.61.0",
|
|
5
|
+
"description": "Easily interact with calendar APIs.",
|
|
6
|
+
"author": "Chris Breuer",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"funding": "https://github.com/sponsors/chrisbbreuer",
|
|
9
|
+
"homepage": "https://github.com/stacksjs/stacks/tree/main/storage/framework/core/calendar#readme",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
13
|
+
"directory": "./storage/framework/core/calendar"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/stacksjs/stacks/issues"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"calendar",
|
|
20
|
+
"stacks",
|
|
21
|
+
"ical",
|
|
22
|
+
"google calendar",
|
|
23
|
+
"outlook calendar"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"bun": "./src/index.ts",
|
|
28
|
+
"import": "./dist/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./*": {
|
|
31
|
+
"bun": "./src/*",
|
|
32
|
+
"import": "./dist/*"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"module": "dist/index.js",
|
|
36
|
+
"types": "dist/index.d.ts",
|
|
37
|
+
"contributors": [
|
|
38
|
+
"Chris Breuer <chris@stacksjs.org>"
|
|
39
|
+
],
|
|
40
|
+
"files": [
|
|
41
|
+
"README.md",
|
|
42
|
+
"dist",
|
|
43
|
+
"src"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "bun --bun build.ts",
|
|
47
|
+
"typecheck": "bun --bun tsc --noEmit",
|
|
48
|
+
"prepublishOnly": "bun run build"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@stacksjs/development": "latest"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CalendarLink } from '../types'
|
|
2
|
+
|
|
3
|
+
const dateFormat = 'YYYYMMDD'
|
|
4
|
+
const timeFormat = 'YYYYMMDDThhmmss'
|
|
5
|
+
|
|
6
|
+
function generateGoogle(link: CalendarLink): string {
|
|
7
|
+
// 20221020T170000Z/20221020T173000Z
|
|
8
|
+
|
|
9
|
+
let url = 'https://calendar.google.com/calendar/render?action=TEMPLATE'
|
|
10
|
+
|
|
11
|
+
const utcStartDateTime = convertTZ(link.from, 'UTC') // set timezone to UTC
|
|
12
|
+
const utcEndDateTime = convertTZ(link.to, 'UTC') // set timezone to UTC
|
|
13
|
+
const dateTimeFormat = link.allDay ? dateFormat : timeFormat
|
|
14
|
+
|
|
15
|
+
url = `${url}&dates=${useDateFormat(utcStartDateTime, dateTimeFormat).value}/${
|
|
16
|
+
useDateFormat(utcEndDateTime, dateTimeFormat).value
|
|
17
|
+
}`
|
|
18
|
+
|
|
19
|
+
if (link.timezone) url = `${url}&ctz=${link.timezone}`
|
|
20
|
+
|
|
21
|
+
url = `${url}&text=${encodeURIComponent(link.title)}`
|
|
22
|
+
|
|
23
|
+
if (link.description) url = `${url}&details=${encodeURIComponent(link.description)}`
|
|
24
|
+
|
|
25
|
+
if (link.address) url = `${url}&location=${encodeURIComponent(link.address)}`
|
|
26
|
+
|
|
27
|
+
return url
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function convertTZ(date: Date | string, tzString: string): Date {
|
|
31
|
+
return new Date((typeof date === 'string' ? new Date(date) : date).toLocaleString('en-US', { timeZone: tzString }))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default generateGoogle
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import md5 from 'crypto-js/md5'
|
|
2
|
+
import type { CalendarLink } from '../types'
|
|
3
|
+
|
|
4
|
+
const dateFormat = 'YYYYMMDD'
|
|
5
|
+
const timeFormat = 'YYYYMMDDThhmmss'
|
|
6
|
+
|
|
7
|
+
const atomicFormat = 'YYYY-MM-DDThh:mm:ss+00:00'
|
|
8
|
+
|
|
9
|
+
function generateIcs(link: CalendarLink): string {
|
|
10
|
+
const uid = `UID:${generateEventUid(link)}`
|
|
11
|
+
const summary = `SUMMARY:${link.title}`
|
|
12
|
+
|
|
13
|
+
const url = [
|
|
14
|
+
'BEGIN:VCALENDAR',
|
|
15
|
+
'VERSION:2.0', // @see https://datatracker.ietf.org/doc/html/rfc5545#section-3.7.4
|
|
16
|
+
'PRODID:Spatie calendar-links', // @see https://datatracker.ietf.org/doc/html/rfc5545#section-3.7.3
|
|
17
|
+
'BEGIN:VEVENT',
|
|
18
|
+
uid,
|
|
19
|
+
summary,
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
const timezone = link.timezone || 'PST'
|
|
23
|
+
|
|
24
|
+
const formatTime = `${timezone}:${timeFormat}`
|
|
25
|
+
|
|
26
|
+
const dateTimeFormat = link.allDay ? dateFormat : formatTime
|
|
27
|
+
|
|
28
|
+
if (link.allDay) {
|
|
29
|
+
url.push(`DTSTAMP;TZID=${useDateFormat(link.from, dateTimeFormat).value}`)
|
|
30
|
+
url.push(`DTSTART:${useDateFormat(link.from, dateTimeFormat).value}`)
|
|
31
|
+
url.push(`DURATION:P${useMax(1, dateDiffInDays(link.from, link.to)).value}D`)
|
|
32
|
+
} else {
|
|
33
|
+
url.push(`DTSTAMP;TZID=${useDateFormat(link.from, dateTimeFormat).value}`)
|
|
34
|
+
url.push(`DTSTART;TZID=${useDateFormat(link.from, dateTimeFormat).value}`)
|
|
35
|
+
url.push(`DTEND;TZID=${useDateFormat(link.to, dateTimeFormat).value}`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (link.description) url.push(`X-ALT-DESC;FMTTYPE=text/html:${link.description}`)
|
|
39
|
+
|
|
40
|
+
if (link.address) url.push(`LOCATION:${link.address}`)
|
|
41
|
+
|
|
42
|
+
url.push('END:VEVENT')
|
|
43
|
+
url.push('END:VCALENDAR')
|
|
44
|
+
|
|
45
|
+
return buildLink(url)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function buildLink(propertiesAndComponents: any): string {
|
|
49
|
+
return `data:text/calendar;charset=utf8;base64,${btoa(propertiesAndComponents.join('\r\n'))}`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// a and b are javascript Date objects
|
|
53
|
+
function dateDiffInDays(from: Date, to: Date): number {
|
|
54
|
+
const _MS_PER_DAY = 1000 * 60 * 60 * 24
|
|
55
|
+
|
|
56
|
+
// Discard the time and time-zone information.
|
|
57
|
+
const utc1 = Date.UTC(from.getFullYear(), from.getMonth(), from.getDate())
|
|
58
|
+
const utc2 = Date.UTC(to.getFullYear(), to.getMonth(), to.getDate())
|
|
59
|
+
|
|
60
|
+
return Math.floor((utc2 - utc1) / _MS_PER_DAY)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function generateEventUid(link: any): string {
|
|
64
|
+
const from = useDateFormat(link.from, atomicFormat).value
|
|
65
|
+
const to = useDateFormat(link.to, atomicFormat).value
|
|
66
|
+
|
|
67
|
+
return md5(`${from}${to}${link.title}`).toString()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// function escapeString(field: string): string {
|
|
71
|
+
// return addcslashes(field, '\r\n,;')
|
|
72
|
+
// }
|
|
73
|
+
|
|
74
|
+
export default generateIcs
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CalendarLink } from '../types'
|
|
2
|
+
|
|
3
|
+
const dateFormat = 'YYYY-MM-DD'
|
|
4
|
+
const timeFormat = 'YYYY-MM-DDThh:mm:ss'
|
|
5
|
+
|
|
6
|
+
const BASE_URL = 'https://outlook.live.com/calendar/deeplink/compose?path=/calendar/action/compose&rru=addevent'
|
|
7
|
+
|
|
8
|
+
function generateOutlook(link: CalendarLink): string {
|
|
9
|
+
// 20221020T170000Z/20221020T173000Z
|
|
10
|
+
|
|
11
|
+
let url = BASE_URL
|
|
12
|
+
|
|
13
|
+
const utcStartDateTime = convertTZ(link.from, 'UTC') // set timezone to UTC
|
|
14
|
+
const utcEndDateTime = convertTZ(link.to, 'UTC') // set timezone to UTC
|
|
15
|
+
const dateTimeFormat = link.allDay ? dateFormat : timeFormat
|
|
16
|
+
|
|
17
|
+
url = link.allDay
|
|
18
|
+
? `${url}&startdt=${useDateFormat(utcStartDateTime, dateTimeFormat).value}`
|
|
19
|
+
: `${url}&startdt=${useDateFormat(utcStartDateTime, dateTimeFormat).value}Z`
|
|
20
|
+
url = link.allDay
|
|
21
|
+
? `${url}&enddt=${useDateFormat(utcEndDateTime, dateTimeFormat).value}`
|
|
22
|
+
: `${url}&enddt=${useDateFormat(utcEndDateTime, dateTimeFormat).value}Z`
|
|
23
|
+
|
|
24
|
+
if (link.allDay) url = `${url}&allday=true`
|
|
25
|
+
|
|
26
|
+
url = `${url}&subject=${encodeURIComponent(link.title)}`
|
|
27
|
+
|
|
28
|
+
if (link.description) url = `${url}&body=${encodeURIComponent(link.description)}`
|
|
29
|
+
|
|
30
|
+
if (link.address) url = `${url}&location=${encodeURIComponent(link.address)}`
|
|
31
|
+
|
|
32
|
+
return url
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function convertTZ(date: Date | string, tzString: string): Date {
|
|
36
|
+
return new Date((typeof date === 'string' ? new Date(date) : date).toLocaleString('en-US', { timeZone: tzString }))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default generateOutlook
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CalendarLink } from '../types'
|
|
2
|
+
|
|
3
|
+
const dateFormat = 'YYYYMMDD'
|
|
4
|
+
const timeFormat = 'YYYYMMDDThhmmss'
|
|
5
|
+
|
|
6
|
+
function generateYahoo(link: CalendarLink): string {
|
|
7
|
+
let url = 'https://calendar.yahoo.com/?v=60&view=d&type=20'
|
|
8
|
+
|
|
9
|
+
const utcStartDateTime = convertTZ(link.from, 'UTC') // set timezone to UTC
|
|
10
|
+
const utcEndDateTime = convertTZ(link.to, 'UTC') // set timezone to UTC
|
|
11
|
+
const dateTimeFormat = link.allDay ? dateFormat : timeFormat
|
|
12
|
+
|
|
13
|
+
if (link.allDay) {
|
|
14
|
+
url = `${url}&ST=${useDateFormat(link.from, dateTimeFormat).value}`
|
|
15
|
+
url = `${url}&DUR=allday`
|
|
16
|
+
url = `${url}&ET=${useDateFormat(link.to, dateTimeFormat).value}`
|
|
17
|
+
} else {
|
|
18
|
+
url = `${url}&ST=${useDateFormat(utcStartDateTime, dateTimeFormat).value}Z`
|
|
19
|
+
url = `${url}&ET=${useDateFormat(utcEndDateTime, dateTimeFormat).value}Z`
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
url = `${url}&TITLE=${encodeURIComponent(link.title)}`
|
|
23
|
+
|
|
24
|
+
if (link.description) url = `${url}&DESC=${encodeURIComponent(link.description)}`
|
|
25
|
+
|
|
26
|
+
if (link.address) url = `${url}&in_loc=${encodeURIComponent(link.address)}`
|
|
27
|
+
|
|
28
|
+
return url
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function convertTZ(date: Date | string, tzString: string): Date {
|
|
32
|
+
return new Date((typeof date === 'string' ? new Date(date) : date).toLocaleString('en-US', { timeZone: tzString }))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default generateYahoo
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './links'
|
package/src/links.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import generateGoogle from './generators/google'
|
|
2
|
+
import generateIcs from './generators/ics'
|
|
3
|
+
import generateOutlook from './generators/weboutlook'
|
|
4
|
+
import generateYahoo from './generators/yahoo'
|
|
5
|
+
import type { CalendarLink } from './types'
|
|
6
|
+
|
|
7
|
+
const link: CalendarLink = {
|
|
8
|
+
from: new Date('2022-12-12 01:00:00'),
|
|
9
|
+
to: new Date('2022-12-12 05:00:00'),
|
|
10
|
+
allDay: false,
|
|
11
|
+
address: 'Playa Vista, Los Angeles, CA, USA',
|
|
12
|
+
title: 'test appointment',
|
|
13
|
+
description: 'test description',
|
|
14
|
+
timezone: 'EDT',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// functions that mutate state and trigger updates
|
|
18
|
+
function exportCalendarGoogle(): string {
|
|
19
|
+
return generateGoogle(link)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// functions that mutate state and trigger updates
|
|
23
|
+
function exportCalendarIcs(): string {
|
|
24
|
+
return generateIcs(link)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// functions that mutate state and trigger updates
|
|
28
|
+
function exportCalendarOutlook(): string {
|
|
29
|
+
return generateOutlook(link)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// functions that mutate state and trigger updates
|
|
33
|
+
function exportCalendarYahoo(): string {
|
|
34
|
+
return generateYahoo(link)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { exportCalendarIcs, exportCalendarGoogle, exportCalendarOutlook, exportCalendarYahoo }
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Ref } from 'vue'
|
|
2
|
+
|
|
3
|
+
export interface CalendarStore {
|
|
4
|
+
day: number
|
|
5
|
+
month: Ref<number>
|
|
6
|
+
year: Ref<number>
|
|
7
|
+
currentMonthYear: Ref<string>
|
|
8
|
+
currentMonthDayYear: Ref<string>
|
|
9
|
+
datesOfThePastMonth: Ref<number[]>
|
|
10
|
+
datesOfTheMonth: Ref<number[]>
|
|
11
|
+
datesOfNextMonth: Ref<number[]>
|
|
12
|
+
currentWeekView: Ref<number[]>
|
|
13
|
+
currentWeekViewToday: Ref<number[]>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface Time {
|
|
17
|
+
from: string
|
|
18
|
+
to: string
|
|
19
|
+
}
|
|
20
|
+
export interface Events {
|
|
21
|
+
date: string
|
|
22
|
+
title: string
|
|
23
|
+
description: string
|
|
24
|
+
month: number
|
|
25
|
+
day: number
|
|
26
|
+
year: number
|
|
27
|
+
time: Time
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface WeekDates {
|
|
31
|
+
month: number
|
|
32
|
+
date: number
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface TimeTableStyle {
|
|
36
|
+
time: string
|
|
37
|
+
gridRow: string
|
|
38
|
+
}
|
|
39
|
+
export interface CalendarLink {
|
|
40
|
+
from: Date
|
|
41
|
+
to: Date
|
|
42
|
+
allDay: Boolean
|
|
43
|
+
address: string
|
|
44
|
+
title: string
|
|
45
|
+
description: string
|
|
46
|
+
timezone: string
|
|
47
|
+
}
|