remove the jump link in BAIDU

去除百度搜索跳转链接

目前为 2015-08-24 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name remove the jump link in BAIDU
  3. // @author burningall
  4. // @description 去除百度搜索跳转链接
  5. // @version 2015.8.24
  6. // @include *www.baidu.com*
  7. // @grant GM_setValue
  8. // @grant GM_getValue
  9. // @grant GM_registerMenuCommand
  10. // @grant GM_xmlhttpRequest
  11. // @run-at document-start
  12. // @compatible chrome 完美运行
  13. // @compatible firefox 完美运行
  14. // @license The MIT License (MIT); http://opensource.org/licenses/MIT
  15. // @supportURL http://www.burningall.com
  16. // @contributionURL troy450409405@gmail.com|alipay.com
  17. // @namespace https://greasyfork.org/zh-CN/users/3400-axetroy
  18. // ==/UserScript==
  19.  
  20. //======说明=======
  21. /*
  22. 如果觉得卡顿
  23. 请修改配置参数项
  24.  
  25. config.isAnimate:GM_getValue("isAnimate",false) 关闭CSS3动画(默认开启)
  26. config.mixRequireMod:false 关闭混合请求(默认开启)
  27.  
  28.  
  29. 不懂代码就不用管
  30.  
  31. 混合请求说明:存在两种请求方式
  32. 1,把所有跳转链接请求个遍,类似于图片的延迟加载。页面滚动到哪里请求到哪里。
  33. 2,把当前页面的href的参数&fn=baiduhome_pg修改成&fn=baidulocal,得到一个全新的页面。也没的链接没有跳转,然后替换到当前页面的链接。
  34.  
  35. 如果关闭混合请求,那么执行第一种,第二种不执行。
  36.  
  37. 为什么关闭第二种方式:(不推荐关闭,理论上是好的)
  38. 存在缺陷,替换的链接不全。
  39. 请求的文件比第一种大,可能造成性能的问题。(chrome下和firefox下测试均没问题,当然,其他脚本\扩展也是用这种方法)。
  40. 请求方式的统一性。
  41. */
  42.  
  43. (function(document) {
  44. //=====配置参数======
  45. var config = {
  46. macthRules: 'a[href*="www.baidu.com/link?url"]:not([transcoding]):not([transcoded]):not([transcodedall]):not(.m)', //需要跳转的链接
  47. reloadRules: 'a[transcoded*="false"]', //请求失败,需要再次请求的链接
  48. isAnimate: GM_getValue("isAnimate",true), //是否需要请求动画,false为关闭动画,默认为true,开启
  49. transcodingAll:false,//是否正在请求全部,不要修改
  50. turn:false,//防止过多请求数,不要修改
  51. mixRequireMod:true//混合请求,默认开启
  52. };
  53. //匹配正则
  54. var regRules = {
  55. isJumpLink: /www.baidu.com\/link\?url=/ig,
  56. sliceResponse: {
  57. step1: /.*window\.location\.replace\(\"(.*)\"\).*$/img,
  58. step2: /^(.*)(<noscript>.*<\/noscript>$)/img
  59. }
  60. };
  61. //======事件对象=======
  62. function handler(obj) {
  63. return new Event(obj);
  64. }
  65. function Event(obj) {
  66. this.element = obj;
  67. return this;
  68. }
  69. Event.prototype.addEvent = function(type, fn) {
  70. var obj = this.element;
  71. var ev;
  72. return obj.addEventListener ?
  73. obj.addEventListener(type, function(e) {
  74. ev = window.event ? window.event : (e ? e : null);
  75. ev.target = ev.target || ev.srcElement;
  76. if (fn.call(obj, ev) === false) {
  77. ev.cancelBubble = true; //阻止冒泡
  78. ev.preventDefault(); //chrome,firefox下阻止默认事件
  79. }
  80. }, false) :
  81. obj.attachEvent('on' + type, function(e) {
  82. ev = window.event ? window.event : (e ? e : null);
  83. ev.target = ev.target || ev.srcElement;
  84. if (fn.call(obj, ev) === false) {
  85. ev.cancelBubble = true; //阻止冒泡
  86. return false; //阻止默认事件,针对IE8
  87. }
  88. });
  89. };
  90. Event.prototype.bind = function(type, fn) {
  91. var obj = this.element;
  92. if (arguments.length == 1) {
  93. for (var attr in type) {
  94. this.addEvent(attr, type[attr]);
  95. }
  96. } else if (arguments.length == 2) {
  97. var events = type.split(' ');
  98. var eventsLength = events.length;
  99. var j = 0;
  100. while (j < eventsLength) {
  101. this.addEvent(events[j], fn);
  102. j++;
  103. }
  104. }
  105. return this;
  106. };
  107. Event.prototype.ob = function(config, fn) {
  108. var target = this.element;
  109. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver,
  110. observer = new MutationObserver(function(mutations) {
  111. mutations.forEach(function(mutation) {
  112. fn.call(target);
  113. });
  114. });
  115. observer.observe(target, config);
  116. return this;
  117. };
  118. //======公共函数=======
  119. function getText(obj){
  120. if( obj.innerText ){
  121. return obj.innerText;
  122. }else{
  123. return obj.textContent;
  124. }
  125. }
  126. function ajax(url,json,a){
  127. a = a ? a : window;
  128. if( typeof json.beforeFn !=="undefined"){
  129. if( json.beforeFn.call(a,url)===false ) return;//this>>>a
  130. }
  131. GM_xmlhttpRequest({
  132. method: "GET",
  133. url: url,
  134. onreadystatechange: function(response) {
  135. if (response.readyState == 4) {
  136. var status = response.status + '';
  137. if (status.charAt(0) == "4" || status.charAt(0) == "5") { //4XX,5XX错误
  138. if( typeof json.failFn !=="undefined"){
  139. json.failFn.call(a,status,url);//this>>>a
  140. }
  141. } else {
  142. if( typeof json.successFn !=="undefined"){
  143. json.successFn.call(a,response.responseText,url);//this>>>a
  144. }
  145. }
  146. }
  147. }
  148. });
  149. }
  150. //======主体对象=======
  151. function init(agm) {
  152. return new Init(agm);
  153. }
  154. function Init(agm) {
  155. this.addStyle();
  156. if (!agm) {
  157. return this;
  158. }
  159. this.jumpLinks = document.querySelectorAll(agm);//获取到要跳转的A链接
  160. this.inViewPort = [];//在可视区域内的跳转链接
  161. for (var j = 0; j < this.jumpLinks.length; j++) {
  162. this.a = this.jumpLinks[j];
  163. if (this.visible() === true) {
  164. this.inViewPort.push(this.jumpLinks[j]);
  165. }
  166. }
  167. return this;
  168. }
  169. Init.prototype.all = function(callBack){
  170. var searchWord = document.getElementById('kw').value;
  171. var url = window.top.location.href.replace('https', 'http').replace(/(\&)(tn=\w+)(\&)/img, '$1' + 'tn=baidulocal' + '$3').replace(/(\&)(wd=\w+)(\&)/img, '$1' + 'wd='+ searchWord + '$3');
  172. ajax(url,{
  173. "beforeFn":function(url){
  174. config.transcodingAll=true;
  175. config.turn=false;
  176. },
  177. "failFn":function(status,url){
  178. this.setAttribute("transcoded","false");
  179. },
  180. "successFn":function(response,url){
  181. var html = document.createElement('html');
  182. html.innerHTML = response.replace(/http\:\/\/(.*)\.gif/img, "https://wwwbaidu.com"); //防止讨厌的http百度图片
  183. var requireAtag = html.querySelectorAll('.f>a');//请求得到的所有A标签
  184. var info = {};//href:innerText
  185. for (var i = 0; i < requireAtag.length; i++) {
  186. if (typeof(info[requireAtag[i].href]) == "undefined") {
  187. info[ requireAtag[i].href ] = getText( requireAtag[i] );
  188. }
  189. }
  190. var currentAtag = document.querySelectorAll('.t>a:not(.OP_LOG_LINK):not([transcoded])');//当前页的A标签
  191. for (var href in info) {
  192. for (var j = 0; j < currentAtag.length; j++) {
  193. if ( info[href].replace(/\s*/img, '') == getText( currentAtag[j] ).replace(/\s*/img,'') ) {
  194. currentAtag[j].href = href;
  195. currentAtag[j].setAttribute('transcodedAll','true');
  196. // currentAtag[j].style.background = 'red';
  197. }
  198. }
  199. }
  200. config.transcodingAll=false;
  201. config.turn = true;
  202. if(callBack) callBack();
  203. }
  204. });
  205. };
  206. if( config.mixRequireMod===false ){
  207. console.log( config.mixRequireMod );
  208. Init.prototype.all = function(callBack){
  209. if(callBack) callBack();
  210. return;
  211. };
  212. }
  213. Init.prototype.onebyone = function(){
  214. if (this.inViewPort.length <= 0) {
  215. return;
  216. }
  217. for (var i = 0; i < this.inViewPort.length; i++) {
  218. this.a = this.inViewPort[i];
  219. if( this.a.getAttribute("all") ){
  220. continue;
  221. }
  222. ajax(this.a.href.replace("http", "https") + "&wd=&eqid=0",{
  223. "beforeFn":function(url){
  224. this.setAttribute("transcoding", "true");
  225. },
  226. "failFn":function(status,url){
  227. this.setAttribute("transcoded", "false");
  228. console.log( '请求' + url + '结果:' + status );
  229. },
  230. "successFn":function(responseStr,url){
  231. var trueLink = responseStr.replace(regRules.sliceResponse.step1, "$1").replace(regRules.sliceResponse.step2, '$1');
  232. this.href = trueLink;
  233. this.removeAttribute("transcoding");
  234. this.setAttribute("transcoded", "true");
  235. }
  236. },this.a);
  237. }
  238. return this;
  239. };
  240. Init.prototype.addStyle = function() {
  241. if (config.isAnimate === false || document.getElementById('transcoded')) {
  242. return;
  243. }
  244. this.cssString = 'a[transcoded]{position:relative}a[transcoded*="false"]:before{background:rgba(197,31,32,0.5)}a[transcoded*="true"]:before{background:rgba(43,138,23,0.5)}a[transcoded]:before{content:"";position:absolute;width:0;height:100%;line-height:100%;display:inline-block;animation:slide 1s ease-in-out .2s backwards;-webkit-animation:slide 1s ease-in-out .2s backwards;-moz-animation:slide 1s ease-in-out .2s backwards;-o-animation:slide 1s ease-in-out .2s backwards;-ms-animation:slide 1s ease-in-out .2s backwards}@keyframes slide{0%{width:0}80%{width:100%}100%{width:0}}@-webkit-keyframes slide{0%{width:0}80%{width:100%}100%{width:0}}@-moz-keyframes slide{0%{width:0}80%{width:100%}100%{width:0}}@-o-keyframes slide{0%{width:0}80%{width:100%}100%{width:0}}@-ms-keyframes slide{0%{width:0}80%{width:100%}100%{width:0}}';
  245. this.css = document.createTextNode(this.cssString);
  246. this.style = document.createElement('style');
  247. this.style.id = "transcoded";
  248. this.style.type = "text/css";
  249. this.style.appendChild(this.css);
  250. document.head.appendChild(this.style);
  251. };
  252. Init.prototype.visible = function() {
  253. var obj = this.a,
  254. pos = obj.getBoundingClientRect(),
  255. w,
  256. h;
  257. if (document.documentElement.getBoundingClientRect) {
  258. w = document.documentElement.clientWidth || document.body.clientWidth;
  259. h = document.documentElement.clientHeight || document.body.clientHeight;
  260. var inViewPort = pos.top > h || pos.bottom < 0 || pos.left > w || pos.right < 0;
  261. if (inViewPort === true) {
  262. return false;
  263. } else {
  264. return true;
  265. }
  266. }
  267. };
  268. //======执行=======
  269. handler(document).bind({
  270. "DOMContentLoaded": function() {
  271. if( config.transcodingAll===false ){
  272. init().all(function() {
  273. var inViewPortElement = init('a[transcodedAll]').inViewPort;
  274. for( var i=0;i<inViewPortElement.length;i++ ){
  275. inViewPortElement[i].setAttribute("transcoded","true");
  276. }
  277. init(config.macthRules).onebyone();
  278. });
  279. }
  280. handler(document).ob({
  281. "childList":true,
  282. "subtree":true
  283. },function(){
  284. if( config.transcodingAll===false ){
  285. init().all(function() {
  286. init(config.macthRules).onebyone();
  287. });
  288. }
  289. });
  290. },
  291. "mouseover": function(e) {
  292. var a = e.target;
  293. if (a.tagName == "A" && regRules.isJumpLink.test(a.href) && a.getAttribute('transcoded') !== "true") {
  294. var href = a.href.replace("http", "https") + "&wd=&eqid=0";
  295. ajax(href,{
  296. "beforeFn":function(url){
  297. this.setAttribute("transcoding", "true");
  298. },
  299. "successFn":function(responseStr,url){
  300. var trueLink = responseStr.replace(regRules.sliceResponse.step1, "$1").replace(regRules.sliceResponse.step2, '$1');
  301. this.href = trueLink;
  302. this.removeAttribute("transcoding");
  303. this.setAttribute("transcoded", "true");
  304. }
  305. },a);
  306. }
  307. }
  308. });
  309. handler(window).bind('scroll',function(){
  310. init(config.macthRules).onebyone();
  311. init(config.reloadRules).onebyone();
  312. var inViewPortElement = init('a[transcodedAll]').inViewPort;
  313. for( var i=0;i<inViewPortElement.length;i++ ){
  314. inViewPortElement[i].setAttribute("transcoded","true");
  315. }
  316. });
  317. //======注册菜单====
  318. function turnAnimate(){
  319. if( window.confirm("打开请求动画\n【确定】>>>打开动画\n【取消】>>>关闭动画\n\n当前状态:"+GM_getValue("isAnimate",true)+"\n\n刷新页面生效")===true ){
  320. GM_setValue("isAnimate",true);
  321. }else{
  322. GM_setValue("isAnimate",false);
  323. }
  324. }
  325. GM_registerMenuCommand("请求动画开关",turnAnimate);
  326. })(document);