forked from greasemonkey/gm4-polyfill
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgm4-polyfill.js
131 lines (114 loc) · 3.83 KB
/
gm4-polyfill.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
/*
This helper script bridges compatibility between the Greasemonkey 4 APIs and
existing/legacy APIs. Say for example your user script includes
// @grant GM_getValue
And you'd like to be compatible with both Greasemonkey 3 and Greasemonkey 4
(and for that matter all versions of Violentmonkey, Tampermonkey, and any other
user script engine). Add:
// @grant GM.getValue
// @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
And switch to the new (GM-dot) APIs, which return promises. If your script
is running in an engine that does not provide the new asynchronous APIs, this
helper will add them, based on the old APIs.
If you use `await` at the top level, you'll need to wrap your script in an
`async` function to be compatible with any user script engine besides
Greasemonkey 4.
(async () => {
let x = await GM.getValue('x');
})();
*/
if (typeof GM == 'undefined') {
this.GM = {};
}
if (typeof GM_addStyle == 'undefined') {
this.GM_addStyle = (aCss) => {
'use strict';
let head = document.getElementsByTagName('head')[0];
if (head) {
let style = document.createElement('style');
style.setAttribute('type', 'text/css');
style.textContent = aCss;
head.appendChild(style);
return style;
}
return null;
};
}
if (typeof GM_registerMenuCommand == 'undefined') {
this.GM_registerMenuCommand = (caption, commandFunc, accessKey) => {
if (!document.body) {
if (document.readyState === 'loading'
&& document.documentElement && document.documentElement.localName === 'html') {
new MutationObserver((mutations, observer) => {
if (document.body) {
observer.disconnect();
GM_registerMenuCommand(caption, commandFunc, accessKey);
}
}).observe(document.documentElement, {childList: true});
} else {
console.error('GM_registerMenuCommand got no body.');
}
return;
}
let contextMenu = document.body.getAttribute('contextmenu');
let menu = (contextMenu ? document.querySelector('menu#' + contextMenu) : null);
if (!menu) {
menu = document.createElement('menu');
menu.setAttribute('id', 'gm-registered-menu');
menu.setAttribute('type', 'context');
document.body.appendChild(menu);
document.body.setAttribute('contextmenu', 'gm-registered-menu');
}
let menuItem = document.createElement('menuitem');
menuItem.textContent = caption;
menuItem.addEventListener('click', commandFunc, true);
menu.appendChild(menuItem);
};
}
if (typeof GM_getResourceText == 'undefined') {
this.GM_getResourceText = (aRes) => {
'use strict';
return GM.getResourceUrl(aRes)
.then(url => fetch(url))
.then(resp => resp.text())
.catch(function(error) {
GM.log('Request failed', error);
return null;
});
};
}
Object.entries({
'log': console.log.bind(console), // Pale Moon compatibility. See #13.
'info': GM_info,
}).forEach(([newKey, old]) => {
if (old && (typeof GM[newKey] == 'undefined')) {
GM[newKey] = old;
}
});
Object.entries({
'GM_addStyle': 'addStyle',
'GM_deleteValue': 'deleteValue',
'GM_getResourceURL': 'getResourceUrl',
'GM_getValue': 'getValue',
'GM_listValues': 'listValues',
'GM_notification': 'notification',
'GM_openInTab': 'openInTab',
'GM_registerMenuCommand': 'registerMenuCommand',
'GM_setClipboard': 'setClipboard',
'GM_setValue': 'setValue',
'GM_xmlhttpRequest': 'xmlHttpRequest',
'GM_getResourceText': 'getResourceText',
}).forEach(([oldKey, newKey]) => {
let old = this[oldKey];
if (old && (typeof GM[newKey] == 'undefined')) {
GM[newKey] = function(...args) {
return new Promise((resolve, reject) => {
try {
resolve(old.apply(this, args));
} catch (e) {
reject(e);
}
});
};
}
});