GSearch in Persian

GSearch in Persian can change Google search results to Persian language, without affecting the RTL (Right-to-Left) direction. (Based on the fork from tgxhx)

بۇ قوليازمىنى قاچىلاش؟
ئاپتورنىڭ تەۋسىيەلىگەن قوليازمىسى

سىز بەلكىم Vajehyab Assistan نى ياقتۇرۇشىڭىز مۇمكىن.

بۇ قوليازمىنى قاچىلاش
  1. // ==UserScript==
  2. // @name GSearch in Persian
  3. // @name:fa سوییچ جستو در سایت‌های فارسی
  4. // @version 0.5
  5. // @author Amir
  6. // @description GSearch in Persian can change Google search results to Persian language, without affecting the RTL (Right-to-Left) direction. (Based on the fork from tgxhx)
  7. // @homepage https://github.com/Amm1rr/GSearch-Toggle/
  8. // @namespace amm1rr
  9. // @description:fa با این اسکریپت به راحتی می‌توان بین جستجو فقط در سایت‌های فارسی در جستجوی گوگل سوییچ کرد، یک گزینه زیر جستجوی گوگل اضافه می شود. البته بدون تغییر در
  10. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
  11. // @icon https://www.google.com/favicon.ico
  12. // @match https://www.google.com/search*
  13. // @exclude https://www.google.com/maps*
  14. // @grant GM_addStyle
  15. // ==/UserScript==
  16.  
  17. /*
  18.  
  19. Last Changes: (Sort by Date)
  20.  
  21. 18/07/2023
  22.  
  23. - Excluded Google Map
  24. - Added support for UK/US Google domains
  25. - Added support for mobile, tablet, and desktop devices
  26. - External library removed
  27.  
  28. */
  29.  
  30. (function () {
  31. "use strict";
  32.  
  33. // I just added this variable to check if the class is found for the first time, so there's no need to execute multiple times.
  34. var iFoundCounter = 0;
  35.  
  36. // How to use:
  37. // if( isMobile.any() ) alert('Mobile');
  38. // To check to see if the user is on a specific mobile device:
  39. // if( isMobile.iOS() ) alert('iOS');
  40. const isMobile = {
  41. Android: function () {
  42. return navigator.userAgent.match(/Android/i);
  43. },
  44. BlackBerry: function () {
  45. return navigator.userAgent.match(/BlackBerry/i);
  46. },
  47. iOS: function () {
  48. return navigator.userAgent.match(/iPhone|iPad|iPod/i);
  49. },
  50. iPhone: function () {
  51. return navigator.userAgent.match(/iPhone/i);
  52. },
  53. Opera: function () {
  54. return navigator.userAgent.match(/Opera Mini/i);
  55. },
  56. Windows: function () {
  57. return (
  58. navigator.userAgent.match(/IEMobile/i) ||
  59. navigator.userAgent.match(/WPDesktop/i)
  60. );
  61. },
  62. any: function () {
  63. return (
  64. isMobile.Android() ||
  65. isMobile.BlackBerry() ||
  66. isMobile.iOS() ||
  67. isMobile.Opera() ||
  68. isMobile.Windows()
  69. );
  70. },
  71. mobile: function () {
  72. return (
  73. isMobile.Android() ||
  74. isMobile.BlackBerry() ||
  75. isMobile.iPhone() ||
  76. isMobile.Opera()
  77. );
  78. },
  79. };
  80.  
  81. //-- Wait for the "Tools" button
  82. if (isMobile.mobile()) {
  83. waitForKeyElements('div[jsname="yIZuWb"]', onPageLoadedMobile);
  84. } else {
  85. waitForKeyElements(".PuHHbb", onPageLoaded);
  86. }
  87.  
  88. function CreateSeprator() {
  89. var seperator = document.createElement("div");
  90. seperator.classList.add("IDFSOe");
  91. //-- Class=> TZqsAd
  92.  
  93. return seperator;
  94. }
  95.  
  96. function CreateLink() {
  97. var aTag = document.createElement("a");
  98. var query = new URLSearchParams(decodeURIComponent(location.search));
  99. const isFarsi = (query.get("lr") || "").toLowerCase() === "lang_fa";
  100. if (isFarsi) {
  101. query.delete("lr");
  102. query.delete("tbs");
  103. aTag.textContent = "Clear";
  104. } else {
  105. query.set("lr", "lang_fa");
  106. query.set("tbs", "lr:lang_fa");
  107. aTag.textContent = "Persian";
  108. }
  109.  
  110. const href = `${location.origin}${
  111. location.pathname
  112. }?${query.toString()}`;
  113. aTag.setAttribute("href", href);
  114. aTag.classList.add("hdtb-tl");
  115. aTag.style.cssText = "color: #5f6368;text-decoration: none;";
  116.  
  117. return aTag;
  118. }
  119.  
  120. function onPageLoadedMobile() {
  121. onPageLoaded("Mobile");
  122. }
  123.  
  124. // Function to be executed after the page has completely loaded
  125. function onPageLoaded(arg) {
  126. var ToolsButton;
  127. if (arg == "Mobile") {
  128. //-- Mobile
  129. ToolsButton = document.querySelector('div[jsname="yIZuWb"]');
  130. } else {
  131. //-- Desktop
  132. ToolsButton = document.querySelector(".PuHHbb");
  133.  
  134. //-- Tablet
  135. if (!ToolsButton) {
  136. ToolsButton = document.querySelector(".hdtb-tl-sel");
  137. // alert("1." + ToolsButton);
  138. }
  139.  
  140. if (!ToolsButton) {
  141. ToolsButton = document.querySelector("#hdtb-tls");
  142. // alert("2." + ToolsButton);
  143. }
  144.  
  145. if (!ToolsButton) {
  146. ToolsButton = document.querySelector(".TZqsAd");
  147. // alert("3." + ToolsButton);
  148. }
  149. //-- Tablet
  150. }
  151.  
  152. if (ToolsButton) {
  153. if (iFoundCounter > 1) {
  154. return;
  155. }
  156. }
  157. iFoundCounter++;
  158.  
  159. var seperator = CreateSeprator();
  160. var alink = CreateLink();
  161.  
  162. ToolsButton.insertAdjacentElement("afterend", seperator);
  163. seperator.insertAdjacentElement("afterend", alink);
  164. }
  165.  
  166. /*--- waitForKeyElements(): A utility function, for Greasemonkey scripts,
  167. that detects and handles AJAXed content.
  168.  
  169. Usage example:
  170.  
  171. waitForKeyElements (
  172. "div.comments"
  173. , commentCallbackFunction
  174. );
  175.  
  176. //--- Page-specific function to do what we want when the node is found.
  177. function commentCallbackFunction (jNode) {
  178. jNode.text ("This comment changed by waitForKeyElements().");
  179. }
  180.  
  181. IMPORTANT: This function requires your script to have loaded jQuery.
  182. */
  183. function waitForKeyElements(
  184. selectorTxt /* Required: The jQuery selector string that
  185. specifies the desired element(s).
  186. */,
  187. actionFunction /* Required: The code to run when elements are
  188. found. It is passed a jNode to the matched
  189. element.
  190. */,
  191. bWaitOnce /* Optional: If false, will continue to scan for
  192. new elements even after the first match is
  193. found.
  194. */,
  195. iframeSelector /* Optional: If set, identifies the iframe to
  196. search.
  197. */
  198. ) {
  199. var targetNodes, btargetsFound;
  200.  
  201. if (typeof iframeSelector == "undefined") targetNodes = $(selectorTxt);
  202. else targetNodes = $(iframeSelector).contents().find(selectorTxt);
  203.  
  204. if (targetNodes && targetNodes.length > 0) {
  205. btargetsFound = true;
  206. /*--- Found target node(s). Go through each and act if they
  207. are new.
  208. */
  209. targetNodes.each(function () {
  210. var jThis = $(this);
  211. var alreadyFound = jThis.data("alreadyFound") || false;
  212.  
  213. if (!alreadyFound) {
  214. //--- Call the payload function.
  215. var cancelFound = actionFunction(jThis);
  216. if (cancelFound) btargetsFound = false;
  217. else jThis.data("alreadyFound", true);
  218. }
  219. });
  220. } else {
  221. btargetsFound = false;
  222. }
  223.  
  224. //--- Get the timer-control variable for this selector.
  225. var controlObj = waitForKeyElements.controlObj || {};
  226. var controlKey = selectorTxt.replace(/[^\w]/g, "_");
  227. var timeControl = controlObj[controlKey];
  228.  
  229. //--- Now set or clear the timer as appropriate.
  230. if (btargetsFound && bWaitOnce && timeControl) {
  231. //--- The only condition where we need to clear the timer.
  232. clearInterval(timeControl);
  233. delete controlObj[controlKey];
  234. } else {
  235. //--- Set a timer, if needed.
  236. if (!timeControl) {
  237. timeControl = setInterval(function () {
  238. waitForKeyElements(
  239. selectorTxt,
  240. actionFunction,
  241. bWaitOnce,
  242. iframeSelector
  243. );
  244. }, 300);
  245. controlObj[controlKey] = timeControl;
  246. }
  247. }
  248. waitForKeyElements.controlObj = controlObj;
  249. }
  250.  
  251. //document.addEventListener('DOMContentLoaded', onPageLoaded);
  252. // window.onload = onPageLoaded;
  253. })();