Sunday, February 26, 2012

Straight Google


// ==UserScript==
// @name Straight Google
// @id straight_google_pokerface
// @namespace   in.co.tossing.toolkit.google
// @description Remove URL redirection from google products
// @license GPL v3 or later version
// @updateURL   http://userscripts.org/scripts/source/121261.meta.js
// @include  *://www.google.*/*?q=*
// @include  *://www.google.*/*?tbs=*
// @include  *://www.google.*/*&q=*
// @include  *://www.google.*/*#q=*
// @include  *://www.google.*/
// @include  *://encrypted.google.*
// @include  *://ipv6.google.*
// @include  *://www.google.*/news*
// @include  *://news.google.*/*
// @include  *://plus.google.com/*
// @include  *://docs.google.com/*
// @include  *://maps.google.com/*
// @include  *://www.google.com/maps*
// @include  *://ditu.google.com/*
// @include  *://groups.google.com/group/*
// @version 1.1
// @author Pokerface - Kevin
// ==/UserScript==

(function ($$d) {
 // document URI
 var $$url = $$d.baseURI;
 //console.debug('Current URI : '+ $$url);
 
 // unsafe window
 var $$w = null;
 
 // get unsafeWindow
 var injectWindow = (function () {
 var retry = 0;
 return function ($var, $func, $testFunc) {
  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) {}
  }
  if ($$w && (($testFunc && $testFunc($$w)) || !$testFunc))
   return $func();
  // if window loading is not successful, retry for 12000ms
  if (++retry<40)
   setTimeout((function ($v, $f, $t) {
    return function () { injectWindow($v, $f, $t); };
    })($var, $func, $testFunc), 300);
 }
 })();
 
 // for each
 function each($arr, $fun) {
  if (!$arr)
   return;
  //console.debug('each function is called. arr length is '+ $arr.length);
  for (var i=$arr.length-1; i >=0; i--)
   $fun.call($arr[i]);
 }
 
 // expand goo.gl shorten url
 function expand_short_url($url, $callback) {
  if (!/^(?:https?:\/\/)?goo\.gl\/\w+$/.test($url))
   return;
  var api = "https://www.googleapis.com/urlshortener/v1/url?shortUrl={$url}";
  // query Google Shorten URL API
  console.debug('Straight Google : trying to expand shorten URL ['+ $url +']');
  GM_xmlhttpRequest({
   method : 'GET',
   url : api.replace('{$url}', /^https?:\/\//.test($url) ? $url : 'http://'+ $url),
   onload : (function ($f) {
    return function (res) {
     try {
      eval('var obj = '+ res.responseText);
     } catch (e) {
      return;
     }
     if (obj.status != "OK")
      return;
     console.debug('Straight Google : shorten URL expanded ['+ obj.longUrl +']');
     // call back
     $f(obj.longUrl);
    };
   })($callback),
   onerror : function (res) {
    console.debug('Straight Google : fail to expand shorten URL ['+ res.finalUrl +']');
   }
  });
 }
 
 // fetch Google Redirection Traget
 function get_google_url($url) {
  if (!$url)
   return;
  var google_url_reg = /^(?:https?:\/\/.+\.google\..+)?\/(?:local_)?url\?(?:(?!url|q)\w+=[^&]*&)*(?:url|q)=((?:https?(?::\/\/|%3A%2F%2F))?[^&]+).*$/i;
  var mat = $url.match(google_url_reg); 
  var res = mat ? unescape(mat[1] || '') : '';
  // fix http://
  if (res && !/^https?:\/\//.test(res))
   res = "http://"+ res; // default http
  return res;
 }
 
 function google_url_clean() {
  var url = get_google_url(this.href);
  if (url) {
   this.href = url;
   console.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 do_not_track() {
  // add no follow
  if (!this.getAttribute("rel"))
   this.setAttribute("rel", "noreferrer");
 }
  
 // listen to specific event
 var listen = (function () {
  var interval_count=[];
  return function ($$dom, $event, $func, $init) {
   var evt_listener = (function ($$dom, $e, $f, $i) {
    var id = interval_count.length;
    return function () {
     var dom = $$d.querySelectorAll($$dom);
     if (dom.length > 0) {
      //console.debug('Event for ['+ $$dom +'] is now binded');
      clearInterval(interval_count[id]);
      delete interval_count[id];
      for (var i=0; i<dom.length; i++) {
       // if the function need initiation
       if ($i)
        $f.call(dom[i]);
       if ($e instanceof Array)
        each(
         $e,
         function () {
          bindEvent(dom[i], this, $f);
         }
        );
       else
        bindEvent(dom[i], $e, $f);
      }
     }
    }
   })($$dom, $event, $func, $init);
   interval_count.push(setInterval(evt_listener, 500));
  }
 })();
 
 // shit IE
 function bindEvent($obj, $evt, $func) {
  if ($obj.addEventListener)
   $obj.addEventListener($evt, $func, false);
  else if ($obj.attachEvent)
   $obj.attachEvent((/^[a-z]+$/.test($evt) ? "on" : '')+ $evt, $func);
 }
 
 // Main part begin ========================================
 // prevent Google Plus redirection : plus.url.google.com
 if (/:\/\/plus\.google\./.test($$url)) {
  console.debug('Straight Google [Plus] is now loaded');
  function plus_clean() {
   each(
    // use 'do not track me' feature
    $$d.querySelectorAll('a.ot-anchor:not([rel])'),
    google_url_clean
   );
  }
  // notification bar
  if (/\/u\/0\//.test($$url) && $$d.querySelector('#summary-content')) {
   // plus home page
   injectWindow("OZ_initData", function () {
    $$w.OZ_initData["1"][20]="";
    console.debug('URL Redirection of Google Plus Notification is now prevented.');
   });
   listen(
    // notification stream
    '#summary-content', "DOMSubtreeModified", plus_clean, true
   );
  }
  else {
   // plus home page
   injectWindow("AF_initDataQueue", function () {
    for (var i=0, q = $$w.AF_initDataQueue; i<q.length; i++)
     if (q[i].key=="1") {
      q[i].data[20]=""; // clear plus.url.google.com
      console.debug('URL Redirection of Google Plus is now prevented.');
      break;
     }
   });
   // listen to the stream
   function _bind_stream() {
    listen(
     "div.lzqA1d", "DOMNodeInserted", plus_clean
    );
   }
   // page switch
   listen(
    '#gbqn', 'click', _bind_stream, true
   );
  }
 }
 // remove google news redirection here
 else if (/:\/\/news\.google\./.test($$url) || /:\/\/www\.google\..+\/news(\/.*)?/.test($$url)) {
  console.debug('Straight Google [News] is now loaded');
  listen(
   '.blended-section',
   "DOMNodeInserted", 
   function () {
     each(
      $$d.querySelectorAll('a.article[url]:not(._tracked)'),
      function () {
       // fix link to its normal url
       this.href = this.getAttribute('url');
       do_not_track.call(this);
       console.debug("Redirection of ["+ this.href +"] is now removed.");
       // cheat google and say "it has been tracked already"
       this.className += ' _tracked';
      }
     );
   },
   true
  );
 }
 // Google Docs
 else if (/docs\.google\.com\/.+/.test($$url)) {
  console.debug('Straight Google [Docs] is now loaded');
  // Spread Sheet
  if (/docs\.google\.com\/spreadsheet\/.+/.test($$url))
   listen('a.docs-bubble-link[target="_blank"]',['mouseup', 'mouseover'], google_url_clean);
  // Other products
  else if (/docs\.google\.com\/(document|presentation|drawings)\/.+/.test($$url))
   listen('div.docs-bubble a[target="_blank"]',['mouseup', 'mouseover'], google_url_clean);
 }
 // Google Maps
 else if (/(ditu|maps)\.google\.com/.test($$url) || /www\.google\.com\/maps/.test($$url)) {
  console.debug('Straight Google [Maps] is now loaded');
  listen('.pp-headline-authority-page a[target="_blank"]', 'mouseover', google_url_clean);
 }
 // Google Groups
 else if (/groups\.google\.com\/group\//.test($$url)) {
  console.debug('Straight Google [Groups] is now loaded');
  listen('#inbdy a[target="_blank"]', 'mouseover', google_url_clean);
 }
 // Google Search
 else if (/:\/\/(www|encrypted|ipv6)\.google\..+(\/((search)?(\?|#)|.+&)(q|tbs)=.+)?$/.test($$url)) {
  console.debug('Straight Google [Search] is now loaded');
  // do a deep clean, kill the rwt function
  injectWindow('rwt', function () {
   $$w.rwt = function ($_self) {
    google_url_clean.call($_self);
    $_self.removeAttribute('onmousedown');
    return true;
   };
  }, function (w) {
   return /google/i.test(''+ w['rwt']);
  });
  
  // define the elements need to be rebinded after page reloading
  var _rebind_elements = '#nav, #ms, #bms';
  
  function search_clean() {
   each(
    $$d.querySelectorAll('#ires a.l[href][onmousedown]'),
    function () {
     google_url_clean.call(this);
     this.removeAttribute('onmousedown');
     console.debug("Click event of link ["+ this.href +"] is now removed.");
    }
   );
   // image redirection
   each(
    $$d.querySelectorAll('#ires a[href^="/url?"]'),
    google_url_clean
   );
  }
  // enable google instant
  var page_clickevent = (function ($c) {
    var eid = '', interval=null, click_event;
    function check_eid() {
     var obj = $$d.querySelector('#rso');
     // the interval check runs until the eid is changed
     if (obj && obj.getAttribute('eid') != eid) {
      if (interval)
       clearInterval(interval);
      interval = null;
      // do clean job
      $c();
      // rebind the click event
      listen(_rebind_elements, "click", click_event);
     }
    }
    click_event = function() {
     var obj = $$d.querySelector('#rso');
     // record current eid
     eid = obj ? obj.getAttribute('eid') : '';
     if (!interval)
      interval = setInterval(check_eid, 500);
    }
    return click_event;
  })(search_clean);
  
  // listen to the pagenation
  listen(_rebind_elements, "click", page_clickevent);
  var googleinstant = (function ($c) {
   var eid='', interval=null;
   function check_eid() {
    // eid will change when the result is changed
    var res = $$d.querySelector('#rso');
    if (res && res.getAttribute('eid') != eid) {
     eid = res.getAttribute('eid');
     // do the clean
     $c();
     // re-bind event to pagenation
     listen(_rebind_elements, "click", page_clickevent);
    }
   };
   return function ($action) {
    if ($action == 'load')
     return function () {
      if (!interval)
       interval = setInterval(check_eid, 500);
     }
    else
     return function () {
      if (interval)
       clearInterval(interval);
      // clear interval
      interval = null;
      // run eid check for once
      page_clickevent();
     }
   }
   })(search_clean);
   
  // listen to the input box - for Google Instant
  listen('#lst-ib, #gbqfq', ['focus','keypress'] , googleinstant('load'));
  listen('#lst-ib, #gbqfq', 'blur', googleinstant('unload'));
  listen('table[dir="ltr"]', ['click','keypress'], page_clickevent);
  // input box mointering end

  // be cool with AutoPager
  listen("#navcnt", "DOMNodeInserted", search_clean, true);
 }
 
})(document);

0 comments:

Post a Comment