|
| 1 | +'use strict'; |
| 2 | + |
| 3 | +var templates = require('./templates.cjs'); |
| 4 | + |
| 5 | +const random = () => Math.random().toString(16).substr(2); |
| 6 | + |
| 7 | +/** |
| 8 | + * generate a simple uid |
| 9 | + * @private |
| 10 | + * @return {String} uid |
| 11 | + */ |
| 12 | +function uid (len = 16) { |
| 13 | + let str = ''; |
| 14 | + while (str.length < len) str += random(); |
| 15 | + return `${str.substr(0, len)}@date-holidays` |
| 16 | +} |
| 17 | + |
| 18 | +/** |
| 19 | + * prefill a number with `len` zeroes |
| 20 | + * @private |
| 21 | + * @param {Number} num |
| 22 | + * @param {Number} [len] |
| 23 | + * @return {String} prefixed number |
| 24 | + */ |
| 25 | +function zero (num, len = 2) { |
| 26 | + const str = Array(len).join('0') + '' + num; |
| 27 | + return str.substring(str.length - len) |
| 28 | +} |
| 29 | + |
| 30 | +/** |
| 31 | + * convert an Iso Date or String to Vcalendar Date |
| 32 | + * @param {Date|String} date |
| 33 | + * @return {String} |
| 34 | + * @example |
| 35 | + * ``` |
| 36 | + * toIso('2016-01-02T11:29:54.925Z') |
| 37 | + * //> '20160102T112954Z' |
| 38 | + * ``` |
| 39 | + */ |
| 40 | +function toISO (date) { |
| 41 | + if (typeof date === 'object') { |
| 42 | + date = date.toISOString(); |
| 43 | + } |
| 44 | + return date |
| 45 | + .replace(/[:-]/g, '') |
| 46 | + .replace(/\.\d{3}/g, '') |
| 47 | +} |
| 48 | + |
| 49 | +/** |
| 50 | + * convert a date string using offset days to a string |
| 51 | + * @private |
| 52 | + * @param {String} str |
| 53 | + * @param {Number} [offset] - offset to date described by str in milliseconds |
| 54 | + * @return {String} date string `YYYYMMDD` |
| 55 | + * @example |
| 56 | + * ``` |
| 57 | + * toDay('2016-01-02 05:00:01') |
| 58 | + * //> '2016012' |
| 59 | + * ``` |
| 60 | + */ |
| 61 | +function toDay (str, offset = 0) { |
| 62 | + // offset only full days |
| 63 | + offset = Math.ceil(offset / 86400000) * 86400000; |
| 64 | + |
| 65 | + const ticks = +(new Date(str)) + (offset); |
| 66 | + const date = new Date(ticks); |
| 67 | + const s = zero(date.getFullYear(), 4) + |
| 68 | + zero(date.getMonth() + 1) + |
| 69 | + zero(date.getDate()); |
| 70 | + return s |
| 71 | +} |
| 72 | + |
| 73 | +/** |
| 74 | + * apply template on date object from `date-holidays` |
| 75 | + * @private |
| 76 | + * @param {Object} date |
| 77 | + * @param {Object} [opts] |
| 78 | + * @param {Boolean} [opts.fullday] - if `true` then event is treated to be on complete day |
| 79 | + * @param {Boolean} [opts.transp] - if `true` then event is treated to be always transparent |
| 80 | + * @return {String} a single vCalendar vevent |
| 81 | + */ |
| 82 | +function vevent (date, opts = {}) { |
| 83 | + if (!date) { |
| 84 | + return '\n' |
| 85 | + } |
| 86 | + |
| 87 | + const now = (new Date()); |
| 88 | + let dtstart = toISO(date.start); |
| 89 | + let dtend = toISO(date.end); |
| 90 | + const note = date.note || ''; |
| 91 | + const type = date.type || ''; |
| 92 | + |
| 93 | + if (opts.fullday) { |
| 94 | + dtend = toDay(date.date, +date.end - +date.start); |
| 95 | + dtstart = toDay(date.date); |
| 96 | + } |
| 97 | + |
| 98 | + const event = { |
| 99 | + created: toISO(now), |
| 100 | + summary: date.name, |
| 101 | + dtstart, |
| 102 | + dtend, |
| 103 | + description: type + (type && note ? ' - ' : '') + note, |
| 104 | + busy: !opts.transp && type === 'public', |
| 105 | + uid: uid() |
| 106 | + }; |
| 107 | + |
| 108 | + return templates.tVevent(event) |
| 109 | +} |
| 110 | + |
| 111 | +/** |
| 112 | + * get vCalendar |
| 113 | + * @param {Object} date |
| 114 | + * @param {Object} [opts] |
| 115 | + * @return {String} vCalendar |
| 116 | + */ |
| 117 | +function vcalendar (dates, opts) { |
| 118 | + const vevents = dates.map(date => vevent(date, opts)); |
| 119 | + return templates.tVcalendar(vevents) |
| 120 | +} |
| 121 | + |
| 122 | +exports.vcalendar = vcalendar; |
0 commit comments