-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdirect_google_images.user.js
124 lines (114 loc) · 3.27 KB
/
direct_google_images.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
// ==UserScript==
// @name Direct Google Images
// @namespace http://greasyfork.org/en/users/461
// @version 0.99
// @description Provides direct links in Google Images.
// @include /^https?\:\/\/(www|encrypted)\.google\./
// @author zanetu
// @license GPL version 2 or any later version; http://www.gnu.org/licenses/gpl-2.0.txt
// @grant GM_addStyle
// @run-at document-start
// @noframes
// ==/UserScript==
//do not run in frames or iframes
if(window.top == window.self) {
var RE = /imgres\?imgurl\=(http.+?)\&imgrefurl\=(http.+?)(\&|$)/i
var RE_SOURCE = /url\?(?:.*?\&)*?url\=(http.+?)(\&|$)/i
var WATCH_EVENTS = ['mouseenter', 'mousedown', 'click', 'focus', 'touchstart']
var clickCount = 0
function dd(url) {
var d1 = decodeURIComponent(url), d2
try {
d2 = decodeURIComponent(d1)
}
catch(malformed) {
return d1
}
return d2
}
function closest(element, matchFunction, maxLevel) {
var max = undefined === maxLevel ? Number.POSITIVE_INFINITY : parseInt(maxLevel) + 1
if(max > 0 && 'function' === typeof matchFunction) {
for(; element && max--; element = element.parentNode) {
if(matchFunction(element)) {
return element
}
}
}
return null
}
function modifyGoogleImage(element) {
if(element && element.href) {
var m = element.href.match(RE)
if(m && m[1] && m[2]) {
element.href = dd(m[1])
setDirect(element)
if(isClickedLast(element)) element.click()
return true
}
m = element.href.match(RE_SOURCE)
if(m && m[1]) {
element.href = dd(m[1])
setDirect(element)
return true
}
}
return false
}
function isDirect(e) {
return 'yes' === (e && e.getAttribute && e.getAttribute('direct'))
}
function setDirect(e) {
e && e.setAttribute && e.setAttribute('direct', 'yes')
}
function triggerMouseEvent(element, eventType) {
var event = new MouseEvent('mousedown', {
bubbles: true,
cancelable: true
})
element.dispatchEvent(event)
}
function isClickedLast(e) {
return clickCount == (e && e.getAttribute && e.getAttribute('click-number'))
}
function cacheClick(e) {
e && e.setAttribute && e.setAttribute('click-number', ++clickCount)
}
//override event handlers
for(var i in WATCH_EVENTS) {
document.addEventListener(WATCH_EVENTS[i], function(event) {
var t = event.target
var aContainer = closest(t, function(e) {
return 'A' === e.nodeName
&& (
//image; regex can be replaced by more recent classList.contains()
/(^|\s)islib(\s|$)/.test(e.className)
//image source
|| 'noopener' === e.getAttribute('rel')
)
}, 2)
if(!aContainer) return
if('click' === event.type) {
//suppress unwanted side bar
event.stopPropagation()
//cache left clicks, ignoring keys like ctrl
if(0 === event.button) cacheClick(aContainer)
}
if(isDirect(aContainer)) {
if('mouseenter' !== event.type) event.stopPropagation()
return
}
if('mouseenter' === event.type) {
if(!modifyGoogleImage(aContainer)) {
var observer = new MutationObserver(function(mutationRecords) {
for(var j in mutationRecords) {
modifyGoogleImage(mutationRecords[j].target)
}
})
observer.observe(aContainer, {attributes: true})
triggerMouseEvent(t, 'mousedown')
}
}
}, true)
}
}