-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTop_auto_scrollbar.user.js
184 lines (167 loc) · 6.33 KB
/
Top_auto_scrollbar.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// ==UserScript==
// @name Top auto scrollbar
// @description Automatic appearing top horizontal scrollbar if the page length is more than thrice the height of the screen. Bar Height and opacity are ajustable by Greasemonkey custom menu.
// @description:ru Горизонтальный скроллбар, автоматически появляющийся у верхнего края страницы, если она более чем в три раза длиннее экрана. Ширина и прозрачность настраивается в custom-меню Greasemonkey.
// @namespace github.com/totalamd
// @match *://*/*
// @exclude
// @version 1.2.1
// @downloadURL https://github.com/totalamd/GM-scripts/raw/master/Top_auto_scrollbar.user.js
// @updateURL https://github.com/totalamd/GM-scripts/raw/master/Top_auto_scrollbar.user.js
// @grant GM_listValues
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_registerMenuCommand
// @grant GM_addStyle
// @noframes
// ==/UserScript==
// TODO:
// - [ ] think up how to declarate consts inside main() & make its global
// - [ ] make it work on peculiar sites like nplus1.ru
// - [x] add feature: click on bar scrolls top and back
// - [ ] detect DOM mutations
"use strict";
const l = function(){}, i = function(){};
(function(){
// const l = console.log.bind(console, `${GM_info.script.name} debug:`), i = console.info.bind(console, `${GM_info.script.name} debug:`);
function addToList() {
let locations = GM_getValue('locations', {});
locations[location.hostname] = true;
GM_setValue('locations', locations);
location.reload();
}
function delFromList() {
let locations = GM_getValue('locations', {});
delete locations[location.hostname];
GM_setValue('locations', locations);
location.reload();
}
function clearList() {
if (confirm('Are you sure?')) {
let locationsList = '';
for (let item in GM_getValue('locations', {})) {
locationsList += '\n' + item;
}
console.log('Anti-activation list was:', locationsList);
GM_setValue('locations', {});
}
}
function showList() {
if (!Object.keys(GM_getValue('locations', {})).length) {
console.log('Anti-activation list is empty.');
} else {
let locationsList = '';
for (let item in GM_getValue('locations', {})) {
locationsList += '\n' + item;
}
console.log('Anti-activation list:', locationsList);
}
}
function setHeight(){
let height;
if ((height = parseInt(prompt('enter height, in px', 5))) && (height > 0)) {
GM_setValue('height', height + 'px');
divContainerStyle.height = height + 'px';
}
}
function setOpacity(){
let opacity;
if ((opacity = parseFloat(prompt('enter opacity, from 0 to 1', 0.8))) && (opacity > 0) && (opacity <= 1)) {
GM_setValue('opacity', opacity);
divContainerStyle.opacity = opacity;
}
}
function update() {
const navTooltip = (!memPosition && !window.scrollY) ? '' : (window.scrollY ? navTooltipUp : navTooltipDown);
const width = Math.min(window.scrollY / (document.body.scrollHeight - window.innerHeight), 1) * 100;
divBarStyle.width = width + '%';
divContainer.title = `${width.toFixed()}%\nPage is ${(document.body.scrollHeight / window.innerHeight).toFixed(1)} times as high as screen\n${navTooltip}`;
}
function main () {
GM_addStyle(`
.topAutoScrollbar-divContainer {
position: fixed;
opacity: ${GM_getValue('opacity') || 0.8};
height: ${GM_getValue('height') || '5px'};
width: 100%;
top: 0px;
left: 0px;
background-color: cornflowerblue;
z-index: 2147483647;
cursor: pointer;
}
.topAutoScrollbar-divBar {
height: 100%;
background-color: hotpink;
width: 0;
}`);
// get vars to bars width properties
for (let sheet of document.styleSheets) {
// "Security error" workaround for some external css
if (!sheet.href) {
for (let rule of sheet.cssRules) {
switch (rule.selectorText) {
case '.topAutoScrollbar-divContainer':
divContainerStyle = rule.style;
break;
case '.topAutoScrollbar-divBar':
divBarStyle = rule.style;
break;
}
}
}
}
if (document.body.style.scrollBehavior) {
origScrollBehavior = document.body.style.scrollBehavior;
}
divContainer.className = 'topAutoScrollbar-divContainer';
divBar.className = 'topAutoScrollbar-divBar';
divContainer.appendChild(divBar);
document.body.appendChild(divContainer);
// define initial % position:
update();
window.addEventListener('scroll', update);
// handle clicks on bar: scroll to top and back:
divContainer.addEventListener('click', navigation);
}
function navigation () {
// check to avoid unnecessary CSS manipulation:
if (origScrollBehavior !== 'smooth') document.body.style.scrollBehavior = 'smooth';
if (window.scrollY !== 0) {
memPosition = window.scrollY;
window.scrollTo(window.scrollX, 0);
} else {
window.scrollTo(window.scrollX, memPosition);
memPosition = 0;
}
document.body.style.scrollBehavior = origScrollBehavior || '';
}
if (!(location.hostname in (GM_getValue('locations', {})))) {
GM_registerMenuCommand("Don't activate scrollbar on this site", addToList);
} else {
GM_registerMenuCommand("Reactivate scrollbar on this site", delFromList);
}
if (Object.keys(GM_getValue('locations', {})).length) {
GM_registerMenuCommand("Clear anti-activation list", clearList);
}
GM_registerMenuCommand("Show anti-activation list", showList);
GM_registerMenuCommand("Set bar height", setHeight);
GM_registerMenuCommand("Set bar opacity", setOpacity);
// declaration outside main() to make its kinda global
const divContainer = document.createElement('div');
const divBar = document.createElement('div');
const navTooltipUp = "Click to get to the top ▲";
const navTooltipDown = "Click to get back ▼";
let divContainerStyle, divBarStyle;
let memPosition;
let origScrollBehavior;
if (document.body.scrollHeight / window.innerHeight <= 3) {
l('Page\'s too short');
return;
} else if (location.hostname in (GM_getValue('locations', {}))) {
l(`'${location.hostname}' is in the anti-activation list.`);
return;
}
main();
}())