Ecosia Google button

Adds a Google button to Ecosia search page.

  1. // ==UserScript==
  2. // @name Ecosia Google button
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description Adds a Google button to Ecosia search page.
  6. // @author reagent
  7. // @match https://www.ecosia.org/search?*
  8. // @grant none
  9. // @run-at document-start
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14. const icon = document.createElement("img");
  15. icon.src = "https://www.google.com/s2/favicons?domain=www.google.com";
  16.  
  17. const link = document.createElement("a");
  18. link.setAttribute("class", "navbar-link");
  19. link.appendChild(icon);
  20. link.appendChild(document.createTextNode("Google"));
  21.  
  22. const updateLink = search => link.setAttribute("href", "https://google.com/search?q=" + encodeURIComponent(search));
  23.  
  24. // Class for knowing when element was added to DOM, for hooking events and such
  25. // Assumes that once element is added, it wont be removed again.
  26. class DomWatch{
  27. constructor(){
  28. this.awaiting = [];
  29. this.watching = false;
  30. this.obs = new MutationObserver(this.onMutations.bind(this));
  31. }
  32. watch(){
  33. this.watching = true;
  34. this.obs.observe(document, {subtree:true, childList: true});
  35. }
  36. on(selector, ...fns){
  37. const found = document.querySelector(selector);
  38. if(found){
  39. fns.forEach(fn => fn(found));
  40. return this;
  41. }
  42.  
  43. const i = this.awaiting.findIndex(item => item.selector === selector);
  44. if(i === -1){
  45. this.awaiting.push({selector, fns});
  46. }else{
  47. this.awaiting[i].fns = this.awaiting[i].fns.concat(fns);
  48. }
  49. if(!this.watching){
  50. this.watch();
  51. }
  52.  
  53. return this;
  54.  
  55. }
  56. off(){
  57. this.watching = false;
  58. this.obs.disconnect();
  59. }
  60. onMutations(muts) {
  61. for(const mut of muts){
  62. const item = this.awaiting.findIndex(({selector}) => mut.target.matches(selector));
  63. if(item !== -1){
  64. this.awaiting[item].fns.forEach(fn => fn(mut.target));
  65. this.awaiting.splice(item, 1);
  66. }else{
  67. let queried = null;
  68. const item = this.awaiting.findIndex(({selector}) => queried = mut.target.querySelector(selector));
  69.  
  70. if(item !== -1){
  71. this.awaiting[item].fns.forEach(fn => fn(queried));
  72. this.awaiting.splice(item, 1);
  73. }
  74. }
  75. if(this.watching && !this.awaiting.length){
  76. return this.off();
  77. }
  78. }
  79. }
  80. }
  81.  
  82. const watch = new DomWatch();
  83.  
  84. watch.on("nav.navbar-row", row => {
  85. const webButton = row.querySelector("div li");
  86. const search = document.querySelector("input.search-form-input");
  87.  
  88. webButton.parentNode.insertBefore((() => {
  89. let el = document.createElement("li");
  90. el.setAttribute("class", "navbar-item navbar-item-vertical");
  91. el.appendChild(link);
  92. return el;
  93. })(), webButton)
  94.  
  95.  
  96. if(!search) return console.error("No search found");
  97. search.addEventListener("keydown", e => updateLink(search.value))
  98.  
  99. updateLink(search.value);
  100. });
  101. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址