-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfacebook-page-up-down.user.js
More file actions
105 lines (86 loc) · 2.81 KB
/
facebook-page-up-down.user.js
File metadata and controls
105 lines (86 loc) · 2.81 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
// ==UserScript==
// @name Facebook 鍵盤捲頁
// @description 在臉書使用鍵盤 PageDown 捲動
// @version 1.0.0
// @license MIT
// @author bootleq
// @namespace bootleq.com
// @homepageURL https://github.com/bootleq/user-scripts
//
// @match https://www.facebook.com/*
// @run-at document-idle
// @grant none
// @noframes
// ==/UserScript==
const scrollBehavior = 'smooth'; // auto | smooth
const scrollOffset = 50; // Reverse offset to make a smaller page distance
const ignoreWindow = true; // If true, do not handle the whole window (only handle dialogs)
const ignoreDialogs = [ // Don't scroll those dialogs were detected, scroll the window instead
'心情',
'通知',
'相片檢視工具',
];
function isScrollable(el) {
if (!el) return false;
const style = window.getComputedStyle(el);
return (
el.scrollHeight > el.clientHeight &&
style.overflowY !== 'visible' &&
el.clientHeight > 100 &&
el.scrollHeight > window.innerHeight / 2
);
}
function findScrollable(root, maxDepth = 5) {
// console.log('findScrollable', root);
if (!root || maxDepth < 1) return null;
const queue = [{ element: root, depth: 0 }];
while (queue.length > 0) {
const { element, depth } = queue.shift();
if (isScrollable(element)) {
return element;
}
if (depth >= maxDepth) continue;
const childDivs = element.querySelectorAll(':scope > div');
for (let child of childDivs) {
queue.push({ element: child, depth: depth + 1 });
}
}
return null;
}
function init() {
document.addEventListener('keydown', function(e) {
const $active = document.activeElement;
// Skip if has editing content
if ($active.contentEditable.toString === 'true' && $active.textContent.length > 0) {
return;
}
const isPageDown = (e.key === 'PageDown' || e.keyCode === 34);
const isPageUp = (e.key === 'PageUp' || e.keyCode === 33);
if (isPageDown || isPageUp) {
let $target = null;
const $dialog = document.querySelector('[role="dialog"][aria-labelledby]');
if (
$dialog &&
!ignoreDialogs.includes($dialog.ariaLabel) &&
$dialog.clientHeight > window.innerHeight * 0.25
) {
// console.log('DIALOG', $dialog, $dialog.ariaLabel);
$target = findScrollable($dialog, 5);
} else {
if (!ignoreWindow) {
$target = window;
}
}
if ($target) {
e.preventDefault(); // sometimes the default works, prevent it to unify behavior
const direction = isPageDown ? 1 : -1;
const distance = direction * window.innerHeight - scrollOffset;
$target.scrollBy({
top: distance,
behavior: scrollBehavior,
});
}
}
});
}
init();