Repository navigation
Expand file tree
/
Copy pathCalendarModel.js
More file actions
135 lines (127 loc) · 4.25 KB
/
Copy pathCalendarModel.js
File metadata and controls
135 lines (127 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
function pad(value) {
return (value < 10 ? "0" : "") + value
}
function dateKey(date) {
return date.getFullYear() + "-" + pad(date.getMonth() + 1) + "-" + pad(date.getDate())
}
function stripJsonComments(raw) {
var input = String(raw || "{}")
var output = ""
var inString = false
var escaped = false
var lineComment = false
var blockComment = false
for (var i = 0; i < input.length; i++) {
var character = input.charAt(i)
var next = input.charAt(i + 1)
if (lineComment) {
if (character === "\n" || character === "\r") {
lineComment = false
output += character
}
continue
}
if (blockComment) {
if (character === "*" && next === "/") {
blockComment = false
i++
} else if (character === "\n" || character === "\r") output += character
continue
}
if (inString) {
output += character
if (escaped) escaped = false
else if (character === "\\") escaped = true
else if (character === "\"") inString = false
continue
}
if (character === "\"") {
inString = true
output += character
} else if (character === "/" && next === "/") {
lineComment = true
i++
} else if (character === "/" && next === "*") {
blockComment = true
i++
} else output += character
}
return output
}
function stripTrailingCommas(raw) {
var input = String(raw || "{}")
var output = ""
var inString = false
var escaped = false
for (var i = 0; i < input.length; i++) {
var character = input.charAt(i)
if (inString) {
output += character
if (escaped) escaped = false
else if (character === "\\") escaped = true
else if (character === "\"") inString = false
continue
}
if (character === "\"") {
inString = true
output += character
continue
}
if (character === ",") {
var next = i + 1
while (/\s/.test(input.charAt(next))) next++
if (input.charAt(next) === "}" || input.charAt(next) === "]") continue
}
output += character
}
return output
}
function parseConfigResult(raw, defaultCalendarName) {
try {
var parsed = JSON.parse(stripTrailingCommas(stripJsonComments(raw)))
if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.calendars))
return { calendars: [], error: "The calendars field must be an array." }
var calendars = parsed.calendars
var result = []
for (var i = 0; i < calendars.length; i++) {
var item = calendars[i]
if (!item || !String(item.url || "").trim()) continue
var url = String(item.url).trim().replace(/^webcal:/i, "https:")
if (!/^(https?|file):\/\//i.test(url)) return { calendars: [], error: "Calendar URLs must use HTTP, HTTPS or file." }
if (result.some(function(calendar) { return calendar.url === url }))
return { calendars: [], error: "Each calendar URL must be unique." }
result.push({
name: String(item.name || defaultCalendarName || "Calendar"),
url: url,
color: String(item.color || ""),
excludeDeclined: item.excludeDeclined !== false,
emails: (Array.isArray(item.emails) ? item.emails : (item.email ? [item.email] : []))
.map(function(email) { return String(email).trim().toLowerCase() })
.filter(function(email) { return email !== "" })
})
}
return { calendars: result, error: "" }
} catch (error) {
return { calendars: [], error: "Invalid JSONC." }
}
}
function parseConfig(raw, defaultCalendarName) {
return parseConfigResult(raw, defaultCalendarName).calendars
}
function daysInMonth(year, month) {
return new Date(year, month + 1, 0).getDate()
}
function formatTime(date, locale) {
var pattern = locale.timeFormat(1)
if (!/[aApP]{1,2}/.test(pattern)) return locale.toString(date, "H:mm")
return locale.toString(date, pattern)
.replace(/^0(?=\d)/, "")
.replace(/\s+h\s*/i, ":")
.replace(/\s*([AaPp])\.?\s*[Mm]\.?$/, function(_, meridiem) {
return meridiem.toLowerCase() + "m"
})
}
function formatEvent(event, locale, timeLocale) {
var time = event.allDay ? "" : formatTime(new Date(event.start), timeLocale || locale)
return { time: time, title: event.summary, location: event.location, calendar: event.calendar, color: event.color }
}