🏠 Home 

Google 快覽

在 Google 搜尋結果頁面利用快捷鍵進行快速瀏覽。


安装此脚本?
  1. // ==UserScript==
  2. // @name Google Navigation
  3. // @name:zh-TW Google 快覽
  4. // @name:zh-CN Google 快覽
  5. // @namespace veringsek
  6. // @match http://*.google.com/search*
  7. // @match http://*.google.ad/search*
  8. // @match http://*.google.ae/search*
  9. // @match http://*.google.com.af/search*
  10. // @match http://*.google.com.ag/search*
  11. // @match http://*.google.com.ai/search*
  12. // @match http://*.google.al/search*
  13. // @match http://*.google.am/search*
  14. // @match http://*.google.co.ao/search*
  15. // @match http://*.google.com.ar/search*
  16. // @match http://*.google.as/search*
  17. // @match http://*.google.at/search*
  18. // @match http://*.google.com.au/search*
  19. // @match http://*.google.az/search*
  20. // @match http://*.google.ba/search*
  21. // @match http://*.google.com.bd/search*
  22. // @match http://*.google.be/search*
  23. // @match http://*.google.bf/search*
  24. // @match http://*.google.bg/search*
  25. // @match http://*.google.com.bh/search*
  26. // @match http://*.google.bi/search*
  27. // @match http://*.google.bj/search*
  28. // @match http://*.google.com.bn/search*
  29. // @match http://*.google.com.bo/search*
  30. // @match http://*.google.com.br/search*
  31. // @match http://*.google.bs/search*
  32. // @match http://*.google.bt/search*
  33. // @match http://*.google.co.bw/search*
  34. // @match http://*.google.by/search*
  35. // @match http://*.google.com.bz/search*
  36. // @match http://*.google.ca/search*
  37. // @match http://*.google.cd/search*
  38. // @match http://*.google.cf/search*
  39. // @match http://*.google.cg/search*
  40. // @match http://*.google.ch/search*
  41. // @match http://*.google.ci/search*
  42. // @match http://*.google.co.ck/search*
  43. // @match http://*.google.cl/search*
  44. // @match http://*.google.cm/search*
  45. // @match http://*.google.cn/search*
  46. // @match http://*.google.com.co/search*
  47. // @match http://*.google.co.cr/search*
  48. // @match http://*.google.com.cu/search*
  49. // @match http://*.google.cv/search*
  50. // @match http://*.google.com.cy/search*
  51. // @match http://*.google.cz/search*
  52. // @match http://*.google.de/search*
  53. // @match http://*.google.dj/search*
  54. // @match http://*.google.dk/search*
  55. // @match http://*.google.dm/search*
  56. // @match http://*.google.com.do/search*
  57. // @match http://*.google.dz/search*
  58. // @match http://*.google.com.ec/search*
  59. // @match http://*.google.ee/search*
  60. // @match http://*.google.com.eg/search*
  61. // @match http://*.google.es/search*
  62. // @match http://*.google.com.et/search*
  63. // @match http://*.google.fi/search*
  64. // @match http://*.google.com.fj/search*
  65. // @match http://*.google.fm/search*
  66. // @match http://*.google.fr/search*
  67. // @match http://*.google.ga/search*
  68. // @match http://*.google.ge/search*
  69. // @match http://*.google.gg/search*
  70. // @match http://*.google.com.gh/search*
  71. // @match http://*.google.com.gi/search*
  72. // @match http://*.google.gl/search*
  73. // @match http://*.google.gm/search*
  74. // @match http://*.google.gr/search*
  75. // @match http://*.google.com.gt/search*
  76. // @match http://*.google.gy/search*
  77. // @match http://*.google.com.hk/search*
  78. // @match http://*.google.hn/search*
  79. // @match http://*.google.hr/search*
  80. // @match http://*.google.ht/search*
  81. // @match http://*.google.hu/search*
  82. // @match http://*.google.co.id/search*
  83. // @match http://*.google.ie/search*
  84. // @match http://*.google.co.il/search*
  85. // @match http://*.google.im/search*
  86. // @match http://*.google.co.in/search*
  87. // @match http://*.google.iq/search*
  88. // @match http://*.google.is/search*
  89. // @match http://*.google.it/search*
  90. // @match http://*.google.je/search*
  91. // @match http://*.google.com.jm/search*
  92. // @match http://*.google.jo/search*
  93. // @match http://*.google.co.jp/search*
  94. // @match http://*.google.co.ke/search*
  95. // @match http://*.google.com.kh/search*
  96. // @match http://*.google.ki/search*
  97. // @match http://*.google.kg/search*
  98. // @match http://*.google.co.kr/search*
  99. // @match http://*.google.com.kw/search*
  100. // @match http://*.google.kz/search*
  101. // @match http://*.google.la/search*
  102. // @match http://*.google.com.lb/search*
  103. // @match http://*.google.li/search*
  104. // @match http://*.google.lk/search*
  105. // @match http://*.google.co.ls/search*
  106. // @match http://*.google.lt/search*
  107. // @match http://*.google.lu/search*
  108. // @match http://*.google.lv/search*
  109. // @match http://*.google.com.ly/search*
  110. // @match http://*.google.co.ma/search*
  111. // @match http://*.google.md/search*
  112. // @match http://*.google.me/search*
  113. // @match http://*.google.mg/search*
  114. // @match http://*.google.mk/search*
  115. // @match http://*.google.ml/search*
  116. // @match http://*.google.com.mm/search*
  117. // @match http://*.google.mn/search*
  118. // @match http://*.google.ms/search*
  119. // @match http://*.google.com.mt/search*
  120. // @match http://*.google.mu/search*
  121. // @match http://*.google.mv/search*
  122. // @match http://*.google.mw/search*
  123. // @match http://*.google.com.mx/search*
  124. // @match http://*.google.com.my/search*
  125. // @match http://*.google.co.mz/search*
  126. // @match http://*.google.com.na/search*
  127. // @match http://*.google.com.ng/search*
  128. // @match http://*.google.com.ni/search*
  129. // @match http://*.google.ne/search*
  130. // @match http://*.google.nl/search*
  131. // @match http://*.google.no/search*
  132. // @match http://*.google.com.np/search*
  133. // @match http://*.google.nr/search*
  134. // @match http://*.google.nu/search*
  135. // @match http://*.google.co.nz/search*
  136. // @match http://*.google.com.om/search*
  137. // @match http://*.google.com.pa/search*
  138. // @match http://*.google.com.pe/search*
  139. // @match http://*.google.com.pg/search*
  140. // @match http://*.google.com.ph/search*
  141. // @match http://*.google.com.pk/search*
  142. // @match http://*.google.pl/search*
  143. // @match http://*.google.pn/search*
  144. // @match http://*.google.com.pr/search*
  145. // @match http://*.google.ps/search*
  146. // @match http://*.google.pt/search*
  147. // @match http://*.google.com.py/search*
  148. // @match http://*.google.com.qa/search*
  149. // @match http://*.google.ro/search*
  150. // @match http://*.google.ru/search*
  151. // @match http://*.google.rw/search*
  152. // @match http://*.google.com.sa/search*
  153. // @match http://*.google.com.sb/search*
  154. // @match http://*.google.sc/search*
  155. // @match http://*.google.se/search*
  156. // @match http://*.google.com.sg/search*
  157. // @match http://*.google.sh/search*
  158. // @match http://*.google.si/search*
  159. // @match http://*.google.sk/search*
  160. // @match http://*.google.com.sl/search*
  161. // @match http://*.google.sn/search*
  162. // @match http://*.google.so/search*
  163. // @match http://*.google.sm/search*
  164. // @match http://*.google.sr/search*
  165. // @match http://*.google.st/search*
  166. // @match http://*.google.com.sv/search*
  167. // @match http://*.google.td/search*
  168. // @match http://*.google.tg/search*
  169. // @match http://*.google.co.th/search*
  170. // @match http://*.google.com.tj/search*
  171. // @match http://*.google.tl/search*
  172. // @match http://*.google.tm/search*
  173. // @match http://*.google.tn/search*
  174. // @match http://*.google.to/search*
  175. // @match http://*.google.com.tr/search*
  176. // @match http://*.google.tt/search*
  177. // @match http://*.google.com.tw/search*
  178. // @match http://*.google.co.tz/search*
  179. // @match http://*.google.com.ua/search*
  180. // @match http://*.google.co.ug/search*
  181. // @match http://*.google.co.uk/search*
  182. // @match http://*.google.com.uy/search*
  183. // @match http://*.google.co.uz/search*
  184. // @match http://*.google.com.vc/search*
  185. // @match http://*.google.co.ve/search*
  186. // @match http://*.google.vg/search*
  187. // @match http://*.google.co.vi/search*
  188. // @match http://*.google.com.vn/search*
  189. // @match http://*.google.vu/search*
  190. // @match http://*.google.ws/search*
  191. // @match http://*.google.rs/search*
  192. // @match http://*.google.co.za/search*
  193. // @match http://*.google.co.zm/search*
  194. // @match http://*.google.co.zw/search*
  195. // @match http://*.google.cat/search*
  196. // @match https://*.google.com/search*
  197. // @match https://*.google.ad/search*
  198. // @match https://*.google.ae/search*
  199. // @match https://*.google.com.af/search*
  200. // @match https://*.google.com.ag/search*
  201. // @match https://*.google.com.ai/search*
  202. // @match https://*.google.al/search*
  203. // @match https://*.google.am/search*
  204. // @match https://*.google.co.ao/search*
  205. // @match https://*.google.com.ar/search*
  206. // @match https://*.google.as/search*
  207. // @match https://*.google.at/search*
  208. // @match https://*.google.com.au/search*
  209. // @match https://*.google.az/search*
  210. // @match https://*.google.ba/search*
  211. // @match https://*.google.com.bd/search*
  212. // @match https://*.google.be/search*
  213. // @match https://*.google.bf/search*
  214. // @match https://*.google.bg/search*
  215. // @match https://*.google.com.bh/search*
  216. // @match https://*.google.bi/search*
  217. // @match https://*.google.bj/search*
  218. // @match https://*.google.com.bn/search*
  219. // @match https://*.google.com.bo/search*
  220. // @match https://*.google.com.br/search*
  221. // @match https://*.google.bs/search*
  222. // @match https://*.google.bt/search*
  223. // @match https://*.google.co.bw/search*
  224. // @match https://*.google.by/search*
  225. // @match https://*.google.com.bz/search*
  226. // @match https://*.google.ca/search*
  227. // @match https://*.google.cd/search*
  228. // @match https://*.google.cf/search*
  229. // @match https://*.google.cg/search*
  230. // @match https://*.google.ch/search*
  231. // @match https://*.google.ci/search*
  232. // @match https://*.google.co.ck/search*
  233. // @match https://*.google.cl/search*
  234. // @match https://*.google.cm/search*
  235. // @match https://*.google.cn/search*
  236. // @match https://*.google.com.co/search*
  237. // @match https://*.google.co.cr/search*
  238. // @match https://*.google.com.cu/search*
  239. // @match https://*.google.cv/search*
  240. // @match https://*.google.com.cy/search*
  241. // @match https://*.google.cz/search*
  242. // @match https://*.google.de/search*
  243. // @match https://*.google.dj/search*
  244. // @match https://*.google.dk/search*
  245. // @match https://*.google.dm/search*
  246. // @match https://*.google.com.do/search*
  247. // @match https://*.google.dz/search*
  248. // @match https://*.google.com.ec/search*
  249. // @match https://*.google.ee/search*
  250. // @match https://*.google.com.eg/search*
  251. // @match https://*.google.es/search*
  252. // @match https://*.google.com.et/search*
  253. // @match https://*.google.fi/search*
  254. // @match https://*.google.com.fj/search*
  255. // @match https://*.google.fm/search*
  256. // @match https://*.google.fr/search*
  257. // @match https://*.google.ga/search*
  258. // @match https://*.google.ge/search*
  259. // @match https://*.google.gg/search*
  260. // @match https://*.google.com.gh/search*
  261. // @match https://*.google.com.gi/search*
  262. // @match https://*.google.gl/search*
  263. // @match https://*.google.gm/search*
  264. // @match https://*.google.gr/search*
  265. // @match https://*.google.com.gt/search*
  266. // @match https://*.google.gy/search*
  267. // @match https://*.google.com.hk/search*
  268. // @match https://*.google.hn/search*
  269. // @match https://*.google.hr/search*
  270. // @match https://*.google.ht/search*
  271. // @match https://*.google.hu/search*
  272. // @match https://*.google.co.id/search*
  273. // @match https://*.google.ie/search*
  274. // @match https://*.google.co.il/search*
  275. // @match https://*.google.im/search*
  276. // @match https://*.google.co.in/search*
  277. // @match https://*.google.iq/search*
  278. // @match https://*.google.is/search*
  279. // @match https://*.google.it/search*
  280. // @match https://*.google.je/search*
  281. // @match https://*.google.com.jm/search*
  282. // @match https://*.google.jo/search*
  283. // @match https://*.google.co.jp/search*
  284. // @match https://*.google.co.ke/search*
  285. // @match https://*.google.com.kh/search*
  286. // @match https://*.google.ki/search*
  287. // @match https://*.google.kg/search*
  288. // @match https://*.google.co.kr/search*
  289. // @match https://*.google.com.kw/search*
  290. // @match https://*.google.kz/search*
  291. // @match https://*.google.la/search*
  292. // @match https://*.google.com.lb/search*
  293. // @match https://*.google.li/search*
  294. // @match https://*.google.lk/search*
  295. // @match https://*.google.co.ls/search*
  296. // @match https://*.google.lt/search*
  297. // @match https://*.google.lu/search*
  298. // @match https://*.google.lv/search*
  299. // @match https://*.google.com.ly/search*
  300. // @match https://*.google.co.ma/search*
  301. // @match https://*.google.md/search*
  302. // @match https://*.google.me/search*
  303. // @match https://*.google.mg/search*
  304. // @match https://*.google.mk/search*
  305. // @match https://*.google.ml/search*
  306. // @match https://*.google.com.mm/search*
  307. // @match https://*.google.mn/search*
  308. // @match https://*.google.ms/search*
  309. // @match https://*.google.com.mt/search*
  310. // @match https://*.google.mu/search*
  311. // @match https://*.google.mv/search*
  312. // @match https://*.google.mw/search*
  313. // @match https://*.google.com.mx/search*
  314. // @match https://*.google.com.my/search*
  315. // @match https://*.google.co.mz/search*
  316. // @match https://*.google.com.na/search*
  317. // @match https://*.google.com.ng/search*
  318. // @match https://*.google.com.ni/search*
  319. // @match https://*.google.ne/search*
  320. // @match https://*.google.nl/search*
  321. // @match https://*.google.no/search*
  322. // @match https://*.google.com.np/search*
  323. // @match https://*.google.nr/search*
  324. // @match https://*.google.nu/search*
  325. // @match https://*.google.co.nz/search*
  326. // @match https://*.google.com.om/search*
  327. // @match https://*.google.com.pa/search*
  328. // @match https://*.google.com.pe/search*
  329. // @match https://*.google.com.pg/search*
  330. // @match https://*.google.com.ph/search*
  331. // @match https://*.google.com.pk/search*
  332. // @match https://*.google.pl/search*
  333. // @match https://*.google.pn/search*
  334. // @match https://*.google.com.pr/search*
  335. // @match https://*.google.ps/search*
  336. // @match https://*.google.pt/search*
  337. // @match https://*.google.com.py/search*
  338. // @match https://*.google.com.qa/search*
  339. // @match https://*.google.ro/search*
  340. // @match https://*.google.ru/search*
  341. // @match https://*.google.rw/search*
  342. // @match https://*.google.com.sa/search*
  343. // @match https://*.google.com.sb/search*
  344. // @match https://*.google.sc/search*
  345. // @match https://*.google.se/search*
  346. // @match https://*.google.com.sg/search*
  347. // @match https://*.google.sh/search*
  348. // @match https://*.google.si/search*
  349. // @match https://*.google.sk/search*
  350. // @match https://*.google.com.sl/search*
  351. // @match https://*.google.sn/search*
  352. // @match https://*.google.so/search*
  353. // @match https://*.google.sm/search*
  354. // @match https://*.google.sr/search*
  355. // @match https://*.google.st/search*
  356. // @match https://*.google.com.sv/search*
  357. // @match https://*.google.td/search*
  358. // @match https://*.google.tg/search*
  359. // @match https://*.google.co.th/search*
  360. // @match https://*.google.com.tj/search*
  361. // @match https://*.google.tl/search*
  362. // @match https://*.google.tm/search*
  363. // @match https://*.google.tn/search*
  364. // @match https://*.google.to/search*
  365. // @match https://*.google.com.tr/search*
  366. // @match https://*.google.tt/search*
  367. // @match https://*.google.com.tw/search*
  368. // @match https://*.google.co.tz/search*
  369. // @match https://*.google.com.ua/search*
  370. // @match https://*.google.co.ug/search*
  371. // @match https://*.google.co.uk/search*
  372. // @match https://*.google.com.uy/search*
  373. // @match https://*.google.co.uz/search*
  374. // @match https://*.google.com.vc/search*
  375. // @match https://*.google.co.ve/search*
  376. // @match https://*.google.vg/search*
  377. // @match https://*.google.co.vi/search*
  378. // @match https://*.google.com.vn/search*
  379. // @match https://*.google.vu/search*
  380. // @match https://*.google.ws/search*
  381. // @match https://*.google.rs/search*
  382. // @match https://*.google.co.za/search*
  383. // @match https://*.google.co.zm/search*
  384. // @match https://*.google.co.zw/search*
  385. // @match https://*.google.cat/search*
  386. // @grant none
  387. // @version 0.3.4
  388. // @author veringsek
  389. // @description Navigate through Google Search with a set of hotkeys.
  390. // @description:zh-TW 在 Google 搜尋結果頁面利用快捷鍵進行快速瀏覽。
  391. // @description:zh-CN 在 Google 搜尋結果頁面利用快捷鍵進行快速瀏覽。
  392. // ==/UserScript==
  393. (function () {
  394. let css = document.createElement('style');
  395. css.type = 'text/css';
  396. css.innerText = `
  397. :root {
  398. --google-navigation--button-size: 30px;
  399. --google-navigation--stroke-color: black;
  400. --google-navigation--background-color: white;
  401. --google-navigation--button-opacity: 1;
  402. }
  403. .google-navigation--button {
  404. position: absolute;
  405. left: calc(-5 / 3 * var(--google-navigation--button-size));
  406. border: 2px var(--google-navigation--stroke-color) solid;
  407. border-radius: 5px;
  408. background: var(--google-navigation--background-color);
  409. box-shadow: 0px 2px var(--google-navigation--stroke-color);
  410. color: var(--google-navigation--stroke-color) !important;
  411. opacity: var(--google-navigation--button-opacity);
  412. text-decoration: none !important;
  413. width: var(--google-navigation--button-size);
  414. height: var(--google-navigation--button-size);
  415. line-height: var(--google-navigation--button-size);
  416. text-align: center;
  417. font-size: calc(2 / 3 * var(--google-navigation--button-size));
  418. user-select: none;
  419. transition: all 0.1s linear;
  420. animation: spawn 0.2s;
  421. }
  422. .google-navigation--button.keydown {
  423. background: var(--google-navigation--stroke-color);
  424. color: var(--google-navigation--background-color) !important;
  425. transform: scale(0.8);
  426. }
  427. .google-navigation--switch {
  428. opacity: 0;
  429. }
  430. .google-navigation--switch.keydown {
  431. opacity: 1;
  432. }
  433. @keyframes spawn {
  434. from {
  435. transform: scale(0);
  436. }
  437. }
  438. `;
  439. document.head.appendChild(css);
  440. })();
  441. let GoogleNavigation = {};
  442. GoogleNavigation.GN_KEYDOWN_TIMER_DURATION = 1000;
  443. GoogleNavigation.GN_KEYDOWN_TIMER_CANCELED = 'GN_KEYDOWN_TIMER_CANCELED';
  444. GoogleNavigation.GN_KEYPRESS_SENSITIVITY = 500;
  445. GoogleNavigation.GN_KEYPRESS_CANCELED = 'GN_KEYPRESS_CANCELED';
  446. GoogleNavigation.GN_BUTTON_SIZE = 30;
  447. GoogleNavigation.GN_BUTTON_SIZE_HALF = GoogleNavigation.GN_BUTTON_SIZE / 2;
  448. GoogleNavigation.keydowns = new Set();
  449. GoogleNavigation.tmrKeydown = undefined;
  450. globalThis.GoogleNavigation = GoogleNavigation;
  451. function setCSSVars() {
  452. document.documentElement.style.setProperty(
  453. '--google-navigation--button-size',
  454. `${globalThis.GoogleNavigation.GN_BUTTON_SIZE}px`
  455. );
  456. document.documentElement.style.setProperty(
  457. '--google-navigation--stroke-color',
  458. globalThis.getComputedStyle(document.body)['color']
  459. );
  460. document.documentElement.style.setProperty(
  461. '--google-navigation--background-color',
  462. globalThis.getComputedStyle(document.body)['backgroundColor']
  463. );
  464. }
  465. function makeTemplate() {
  466. let template = document.createElement('a');
  467. template.classList.add('google-navigation--button');
  468. template.commandKeydown = function () {
  469. this.classList.add('keydown');
  470. let documentElement = document.documentElement;
  471. documentElement.scroll({
  472. top: this.getBoundingClientRect().top + documentElement.scrollTop - window.innerHeight / 2,
  473. behavior: 'smooth'
  474. });
  475. globalThis.GoogleNavigation.tmrKeydown = globalThis.setTimeout(() => {
  476. globalThis.clearTimeout(globalThis.GoogleNavigation.tmrKeydown);
  477. globalThis.GoogleNavigation.tmrKeydown = globalThis.GoogleNavigation.GN_KEYDOWN_TIMER_CANCELED;
  478. this.classList.remove('keydown');
  479. this.commandCancel();
  480. }, globalThis.GoogleNavigation.GN_KEYDOWN_TIMER_DURATION);
  481. };
  482. template.commandKeyup = function () {
  483. this.classList.remove('keydown');
  484. this.commandPress();
  485. };
  486. template.commandPress = function () {
  487. if (document.getElementById('google-navigation--switch-Control').keydown) {
  488. window.open(this.link, '_blank');
  489. } else {
  490. window.open(this.link, '_self');
  491. }
  492. };
  493. template.commandCancel = function () {
  494. return;
  495. };
  496. globalThis.GoogleNavigation.buttonTemplate = template;
  497. }
  498. function getClonedButton(key, link) {
  499. let string = key;
  500. if (Array.isArray(key)) {
  501. [key, string] = key;
  502. }
  503. let cloned = globalThis.GoogleNavigation.buttonTemplate.cloneNode();
  504. cloned.commandKeydown = globalThis.GoogleNavigation.buttonTemplate.commandKeydown;
  505. cloned.commandKeyup = globalThis.GoogleNavigation.buttonTemplate.commandKeyup;
  506. cloned.commandPress = globalThis.GoogleNavigation.buttonTemplate.commandPress;
  507. cloned.commandCancel = globalThis.GoogleNavigation.buttonTemplate.commandCancel;
  508. cloned.innerHTML = string;
  509. cloned.classList.add(`google-navigation--button-${key}`);
  510. if (link) {
  511. cloned.link = link;
  512. cloned.setAttribute('link', link);
  513. }
  514. return cloned;
  515. }
  516. function plantButtons() {
  517. let search = document.getElementById('search');
  518. let rcnt = document.getElementById('rcnt');
  519. let links = [...document.getElementsByClassName('LC20lb')];
  520. let num = 0;
  521. for (let link of links) {
  522. if (getCollapseSectionParent(link)) continue;
  523. if (num >= 10) break;
  524. let href = link.parentElement.href;
  525. let cloned;
  526. cloned = getClonedButton(num, href);
  527. cloned.style.top = `${link.offsetTop + link.clientHeight / 2 - GoogleNavigation.GN_BUTTON_SIZE_HALF}px`;
  528. link.insertBefore(cloned, link.children[0]);
  529. let node = link;
  530. let notInRcnt = false;
  531. do {
  532. if (!(node instanceof Element)) {
  533. notInRcnt = true;
  534. break;
  535. }
  536. let style = window.getComputedStyle(node);
  537. if (style['overflow'] === 'hidden') {
  538. node.style.overflow = 'visible';
  539. }
  540. if (style['contain'] === 'layout paint') {
  541. node.style.contain = 'unset';
  542. }
  543. node = node.parentElement;
  544. } while (node !== rcnt);
  545. if (notInRcnt) continue;
  546. setButtonEnter(document.activeElement === document.body);
  547. num += 1;
  548. }
  549. if (search) {
  550. let cloned = getClonedButton(['Control', 'CTRL']);
  551. cloned.id = 'google-navigation--switch-Control';
  552. cloned.classList.add('google-navigation--switch');
  553. cloned.style.left = '-150px';
  554. cloned.style.width = '80px';
  555. cloned.style.fontWeight = 'bold';
  556. cloned.keydown = false;
  557. cloned.commandKeydown = function () {
  558. this.tmrKeypress = globalThis.setTimeout(() => {
  559. this.tmrKeypress = globalThis.GoogleNavigation.GN_KEYPRESS_CANCELED;
  560. }, globalThis.GoogleNavigation.GN_KEYPRESS_SENSITIVITY);
  561. };
  562. cloned.commandKeyup = function () {
  563. if (this.tmrKeypress === globalThis.GoogleNavigation.GN_KEYPRESS_CANCELED) {
  564. this.tmrKeypress = undefined;
  565. } else if (this.tmrKeypress) {
  566. this.keydown = !this.keydown;
  567. if (this.keydown) {
  568. this.classList.add('keydown');
  569. } else {
  570. this.classList.remove('keydown');
  571. }
  572. }
  573. };
  574. search.insertBefore(cloned, search.children[0]);
  575. }
  576. let btnWiki = document.getElementsByClassName('ruhjFe')[0];
  577. if (btnWiki) {
  578. let cloned = getClonedButton(['p', 'P'], btnWiki.href);
  579. let card = getWidgetParent(btnWiki);
  580. if (!card) {
  581. card = document.getElementById('rhs');
  582. cloned.style.left = `calc(2 / 3 * var(--google-navigation--button-size) + 100%)`;
  583. }
  584. card.style.position = 'relative';
  585. card.insertBefore(cloned, card.children[0]);
  586. }
  587. let translatorWidgetMain = document.getElementById('tw-main');
  588. let translatorWidgetSourceTextTA = document.getElementById('tw-source-text-ta');
  589. if (translatorWidgetMain && translatorWidgetSourceTextTA) {
  590. let cloned = getClonedButton(['t', 'T']);
  591. let rectMain = translatorWidgetMain.getBoundingClientRect();
  592. let rectText = translatorWidgetSourceTextTA.getBoundingClientRect();
  593. let top = (rectText.bottom + rectText.top) / 2 - rectMain.top - GoogleNavigation.GN_BUTTON_SIZE_HALF;
  594. cloned.style.top = `${top}px`;
  595. cloned.commandPress = function () {
  596. document.getElementById('tw-source-text-ta').focus();
  597. };
  598. translatorWidgetMain.style.position = 'relative';
  599. translatorWidgetMain.insertBefore(cloned, translatorWidgetMain.children[0]);
  600. }
  601. let calculatorWidget = document.getElementById('cwos')?.parentElement?.parentElement;
  602. if (calculatorWidget) {
  603. let calculatorWidgetParent = getWidgetParent(calculatorWidget);
  604. let cloned = getClonedButton(['t', 'T']);
  605. let top = calculatorWidgetParent.clientHeight / 2 - globalThis.GoogleNavigation.GN_BUTTON_SIZE_HALF;
  606. cloned.style.top = `${top}px`;
  607. cloned.commandPress = function () {
  608. document.getElementById('cwos').parentElement.parentElement.focus();
  609. };
  610. calculatorWidgetParent.insertBefore(cloned, calculatorWidgetParent.children[0]);
  611. }
  612. let pnprev = document.getElementById('pnprev');
  613. if (pnprev) {
  614. let cloned = getClonedButton([',', ','], pnprev.href);
  615. cloned.style.top = '-3px';
  616. cloned.style.left = '-40px';
  617. pnprev.style.position = 'relative';
  618. pnprev.insertBefore(cloned, pnprev.children[0]);
  619. }
  620. let pnnext = document.getElementById('pnnext');
  621. if (pnnext) {
  622. let cloned = getClonedButton(['.', '‧'], pnnext.href);
  623. cloned.style.top = '-3px';
  624. cloned.style.left = 'calc(100% + 5px)';
  625. pnnext.style.position = 'relative';
  626. pnnext.insertBefore(cloned, pnnext.children[0]);
  627. }
  628. }
  629. function isCommanding() {
  630. let target = document.activeElement;
  631. return !(['INPUT', 'TEXTAREA'].includes(target.tagName) || target.classList.contains('jlkklc'));
  632. }
  633. function cssVar(name) {
  634. return globalThis.getComputedStyle(document.documentElement).getPropertyValue(name);
  635. }
  636. function getParent(element, condition) {
  637. let node = element;
  638. do {
  639. if (condition(node)) return node;
  640. node = node.parentElement;
  641. } while (node !== document.body);
  642. return null;
  643. }
  644. function getWidgetParent(element) {
  645. return getParent(element, node => {
  646. let computedStyle = globalThis.getComputedStyle(node);
  647. let borderWidth = computedStyle.borderWidth;
  648. return borderWidth !== '' && !(/^0\D*/.test(borderWidth));
  649. });
  650. }
  651. function getCollapseSectionParent(element) {
  652. return getParent(element, node => node.getAttribute('jscontroller') === 'Da4hkd');
  653. }
  654. function assignEventListeners() {
  655. let onFocusChanged = function (ev) {
  656. document.documentElement.style.setProperty(
  657. '--google-navigation--button-opacity',
  658. isCommanding() ? 1 : 0.5
  659. );
  660. setButtonEnter(document.activeElement === document.body);
  661. };
  662. window.addEventListener('focus', onFocusChanged, true);
  663. window.addEventListener('blur', onFocusChanged, true);
  664. document.body.addEventListener('keydown', function (ev) {
  665. if (globalThis.GoogleNavigation.keydowns.has(ev.key)) return;
  666. globalThis.GoogleNavigation.keydowns.add(ev.key);
  667. if (isCommanding()) {
  668. let button = document.getElementsByClassName(`google-navigation--button-${ev.key}`)[0];
  669. if (button) {
  670. button.commandKeydown();
  671. }
  672. }
  673. });
  674. document.body.addEventListener('keyup', function (ev) {
  675. globalThis.GoogleNavigation.keydowns.delete(ev.key);
  676. if (globalThis.GoogleNavigation.tmrKeydown === globalThis.GoogleNavigation.GN_KEYDOWN_TIMER_CANCELED) {
  677. globalThis.GoogleNavigation.tmrKeydown = undefined;
  678. return;
  679. }
  680. globalThis.clearTimeout(globalThis.GoogleNavigation.tmrKeydown);
  681. globalThis.GoogleNavigation.tmrKeydown = undefined;
  682. if (isCommanding()) {
  683. let button = document.getElementsByClassName(`google-navigation--button-${ev.key}`)[0];
  684. if (button) {
  685. button.commandKeyup();
  686. }
  687. }
  688. });
  689. }
  690. function setButtonEnter(enabled) {
  691. let btn0 = document.getElementsByClassName('google-navigation--button-0')[0];
  692. if (enabled) {
  693. btn0.innerHTML = '⮨';
  694. btn0.classList.add('google-navigation--button-Enter');
  695. } else {
  696. btn0.innerHTML = '0';
  697. btn0.classList.remove('google-navigation--button-Enter');
  698. }
  699. }
  700. setCSSVars();
  701. makeTemplate();
  702. plantButtons();
  703. assignEventListeners();