-
-
Notifications
You must be signed in to change notification settings - Fork 165
/
mutations.js
120 lines (115 loc) · 3.67 KB
/
mutations.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
/* GitHub mutations observer library script v0.6.0
* Detect changes to various elements and trigger an event
* This script is meant to be used as a library for GitHub-based userscripts
* Copyright © 2022 Rob Garrison
* License: MIT
*/
(() => {
"use strict";
// prefix for event & document body class name, e.g. "ghmo:container"
const prefix = "ghmo";
const disableAttr = `data-${prefix}-disable`;
const debounceInterval = 250;
const targets = {
// pjax container (covers general, repo & gists)
// .news = newsfeed layout
// .repository-content = file code (code folding)
// body = global changes
"[data-pjax-container], .news, .repository-content, body": {
count: 0,
name: "container"
},
// comment preview active
".js-preview-body": {
count: 0,
name: "preview"
},
// .js-discussion = wrapper for progressively loaded comments;
// "# items not shown" example: https://github.com/isaacs/github/issues/18
// .discussion-item = issue status changed (github-issue-show-status)
// #progressive-timeline-item-container = load hidden items (old?)
// #js-progressive-timeline-item-container = load hidden items
// markdown-toolbar = issue comments
".js-discussion, .discussion-item, .toolbar-item, #progressive-timeline-item-container, #js-progressive-timeline-item-container, markdown-toolbar": {
count: 0,
name: "comments"
},
// progressively loaded content (diff files)
".js-diff-progressive-container, .data.blob-wrapper, .js-diff-load-container, .diff-table tbody, .diff-progressive-loader": {
count: 0,
name: "diff"
},
// issues/pr sidebar & timeline sections: e.g. form actions, commit
// references, deployment state & PR checks container
".js-updatable-content, .js-updatable-content-preserve-scroll-position": {
count: 0,
name: "updatable"
},
// user profile menu (loads on hover)
"details-menu": {
count: 0,
name: "menu"
}
};
const list = Object.keys(targets);
let queue = new Set();
let timer;
function fireEvents() {
list.forEach(selector => {
if (targets[selector].count > 0) {
// event => "ghmo:container", "ghmo:comments"
const event = new Event(prefix + ":" + targets[selector].name);
document.dispatchEvent(event);
targets[selector].count = 0;
}
});
}
function process() {
clearTimeout(timer);
// avoiding use of forEach loops for performance reasons
for (const target of queue) {
if (target) {
for (const item of list) {
if (target.matches(item)) {
targets[item].count++;
}
}
}
}
timer = setTimeout(() => fireEvents(), debounceInterval);
queue.clear();
}
function init() {
// prevent error when library is loaded at document-start & no body exists
const container = document.querySelector("body");
/* document.body attribute used to disable updates; it *should not*
* be used regularly as multiple scripts may enable or disable the
* observers at inappropriate times. It is best that each script handles
* the mutation events triggered by this library on its own
*/
if (container.getAttribute(disableAttr)) {
return;
}
// prevent script from installing more than once
if (container && !container.classList.contains(prefix + "-enabled")) {
container.classList.add(prefix + "-enabled");
// http://stackoverflow.com/a/39332340/145346
new MutationObserver(mutations => {
if (!queue.size) {
requestAnimationFrame(process);
}
for (const mutation of mutations) {
queue.add(mutation.target);
}
}).observe(document, {
childList: true,
subtree: true,
});
}
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => init);
} else {
init();
}
})();