forked from imightbeamy/gcal-multical-event-merge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
events.user.js
129 lines (115 loc) · 4.76 KB
/
events.user.js
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
// ==UserScript==
// @name Event Merge for Google Calendar™ (by @imightbeAmy)
// @namespace gcal-multical-event-merge
// @include https://www.google.com/calendar/*
// @include http://www.google.com/calendar/*
// @include https://calendar.google.com/*
// @include http://calendar.google.com/*
// @version 1
// @grant none
// ==/UserScript==
'use strict';
const stripesGradient = (colors, width, angle) => {
let gradient = `repeating-linear-gradient( ${angle}deg,`;
let pos = 0;
colors.forEach(color => {
gradient += color + " " + pos + "px,";
pos += width;
gradient += color + " " + pos + "px,";
});
gradient = gradient.slice(0, -1);
gradient += ")";
return gradient;
};
const dragType = e => parseInt(e.dataset.dragsourceType);
const merge = (mainCalender) => {
const eventSets = {};
const days = mainCalender.querySelectorAll("[role=\"gridcell\"]");
days.forEach((day, index) => {
const events = Array.from(day.querySelectorAll("[data-eventid][role=\"button\"], [data-eventid] [role=\"button\"]"));
events.forEach(event => {
const eventTitleEls = event.querySelectorAll('[aria-hidden="true"]');
if (!eventTitleEls.length) {
return;
}
let eventKey = Array.from(eventTitleEls).map(el => el.textContent).join('').replace(/\\s+/g,"");
eventKey = index + eventKey + event.style.height;
eventSets[eventKey] = eventSets[eventKey] || [];
eventSets[eventKey].push(event);
});
});
Object.values(eventSets)
.forEach(events => {
if (events.length > 1) {
const colors = events.map(event =>
event.style.backgroundColor || // Week day and full day events marked 'attending'
event.style.borderColor || // Not attending or not responded week view events
event.parentElement.style.borderColor // Timed month view events
);
events.sort((e1, e2) => dragType(e1) - dragType(e2));
const parentPosition = events[0].parentElement.getBoundingClientRect();
const positions = events.map(event => {
const eventPosition = event.getBoundingClientRect();
event.originalLeft = event.originalLeft || eventPosition.left;
event.originalRight = event.originalRight || eventPosition.right;
return {
left: eventPosition.left - parentPosition.left,
right: parentPosition.right - eventPosition.right,
}
});
const eventToKeep = events.shift();
events.forEach(event => {
event.style.visibility = "hidden";
});
if (eventToKeep.style.backgroundColor || eventToKeep.style.borderColor) {
eventToKeep.originalStyle = eventToKeep.originalStyle || {
backgroundImage: eventToKeep.style.backgroundImage,
left: eventToKeep.style.left,
right: eventToKeep.style.right,
visibility: eventToKeep.style.visibility,
width: eventToKeep.style.width,
border: eventToKeep.style.border,
};
eventToKeep.style.backgroundImage = stripesGradient(colors, 10, 45);
eventToKeep.style.left = Math.min.apply(Math, positions.map(s => s.left)) + 'px';
eventToKeep.style.right = Math.min.apply(Math, positions.map(s => s.right)) + 'px';
eventToKeep.style.visibility = "visible";
eventToKeep.style.width = null;
eventToKeep.style.border = "solid 1px #FFF"
events.forEach(event => {
event.style.visibility = "hidden";
});
} else {
const dots = eventToKeep.querySelector('[role="button"] div:first-child');
const dot = dots.querySelector('div');
dot.style.backgroundImage = stripesGradient(colors, 4, 90);
dot.style.width = colors.length * 4 + 'px';
dot.style.borderWidth = 0;
dot.style.height = '8px';
events.forEach(event => {
event.style.visibility = "hidden";
});
}
} else {
events.forEach(event => {
for (var k in event.originalStyle) {
event.style[k] = event.originalStyle[k];
}
});
}
});
}
const init = (mutationsList) => {
mutationsList && mutationsList
.map(mutation => mutation.addedNodes[0] || mutation.target)
.filter(node => node.matches && node.matches("[role=\"main\"], [role=\"dialog\"]"))
.map(merge);
}
setTimeout(() => chrome.storage.local.get('disabled', storage => {
console.log(`Event merge is ${storage.disabled ? 'disabled' : 'enabled'}`);
if (!storage.disabled) {
const observer = new MutationObserver(init);
observer.observe(document.querySelector('body'), { childList: true, subtree: true, attributes: true });
}
chrome.storage.onChanged.addListener(() => window.location.reload())
}), 10);