-
-
Save roshanca/cfef2b1249fc61aad6e5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Straight Google | |
// @id straight_google_pokerface | |
// @version 1.17.13 | |
// @author Pokerface - Kevin | |
// @namespace in.co.tossing.toolkit.google | |
// @description Remove URL redirection from google products | |
// @license GPL v3 or later version | |
// @downloadURL https://userscripts.org/scripts/source/121261.user.js | |
// @updateURL https://userscripts.org/scripts/source/121261.meta.js | |
// @run-at document-end | |
// @grant GM_addStyle | |
// @grant GM_xmlhttpRequest | |
// @include *://www.google.*/*q=* | |
// @include *://www.google.*/*tbs=* | |
// @include *://www.google.*/search?* | |
// @include *://www.google.*/webhp?* | |
// @include *://www.google.*/cse?* | |
// @include *://www.google.*/?* | |
// @include *://www.google.*/#* | |
// @include *://www.google.*/ | |
// @include *://encrypted.google.* | |
// @include *://ipv6.google.* | |
// @include *://www.google.*/news* | |
// @include *://news.google.*/* | |
// @include *://plus.google.com/_/scs/apps-static/_/js/* | |
// @include *://images.google.com/* | |
// @include *://docs.google.com/* | |
// @include *://maps.google.com/* | |
// @include *://www.google.com/maps* | |
// @include *://ditu.google.com/* | |
// @include *://www.youtube.* | |
// @include *://groups.google.com/group/* | |
// @include *://www.google.com/bookmarks/* | |
// @include *://history.google.com/bookmarks/* | |
// @include *://www.google.com/history/* | |
// @include *://www.google.com/prdhp* | |
// @include *://www.google.com/products/catalog?* | |
// @include *://www.google.com/shopping/product/* | |
// @include *://mail.google.com/* | |
// @include *://www.google.com/mail* | |
// @include *://play.google.com/store* | |
// @exclude *://www.google.com/reader/* | |
// ==/UserScript== | |
/* | |
Straight Google (also named as Straight Search) | |
Kevin Wang (kevixw'At'gmail.com) | |
Copyright (c) 2013 . All rights reserved. | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
/* | |
KissogramToolkit | |
build 10/27/2012 by Kevin Wang | |
[email protected] | |
*/ | |
var $K = KissogramToolkit = (function ($$d) { | |
// some configuration | |
var DEBUG_ON = 0; | |
// Basic function ============================================== | |
// for each | |
function each($arr, $func) { | |
var item; | |
if (!$arr) | |
return; | |
//_debug('each function is called. arr length is '+ $arr.length); | |
if ($func) | |
for (item in $arr) | |
$func.call($arr[item]); | |
else | |
// the $arr is collection of function itself | |
for (item in $arr) | |
if (typeof $arr[item]==='function') | |
$arr[item](); | |
} | |
var utils = { | |
"isStrictArray" : function ($obj) { | |
return Object.prototype.toString.apply($obj) === '[object Array]'; | |
}, | |
"isRegExp" : function ($obj) { | |
return Object.prototype.toString.apply($obj) === '[object RegExp]'; | |
}, | |
"toArray" : function ($obj) { | |
if (!this.isArray($obj)) | |
return [$obj]; | |
else if (!this.isStrictArray($obj)) | |
return Array.prototype.slice.apply($obj); | |
else | |
return $obj; | |
}, | |
"isArray" : function ($obj) { | |
var type = Object.prototype.toString.apply($obj); | |
return type === '[object Array]' // array | |
|| type === '[object NodeList]' // document.querySelectorAll | |
|| type === '[object Arguments]' // function arguments | |
; | |
}, | |
"trim" : function ($str) { | |
return $str.replace(/^\s+|\s+$/g, ''); | |
}, | |
"trimS" : function ($str) { | |
return this.trim($str).replace(/\s{2,}/g, ' '); | |
} | |
}; | |
// shallow copy | |
function extend($target, $options) { | |
var name; | |
for (name in $options) { | |
if ($target === $options[name]) | |
continue; | |
if ($options[name]) | |
$target[name] = $options[name]; | |
} | |
return $target; | |
} | |
// Basic function ends ============================================= | |
// limit the interval/delay of running a specific function, return the changed function | |
function setFunctionTiming($func, $opt) { | |
$opt = $opt || {}; | |
var opt = { | |
interval : $opt.interval || 0, | |
delay : $opt.delay || 0, | |
check : $opt.check || 0 | |
}; | |
return (function () { | |
var lastRunTime = 0, instances = [], isRunning = 0, checkInterval = null; | |
var res = function () { | |
if (opt.check > 0 && checkInterval==null) | |
checkInterval = setInterval(res, opt.check); | |
var timeRemain = (new Date().getTime()) - lastRunTime; | |
var _this = this, args = utils.toArray(arguments); | |
// the real function | |
function runFunc() { | |
lastRunTime = new Date().getTime(); | |
isRunning = 1; | |
$func.apply(_this, args); | |
isRunning = 0; | |
instances.shift(); | |
}; | |
if (instances.length < 1 || isRunning) { | |
// not time yet | |
if (timeRemain < opt.interval) | |
instances.push(setTimeout(runFunc, Math.max(100, opt.delay + opt.interval - (isRunning ? 0 : timeRemain)))); | |
else | |
instances.push(setTimeout(runFunc, Math.max(100, opt.delay))); | |
} | |
}; | |
return res; | |
})(); | |
} | |
var $$browser = (function getNavigator($n) { | |
var navigatorString = $n.userAgent.toLowerCase(), | |
// browser agent | |
rBrowsers = [ | |
/.*version\/([\w.]+).*(safari).*/, | |
/.*(msie) ([\w.]+).*/, | |
/.*(firefox)\/([\w.]+).*/, | |
/(opera).+version\/([\w.]+)/, | |
/.*(chrome)\/([\w.]+).*/ | |
], | |
// result | |
ret = { | |
name : 'unknown', | |
version : 'unknown', | |
language: $n['language'] || $n['userLanguage'] || '', | |
toString : function () { | |
return this.name; | |
} | |
}; | |
for (var i = 0, match=null; i < rBrowsers.length; ++i) | |
if ( match = rBrowsers[i].exec(navigatorString) ) { | |
// match safari | |
ret.name = (i==0 ? match[2] : match[1]) || 'unknown'; | |
ret.version = (i==0 ? match[1] : match[2]) || 'unknown'; | |
ret[ret.name] = 1; | |
break; | |
} | |
return ret; | |
})(window.navigator); | |
// get unsafeWindow | |
var $$w = (function () { | |
var w = null, // window object | |
resizeTasks = [], | |
scrollTasks = []; | |
function getSize() { | |
return { | |
windowHeight : window.innerHeight, | |
windowWidth : window.innerWidth, | |
height : $$d.documentElement.clientHeight, | |
width : $$d.documentElement.clientWidth | |
}; | |
} | |
function _isScroll(el) { | |
// test targets | |
var elems = el ? [el] : [document.documentElement, document.body]; | |
var scrollX = 0, scrollY = 0; | |
for (var i = 0; i < elems.length; i++) { | |
var o = elems[i]; | |
// test horizontal | |
var sl = o.scrollLeft; | |
o.scrollLeft += (sl > 0) ? -1 : 1; | |
o.scrollLeft !== sl && (scrollX = scrollX || 1); | |
o.scrollLeft = sl; | |
// test vertical | |
var st = o.scrollTop; | |
o.scrollTop += (st > 0) ? -1 : 1; | |
o.scrollTop !== st && (scrollY = scrollY || 1); | |
o.scrollTop = st; | |
} | |
// ret | |
return { | |
scrollX: scrollX, | |
scrollY: scrollY | |
}; | |
}; | |
window.addEventListener('resize', function () { | |
each(resizeTasks); | |
}); | |
window.addEventListener('scroll', function () { | |
each(scrollTasks); | |
}); | |
// return 1 when unsafeWindow is loaded successfully | |
function _init($var) { | |
if (!w) { | |
// load unsafeWindow | |
if (typeof(unsafeWindow) !== "undefined" && typeof(unsafeWindow[$var]) !== "undefined") | |
w = unsafeWindow; | |
else if (typeof(window[$var]) !== "undefined") | |
w = window; | |
else | |
try { | |
// for Chrome | |
var a = document.createElement("a"); | |
a.setAttribute("onclick", "return window;"); | |
var win = a.onclick(); | |
if (typeof(win[$var]) !== "undefined") | |
w = win; | |
} | |
catch (e) { | |
_debug('Kissogram Toolkit : Unable to load unsafeWindow Object!'); | |
w = null; | |
} | |
} | |
return w; | |
} | |
function _onUnsafeWindowReady($var, $func, $options) { | |
$options = $options || {}; | |
$options.retry = (typeof $options.retry != "number") ? 30 : $options.retry; | |
$options.interval = $options.interval || 300; | |
if (_init($var) && (!$options.test || $options.test(w))) { | |
_debug("Kissogram Toolkit : unsafeWindow injection succeed!"); | |
return $func(w, w[$var]); | |
} | |
if ($options.retry-- > 0) | |
setTimeout(function () { _onUnsafeWindowReady($var, $func, $options); }, $options.interval); | |
} | |
var $c = { | |
// get unsafeWindow if possible | |
get : function ($var) { | |
return (this.getUnsafeWindow($var) || window)[$var]; // return safe window | |
}, | |
// get unsafeWindow | |
getUnsafeWindow : function ($var) { | |
return _init($var); | |
}, | |
/* | |
when specific function is ready | |
options : { | |
test : a function that test if specific variable is loaded properly | |
retry : retry times before test() returns a failure, default is 40 | |
interval : the interval between every check, default is 300 ms | |
} | |
*/ | |
onReady : _onUnsafeWindowReady , | |
size : getSize, | |
onResize : function ($func, $init) { | |
if ($init) | |
$func(); | |
resizeTasks.push($func); | |
return resizeTasks.length-1; | |
}, | |
_onResize : function ($id) { | |
if ($id || $id==0) | |
delete resizeTasks[$id]; | |
}, | |
isScroll : _isScroll, | |
onScroll : function ($func, $init) { | |
if ($init) | |
$func(); | |
scrollTasks.push($func); | |
return scrollTasks.length-1; | |
}, | |
_onScroll : function ($id) { | |
if ($id || $id==0) | |
delete scrollTasks[$id]; | |
} | |
}; | |
return $c; | |
})(); | |
// css Class | |
var $$css = (function () { | |
var css_enabled = [], | |
root = $$d.documentElement, | |
FEATURE_LIST_ATTR = "feature-list", | |
CSS_ELEM_REGEXP = /^\s*[.\w][.\w\d-]+[\w\d-]\s*$/; | |
var instance = function ($arg) { | |
extend(this, $c); | |
if ($arg) | |
this.dictionary = this.dictionary.concat($arg.reverse()); //define the css dictionary | |
}; | |
// effective only for Chrome | |
function _getMediaQueriesWidth() { | |
if ($$browser == "firefox") | |
return window.innerWidth; | |
// for Chrome, the width in Media Queries is quite close to window.outerWidth | |
for (var i=1, width = window.outerWidth, match=0; !match; i++) { | |
if (width > 0) | |
match = window.matchMedia('(min-width :' + width + 'px) and (max-width:'+ width + 'px)').matches; | |
if (match) | |
return width; | |
width += (i%2 == 0 ? 1 : -1) * i; | |
} | |
} | |
// to be compatible with Opera | |
var _addStyle = (typeof GM_addStyle != "undefined") ? GM_addStyle : function($css) { | |
var NSURI = 'http://www.w3.org/1999/xhtml'; | |
var head = document.getElementsByTagName('head')[0]; | |
var p = head || document.documentElement; | |
var elem = document.createElementNS(NSURI,'link'); | |
elem.setAttributeNS(NSURI,'rel','stylesheet'); | |
elem.setAttributeNS(NSURI,'type','text/css'); | |
elem.setAttributeNS(NSURI,'href','data:text/css,'+encodeURIComponent($css)); | |
if (head) | |
p.appendChild(elem); | |
else | |
p.insertBefore(elem, p.firstChild); | |
} | |
var $c = { | |
dictionary : [], | |
ns : 'gpp-', // name space | |
// append a class to an element | |
add : function ($elem, $className) { | |
if (!$elem || !CSS_ELEM_REGEXP.test($className = this.get($className))) | |
return; | |
$className = $className.replace(/\./g, ' '); | |
var arr = $className.split(' '), appendList = ""; | |
for (var i=0, clazz = " "+$elem.className+" "; i<arr.length; i++) | |
if (arr[i] && clazz.indexOf(' '+arr[i]+' ') < 0) | |
appendList+= ' '+ arr[i]; | |
$elem.className = utils.trimS($elem.className + appendList); | |
}, | |
remove : function ($elem, $className) { | |
if (!$elem || !CSS_ELEM_REGEXP.test($className = this.get($className))) | |
return; | |
$className = utils.trimS($className.replace(/\./g, ' ')); | |
var arr = $className.split(' '), clazz = " "+$elem.className+" "; | |
for (var i=0; i<arr.length; i++) | |
clazz = clazz.replace(' '+ arr[i] +' ', ' '); | |
$elem.className = utils.trimS(clazz); | |
}, | |
// append css | |
set : function ($str) { | |
_addStyle(this.get($str)); | |
}, | |
get : function ($str) { | |
$str = ($str || '').replace(/\/\*[\s\S]*?\*\//g, ''); // clear the comment | |
// backforwards | |
for (var i=0; i<this.dictionary.length; i++) | |
$str = $str.replace(this.dictionary[i][0], this.dictionary[i][1]); | |
return $str; | |
}, | |
// get value | |
val : function ($str) { | |
var arr = this.get($str).split(/[^\w-]/); | |
do { | |
var val = arr.pop(); | |
if (val) | |
return val; | |
} while (arr.length>0); | |
return null; // not found | |
}, | |
push : function ($arg, $str, $opt) { | |
$opt = $opt || {}; | |
var condition = this.getCondition($arg); | |
if ($opt.enable) | |
this.enable({ name: $arg, value: $opt.value }); | |
$str = $str.replace(/((?:[^,{]+,?)*)\s*{([^}]+)}/g, condition+"$1 {$2}"); | |
$str = $str.replace(/,/g, ","+condition); | |
this.set($str); | |
}, | |
pull : function ($feature) { | |
return css_enabled[$feature] || null; | |
}, | |
enable : function ($arg) { | |
if (!$arg) return; | |
var feaAttr = this.getFeatureListAttr(), | |
ns = this.ns, | |
data = " "+(root.getAttribute(feaAttr)||"")+" ", | |
appendList = ""; | |
utils.toArray($arg).forEach( | |
function ($item) { | |
var obj = (typeof $item=="string") ? { name: $item } : $item; | |
// when $value is null, assert it is a boolean | |
if (!obj.value && obj.value != 0) { | |
var name = " "+ obj.name +" "; | |
if (data.indexOf(name) < 0) | |
appendList += name; | |
} | |
else | |
root.setAttribute(ns + obj.name, obj.value); | |
css_enabled[obj.name] = obj.value || 1; | |
} | |
); | |
if (appendList) | |
root.setAttribute(feaAttr, utils.trimS(data + appendList)); | |
}, | |
disable : function ($arg) { | |
if (!$arg) return ''; | |
var feaAttr = this.getFeatureListAttr(), | |
ns = this.ns, | |
hasFeature = root.hasAttribute(feaAttr), | |
data = " "+(root.getAttribute(feaAttr)||"")+" "; | |
utils.toArray($arg).forEach( | |
function ($item) { | |
var obj = (typeof $item=="string") ? { name: $item } : $item; | |
if (hasFeature) | |
data = data.replace(" "+obj.name+" "," "); | |
root.removeAttribute(ns + obj.name); | |
delete css_enabled[obj.name]; | |
} | |
); | |
if (hasFeature) | |
root.setAttribute(feaAttr, utils.trimS(data)); | |
}, | |
getFeatureListAttr : function () { | |
return this.ns + FEATURE_LIST_ATTR; | |
}, | |
// has specific class | |
is : function ($elem, $className) { | |
if (!$elem) | |
return 0; | |
$className = utils.trimS(this.get($className).replace(/\./g, ' ')); | |
var arr = $className.split(' '), clazz = " "+$elem.className+" "; | |
for (var i=0; i<arr.length; i++) | |
if (clazz.indexOf(' '+ arr[i] +' ', ' ') < 0) | |
return 0; | |
return 1; | |
}, | |
select : function ($str) { | |
return $$d.querySelector(this.get($str)); | |
}, | |
selectAll : function ($str) { | |
return utils.toArray($$d.querySelectorAll(this.get($str))); | |
}, | |
getMediaQueriesWidth : _getMediaQueriesWidth, | |
extendDictionary : function ($dic) { | |
this.dictionary = this.dictionary.concat($dic.reverse()); | |
}, | |
// notice the difference between getCondition("string") and getCondition({name: "string"}) | |
// the first one will return featAttr~="string", the second one will return [ns+"string"] | |
getCondition : function ($arg) { | |
if (!$arg) return ''; | |
var condition = "html", | |
feaAttr = this.getFeatureListAttr(), | |
ns = this.ns; | |
utils.toArray($arg).forEach( | |
function ($item) { | |
var obj = (typeof $item=="string") ? { name: $item, blooeanVal: 1 } : $item; | |
condition += "["+ ( | |
obj.blooeanVal ? | |
feaAttr +'~="'+ obj.name +'"' : | |
(obj.value || obj.value==0) ? | |
ns + obj.name +'="'+ obj.value +'"' : | |
ns + obj.name | |
)+"]" | |
; | |
} | |
); | |
return condition+' '; | |
}, | |
// return a number of piexl from '##px' | |
getPiexls : function ($str) { | |
if (!/^\d+(px)?$/i.test($str)) | |
return null; // may be 'auto' or anything else | |
return parseInt($str.replace(/px$/i, "")); | |
}, | |
// get the absolute x / y of an element | |
getAbsPos : function ($e) { | |
var t = l = 0; | |
do { | |
t += $e.offsetTop; | |
l += $e.offsetLeft; | |
} while ($e = $e.offsetParent); | |
return { | |
left: l, | |
top: t | |
}; | |
} | |
}; | |
return extend(instance, $c); | |
})(); | |
// the Class that process url change | |
var $$url = (function () { | |
var _url = formatUrl(), | |
urlChangeTasks = [], | |
hashChangeTasks = [], | |
urlMonitor = null; | |
function isUrlChanged($url) { | |
var url = formatUrl($url); | |
if (url != _url) { | |
_url = url; | |
return 1; | |
} | |
else | |
return 0; | |
} | |
// turn http://xxx.xxx into http://xxx.xxx/ | |
function formatUrl($url) { | |
var url = $url || $$d.location.href; | |
if (/^https?:\/\/[\w.]+\w+$/.test(url)) | |
url += '/'; | |
return url; | |
} | |
function execTask($e) { | |
if (!$e) { | |
_debug('Kissogram Toolkit: URL changed!'); | |
each(urlChangeTasks); | |
} | |
else if ($e.type == "popstate") { | |
_debug('Kissogram Toolkit: URL [popstate] changed!'); | |
each(urlChangeTasks); | |
} | |
else if ($e.type == "hashchange") { // hashchange | |
_debug('Kissogram Toolkit: URL [hash] changed!'); | |
each(hashChangeTasks); | |
} | |
} | |
// bind onpopstate | |
window.addEventListener('popstate', function (e) { | |
if (isUrlChanged()) | |
execTask(e); | |
}); | |
// hashchange | |
window.addEventListener('hashchange', function (e) { | |
execTask(e); | |
}); | |
var $c = { | |
onUrlChange : function ($func, $init) { | |
if ($init) | |
$func(); | |
// mointor | |
if (urlMonitor == null) { | |
_debug('Kissogram Toolkit: URL onChange inited!'); | |
urlMonitor = setInterval(function () { | |
if (isUrlChanged()) | |
execTask(); | |
}, 500); | |
} | |
urlChangeTasks.push($func); | |
}, | |
onHashChange : function ($func, $init) { | |
if ($init) | |
$func(); | |
hashChangeTasks.push($func); | |
}, | |
onUrlMatch : function ($match, $func, $init) { | |
if (!$match) | |
return; | |
}, | |
toString : function () { | |
return _url = formatUrl(); | |
} | |
}; | |
return $c; | |
})(); | |
/* | |
listen to specific event | |
$options { | |
init : boolean / function | |
runOnce : boolean | |
interval | |
} | |
*/ | |
var listen = (function () { | |
var interval_count=[]; // collection of interval count | |
var _support = {}; | |
function testSupport($event) { | |
var e = $$d.querySelector("body"); | |
e.addEventListener($event, function fn() { | |
_support[$event] = 1; | |
e.removeEventListener($event, fn); | |
}); | |
} | |
function doTest() { | |
testSupport("DOMSubtreeModified"); | |
testSupport("DOMNodeInserted"); | |
testSupport("DOMNodeRemoved"); | |
// try insert a div and then remove it, will trigger all these three event if succeed | |
var test = $$d.createElement("div"), | |
e = $$d.querySelector("body") || $$d.body || $$d.documentElement; | |
e.appendChild(test); | |
e.removeChild(test); | |
} | |
// do dom event support test now -> Opear does not support DOMSubtreeModified | |
try { | |
doTest(); | |
} | |
catch (e) { | |
_debug("DOMSubtreeModified test failed. Something is wrong"); | |
} | |
var func = function ($selector, $event, $func, $options) { | |
$options = $options || {}; | |
// $event & $init cannot be 0 at the same time | |
if (!$event && !$options.init) | |
return; | |
var evt_listener = (function ($s, $e, $f, $o) { | |
var id = interval_count.length, | |
funcWithTiming = setFunctionTiming($f, { | |
interval : $o.interval || 0, | |
delay : $o.delay || 0 | |
}); | |
// bind event to dom object | |
var _bind = function ($d, $evt) { | |
$d.addEventListener($evt, | |
(function () { | |
var runOnceFunc = setFunctionTiming(function () { | |
$f.apply($d, utils.toArray(arguments), 0); | |
$d.removeEventListener($evt, runOnceFunc); | |
}, { delay: $o.delay }), | |
newFunc = function () { | |
funcWithTiming.apply($d, utils.toArray(arguments)); | |
}; | |
return $o.runOnce ? runOnceFunc : newFunc ; | |
})() | |
); | |
}; | |
return function () { | |
// if $s is a element itself | |
var dom = utils.toArray( | |
(typeof $s == 'string') ? $$css.selectAll($s) : $s | |
); | |
if (dom.length > 0) { | |
// dom is captured | |
clearInterval(interval_count[id]); | |
delete interval_count[id]; | |
// to be compatible with Opera!! for DOMSubtreeModified! | |
if (!_support["DOMSubtreeModified"]) { | |
if (utils.isStrictArray($e)) { | |
var DOMInsert = -1, DOMRemove = -1, DOMSub = -1; | |
for (var i=0;i<$e.length;i++) | |
if ($e == "DOMNodeInserted") | |
DOMInsert = i; | |
else if ($e == "DOMNodeRemoved") | |
DOMRemove = i; | |
else if ($e == "DOMSubtreeModified") | |
DOMSub = i; | |
if (DOMSub > -1) { | |
$e.splice(DOMSub, i); | |
if (DOMInsert < 0) | |
$e.push("DOMNodeInserted"); | |
if (DOMRemove < 0) | |
$e.push("DOMNodeRemoved"); | |
} | |
} | |
else if ($e == "DOMSubtreeModified") | |
$e = ["DOMNodeInserted", "DOMNodeRemoved"]; | |
} | |
for (var i=0; i<dom.length; i++) { | |
// if the function need initiation (when the listen function capture the dom objects the first time) | |
if ($o.init) { | |
if (typeof $o.init == "function") | |
$o.init.call(dom[i]); | |
else | |
$f.call(dom[i]); | |
} | |
if (utils.isStrictArray($e)) | |
each($e, function () { _bind(dom[i], this); }); | |
else if (typeof $e == "string") // when $e != null | |
_bind(dom[i], $e); | |
else { // do nothing | |
} | |
} | |
} | |
} | |
})($selector, $event, $func, $options); | |
// check it later | |
interval_count.push(setInterval(evt_listener, 500)); | |
}; | |
return func; | |
})(); | |
var mouse = (function () { | |
// simluate a click event | |
function click($elem, $options) { | |
if (!$elem) | |
return; | |
$options = $options || {}; | |
var opt = { | |
button : $options.button || 0 | |
}; | |
// dispatch click event following the W3C order | |
var e = $$d.createEvent("MouseEvents"); | |
e.initMouseEvent("mousedown", 1, 1, window, 0, 0, 0, 0, 0, 0, 0, 0, 0, opt.button, null); | |
$elem.dispatchEvent(e); | |
e = $$d.createEvent("MouseEvents"); | |
e.initMouseEvent("mouseup", 1, 1, window, 0, 0, 0, 0, 0, 0, 0, 0, 0, opt.button, null); | |
$elem.dispatchEvent(e); | |
e = $$d.createEvent("MouseEvents"); | |
e.initMouseEvent("click", 1, 1, window, 0, 0, 0, 0, 0, 0, 0, 0, 0, opt.button, null); | |
$elem.dispatchEvent(e); | |
} | |
return { | |
"click" : click | |
}; | |
})(); | |
// xml http request | |
var httpRequest = (function () { | |
function _send($arg) { | |
var req = new XMLHttpRequest(); | |
req.onreadystatechange = function() { | |
var res = { | |
responseXML: (req.readyState==4 ? req.responseXML : ''), | |
responseText: (req.readyState==4 ? req.responseText : ''), | |
readyState: req.readyState, | |
responseHeaders: (req.readyState==4 ? req.getAllResponseHeaders() : ''), | |
status: (req.readyState==4 ? req.status : 0), | |
statusText: (req.readyState==4 ? req.statusText : '') | |
} | |
if (req.readyState == 4) | |
res = { | |
responseXML: req.responseXML, | |
responseText: req.responseText, | |
readyState: req.readyState, | |
responseHeaders: req.getAllResponseHeaders(), | |
status: req.status, | |
statusText: req.statusText | |
}; | |
if ($arg["onreadystatechange"]) | |
$arg["onreadystatechange"](res); | |
if (req.readyState == 4) { | |
if ($arg["onload"] && req.status>=200 && req.status<300) | |
$arg["onload"](res); | |
if ($arg["onerror"] && (req.status<200 || req.status>=300)) | |
$arg["onerror"](res); | |
} | |
} | |
try { | |
//cannot do cross domain | |
req.open($arg.method, $arg.url); | |
} | |
catch(e) { | |
if ($arg["onerror"]) { | |
//simulate a real error | |
$arg["onerror"]({ | |
responseXML:'', | |
responseText:'', | |
readyState:4, | |
responseHeaders:'', | |
status:403, | |
statusText:'Forbidden' | |
}); | |
} | |
return; | |
} | |
if ($arg.headers) { | |
for (var prop in $arg.headers) | |
req.setRequestHeader(prop, $arg.headers[prop]); | |
} | |
req.send((typeof($arg.data)!='undefined') ? $arg.data : null); | |
} | |
return { | |
"send": (typeof GM_xmlhttpRequest == "undefined") ? _send : GM_xmlhttpRequest | |
}; | |
})(); | |
function _debug($msg) { | |
if (DEBUG_ON) | |
console.debug($msg); | |
} | |
// Main function begin ======================================== | |
// constructor | |
var $$c = function () { | |
}; | |
return extend($$c, { | |
"each" : each, | |
"extend" : extend, | |
"css" : $$css, | |
"listen" : listen, | |
"url" : $$url, | |
"mouse" : mouse, | |
"browser" : $$browser, | |
"window" : $$w, | |
"select" : function (e) { return $$css.select(e) }, | |
"selectAll" : function (e) { return $$css.selectAll(e) }, | |
"tickTork" : setFunctionTiming, | |
"utils" : utils, | |
"debug" : _debug, | |
"httpRequest" : httpRequest | |
}); | |
})(document); | |
// main function | |
var StraightGoogle = (function ($$d) { | |
// expand goo.gl shorten url | |
var expand_short_url = (function () { | |
var url_cache = {}; | |
var GOOGLE_SHORTEN_URL_REG = /^(?:https?:\/\/)?goo\.gl\/(\w+)$/i; | |
var GOOGLE_SHORTEN_URL_API = "https://www.googleapis.com/urlshortener/v1/url?shortUrl={$url}"; | |
return function ($url, $callback) { | |
var match = GOOGLE_SHORTEN_URL_REG.exec($url); | |
if (!match) | |
return; | |
var key = match[1]; | |
if (url_cache[key]) | |
return $f(url_cache[key]); | |
// query Google Shorten URL API | |
$K.debug('Straight Google : trying to expand shorten URL ['+ $url +']'); | |
$url = /^https?:\/\//.test($url) ? $url : 'http://'+ $url; | |
$K.httpRequest.send({ | |
method : 'GET', | |
url : GOOGLE_SHORTEN_URL_API.replace('{$url}', $url), | |
onload : (function ($u, $f) { | |
return function (res) { | |
try { | |
eval('var obj = '+ res.responseText); | |
} catch (e) { | |
return; | |
} | |
if (obj.status != "OK") | |
return; | |
$K.debug('Straight Google : shorten URL expanded ['+ obj["longUrl"] +']'); | |
// call back | |
url_cache[$u] = obj["longUrl"]; | |
$f(obj["longUrl"]); | |
}; | |
})($url, $callback), | |
onerror : function (res) { | |
$K.debug('Straight Google : fail to expand shorten URL ['+ res["finalUrl"] +']'); | |
} | |
}); | |
}; | |
})() | |
// fetch Google Redirection Traget | |
function get_google_url($url, $urlType) { | |
if (!$url) | |
return; | |
var google_url_reg = [], mat = null, res; | |
// for Google Image Redirection | |
switch ($urlType) { | |
case 1 : // image reference url | |
google_url_reg.push(/^(?:https?:\/\/[-\w\d.]+\.google\.\w[\w.]*\w(?:\/\w+)*)?\/imgres\?(?:(?!imgrefurl)\w+=[^&]*&)*(?:imgrefurl)=((?:https?(?::\/\/|%3A%2F%2F))?[^&]+).*$/i); | |
break; | |
case 2 : // match imgurl only ( Google Image ) | |
google_url_reg.push(/^(?:https?:\/\/[-\w\d.]+\.google\.\w[\w.]*\w(?:\/\w+)*)?\/imgres\?(?:(?!imgurl)\w+=[^&]*&)*imgurl=((?:https?(?::\/\/|%3A%2F%2F))?[^&]+).*$/i); | |
break; | |
default : | |
google_url_reg.push(/^(?:https?:\/\/[-\w\d.]+\.google\.\w[\w.]*\w(?:\/\w+)*)?\/(?:(?:local_)?url|imgres|aclk)\?(?:(?!url|imgurl|adurl)\w+=[^&]*&)*(?:url|imgurl|adurl)=((?:https?(?::\/\/|%3A%2F%2F))?[^&]+).*$/i); | |
google_url_reg.push(/^(?:https?:\/\/[-\w\d.]+\.google\.\w[\w.]*\w(?:\/\w+)*)?\/(?:(?:local_)?url|imgres|aclk)\?(?:(?!q)\w+=[^&]*&)*(?:q)=((?:https?(?::\/\/|%3A%2F%2F))?[^&]+).*$/i); | |
} | |
for (var i=0;i<google_url_reg.length;i++) { | |
mat = mat || $url.match(google_url_reg[i]); | |
res = mat ? unescape(mat[1] || '') : ''; | |
if (/^(https?:\/\/)?[a-zA-Z\.\-&:0-9]+\.[a-zA-Z0-9\-]/i.test(res)) | |
break; | |
} | |
// fix http:// | |
if (res && !/^https?:\/\//.test(res)) | |
res = "http://"+ res; // default http | |
return res; | |
} | |
function google_url_clean($urlType) { | |
var url = get_google_url(this.href, $urlType); | |
if (url) { | |
this.href = url; | |
$K.debug('Redirection of ['+ url +'] is now removed.'); | |
} | |
do_not_track.call(this); | |
// try to expand shorten url | |
expand_short_url(url || this.href, (function (obj) { | |
return function (url) { | |
if (obj) obj.href = url; | |
}; | |
})(this)); | |
return url || ''; | |
} | |
function common_clean_job() { | |
$K.listen('a[href*="/url?"], a[href*="/aclk?"]', null, google_url_clean, { init : 1 }); // this applys for static pages | |
} | |
function do_not_track() { | |
// add no follow | |
if (!this.getAttribute("rel")) this.setAttribute("rel", "noreferrer"); | |
} | |
// Main part begin ======================================== | |
function _start() { | |
// prevent Google Plus redirection : plus.url.google.com | |
if (/:\/\/plus\.google\.com\/.*$/.test($K.url)) { | |
// this the main js which causes the redirection | |
if (/\/_\/scs\/apps-static\/_\/js\//.test($K.url)) { | |
$K.debug('Straight Google [Plus] is now loaded'); | |
// keyword: "/url?sa=z&n=" | |
// kill the redirection function directly | |
$K.window.onReady( | |
"lAa", | |
function ($w) { | |
if ((''+$w["lAa"]).indexOf('/url?sa=')>-1) { | |
$K.debug('Injection for Google Plus succeeds!'); | |
$w["lAa"] = function () { }; | |
} | |
else { | |
$K.debug('Injection for Google Plus fails'); | |
} | |
} | |
); | |
} | |
} | |
// Google News | |
else if (/:\/\/news\.google\.[\w.]+\w\/.*$/.test($K.url) || /:\/\/www\.google\.[\w.]+\w\/news\/.*$/.test($K.url)) { | |
$K.debug('Straight Google [News] is now loaded'); | |
$K.listen( | |
'.blended-section', | |
"DOMNodeInserted", | |
function () { | |
$K.each( | |
$K.selectAll('a.article[url]:not(._tracked)'), | |
function () { | |
// fix link to its normal url | |
this.href = this.getAttribute('url'); | |
do_not_track.call(this); | |
$K.debug("Redirection of ["+ this.href +"] is now removed."); | |
// cheat google and say "it has been tracked already" | |
$K.css.add(this,' _tracked'); | |
} | |
); | |
}, | |
{ init: 1 } | |
); | |
} | |
// Google Docs | |
else if (/:\/\/docs\.google\.com\/.+/.test($K.url)) { | |
$K.debug('Straight Google [Docs] is now loaded'); | |
// Spread Sheet | |
if (/docs\.google\.com\/spreadsheet\/.+/.test($K.url)) | |
$K.listen( | |
'a.docs-bubble-link[target="_blank"]', | |
'mouseover', | |
google_url_clean | |
); | |
// Other products | |
else if (/docs\.google\.com\/(document|presentation|drawings)\/.+/.test($K.url)) | |
$K.listen( | |
'.docs-bubble a[target="_blank"]', | |
'mouseover', | |
google_url_clean | |
); | |
} | |
// Google Maps | |
else if (/:\/\/(ditu|maps)\.google\.com\/.*$/.test($K.url) || /:\/\/www\.google\.com\/maps((\?|\/).*)?$/.test($K.url)) { | |
$K.debug('Straight Google [Maps] is now loaded'); | |
var match_pattern = '#resultspanel a[href*="/local_url?"]'; | |
// inject as a local function when output is js | |
if (/output=js/.test($K.url)) | |
$K.window.onReady('w', | |
function ($w, $var) { | |
if (!$var["loadVPage"]) | |
return; | |
// select parent window's elements | |
$K.listen($var.document.querySelectorAll(match_pattern), null, google_url_clean, { init : 1 }); | |
} | |
); | |
else | |
$K.listen(match_pattern, null, google_url_clean, { init : 1 }); | |
} | |
// Google Groups | |
else if (/:\/\/groups\.google\.com\/(forum|group)\/.+/.test($K.url)) { | |
$K.debug('Straight Google [Groups] is now loaded'); | |
// for old Google Groups template | |
if (/groups\.google\.com\/group\/.+/.test($K.url)) | |
common_clean_job(); | |
} | |
// Google Bookmarks | |
else if (/:\/\/(www|history)\.google\.com\/bookmarks\/.*$/.test($K.url)) { | |
$K.debug('Straight Google [Bookmarks] is now loaded'); | |
$K.each( | |
$K.selectAll('.result a[id^="bkmk_href_"]'), | |
google_url_clean | |
); | |
} | |
// Google Web History | |
else if (/:\/\/(www|history)\.google\.com\/history\/.*$/.test($K.url)) { | |
$K.debug('Straight Google [Web History] is now loaded'); | |
common_clean_job(); | |
} | |
// Google Mail | |
else if (/:\/\/(www|mail)\.google\.com\/mail\/.*$/.test($K.url)) { | |
$K.debug('Straight Google [Mail] is now loaded'); | |
common_clean_job(); | |
} | |
// Google Play | |
else if (/:\/\/(www|play)\.google\.com\/store\/.*$/.test($K.url)) { | |
$K.debug('Straight Google [Play] is now loaded'); | |
common_clean_job(); | |
} | |
// Google Image Search | |
else if (/:\/\/(www|encrypted|ipv6)\.google\.[\w.]+\w\/(imghp\?.+|search(\?|#)(.+&)*tbm=isch(&.+)*)$/.test($K.url)) { | |
$K.debug('Straight Google [Image] is now loaded'); | |
$K.window.onReady( | |
'_', | |
function ($w) { | |
try { | |
if ((''+$w._.Tj.G().J).indexOf('/url?sa=')>-1) { | |
$w._.Tj.G().J = function () { }; | |
} | |
/* keyword | |
for (var b = [(0, _.H)("irc_fn"), (0, _.H)("irc_fsl"), (0, _.H)("irc_hol"), (0, _.H)("irc_itl"), (0, _.H)("irc_ifl"), (0, _.H)("irc_kl"), (0, _.CP)().va("irc_mil"), (0, _.H)("irc_vpl")], c = 0; c < b.length; ++c) b[c] && (b[c].onmousedown = (0, _.hna)(a, b[c]), a.X.listen(b[c], "keydown", (0, _.ib)(function(a, b) { | |
if (13 == (new _.yg(b)).keyCode && a.onmousedown) a.onmousedown(b) | |
}, | |
*/ | |
if ((''+ $w._.PR).indexOf('irc_fsl')>-1 && (''+ $w._.PR).indexOf('irc_hol')>-1 && (''+ $w._.PR).indexOf('irc_tas')>-1) { | |
$w._.PR = function () {}; // reset the redirection function | |
} | |
} | |
catch (e) { | |
$K.debug('Fail to inject!'); | |
} | |
}, | |
{ | |
test: function (w) { | |
// if Google Image script is initialized | |
return !!w['_'] && !!w._.PR && !!w._.Tj; | |
} | |
} | |
); | |
} | |
// Google Shopping | |
else if (/:\/\/www\.google\.com\/(products\/catalog\?|shopping\/product\/|prdhp).*/.test($K.url)) { | |
$K.debug('Straight Google [Shopping] is now loaded'); | |
$K.listen( | |
"#os-sellers-content", | |
"DOMSubtreeModified", | |
common_clean_job, | |
{init:1} | |
); | |
// Show All # function | |
if (/\/products\/catalog\?/.test($K.url)) | |
$K.window.onReady('showPlusBox', | |
(function () { | |
var originFunc = null; | |
return function ($w, $var) { | |
originFunc = $var; | |
$w["showPlusBox"] = function () { | |
originFunc.apply(this, $K.utils.toArray(arguments)); | |
common_clean_job(); | |
} | |
}; | |
})() | |
); | |
} | |
// Google Web Search (iframed) | |
else if (/:\/\/(www|encrypted|ipv6)\.google\.[\w.]+\w\/cse\?.+/.test($K.url)) { | |
$K.debug('Straight Google [iFramed Web Search] is now loaded'); | |
$K.window.onReady( | |
'google', | |
function ($w) { | |
try { | |
// kill the redirection function | |
$w.google["search"].Z.Yi = function () {}; | |
// or redirect the track Url to origin Url | |
//$w.google["search"].Z.Hi = $w.google["search"].Z.Zi; | |
} | |
catch (e) {} | |
} | |
); | |
} | |
// Google Web Search | |
else if (/:\/\/(www|encrypted|ipv6)\.google\.[\w.]+\w\/(search|webhp\?.+|(search|webhp)?(\?|#)(.+&)*(q|tbs|as_q)=.+)?$/.test($K.url)) { | |
$K.debug('Straight Google [Web Search] is now loaded'); | |
var refUrl = 'ori-url', isCleanLink = "is-clean-link"; | |
function img_search_clean() { | |
// for Image links | |
var cur_expanded = $K.select('#rg_h[data-initialized="1"]'); | |
if (!cur_expanded) | |
return; | |
var span = cur_expanded.querySelector('.rg_hr span#rg_hr'); | |
var rg_hta = cur_expanded.querySelector('#rg_ht a#rg_hta'); | |
var clean_href = rg_hta.href; | |
var rg_l = $K.select('#ires a.rg_l[href="'+ clean_href +'"]['+ refUrl +']'); | |
if (!clean_href || !rg_l) | |
return; | |
var ref_url = rg_l.getAttribute(refUrl); | |
rg_hta.href = get_google_url(ref_url, 1); | |
} | |
function img_url_clean() { | |
// before expanding | |
$K.each( | |
$K.selectAll('#ires a[href*="/imgres?"]:not(['+isCleanLink+'])'), | |
function () { | |
this.setAttribute(refUrl, this.href); // straight google - url | |
google_url_clean.call(this, 2); | |
} | |
); | |
} | |
function search_clean() { | |
// image redirection | |
common_clean_job(); | |
img_url_clean(); | |
$K.each( | |
$$d.querySelectorAll('a[href][onmousedown]'), | |
function () { | |
if (this.removeAttribute) | |
this.removeAttribute('onmousedown'); | |
} | |
); | |
} | |
// do a deep clean, kill the redirection function, which rwt points to | |
$K.window.onReady( | |
'_', | |
function ($w) { | |
try { | |
// keyword: 'rwt' | |
if ((''+$w._.Tj.G().J).indexOf('/url?sa=')>-1) { | |
$w._.Tj.G().J = function ($_self) { | |
$_self.removeAttribute('onmousedown'); | |
}; | |
} | |
} | |
catch (e) { | |
$K.debug('Fail to inject!'); | |
} | |
}, | |
{ | |
test : function (w) { | |
return !!w['_'] && !!w['_'].Tj; | |
} | |
} | |
); | |
// for Google Instant | |
$K.url.onHashChange(search_clean, 1); | |
// be cool with AutoPager & lazy-load content | |
setTimeout(search_clean, 200); | |
} | |
// for Youtube | |
else if (/:\/\/(\w+\.)*youtube\.com\//.test($K.url)) { | |
$K.debug('Straight Google [Youtube] is now loaded'); | |
var YOUTUBE_REDIRECT_CLASS = '.yt-uix-redirect-link'; | |
$K.each( | |
$K.selectAll(YOUTUBE_REDIRECT_CLASS), | |
function () { | |
$K.css.remove(this, YOUTUBE_REDIRECT_CLASS); | |
$K.debug("Redirection of link ["+ this.href +"] is now removed."); | |
} | |
); | |
} | |
} | |
return { | |
start : _start | |
}; | |
})(document); | |
$K.debug('Straight Google is enabled in current URL ['+ $K.url +'].'); | |
StraightGoogle.start(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment