您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
インスタント検索無効時、検索窓をページ下部にも表示 / When Google Instant is disable, also shows the search box to the page bottom.
当前为
// ==UserScript== // @name Google 検索窓を複製 // @namespace http://userscripts.org/users/347021 // @id google-clone-search-box-347021 // @version 2.2.0 // @description インスタント検索無効時、検索窓をページ下部にも表示 / When Google Instant is disable, also shows the search box to the page bottom. // @include https://www.google.tld/search* // @run-at document-start // @grant dummy // @icon data:image/vnd.microsoft.icon;base64,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 // @author 100の人 // @homepage http://greasyfork.icu/ja/scripts/274-google-%E6%A4%9C%E7%B4%A2%E7%AA%93%E3%82%92%E8%A4%87%E8%A3%BD // @license Creative Commons Attribution 4.0 International Public License; http://creativecommons.org/licenses/by/4.0/ // ==/UserScript== (function() { 'use strict'; polyfill(); // body要素挿入時に実行し、Google検索のバージョンを判別する var textBoxId, inputNodeId, inputParentNodesClassName, textBoxBorderClass, classOnfocuse, previousSiblingId; startScript(function() { var isTargetParent, isTarget, functionsForFirefox, body = document.body; if (body.id) { if (location.search.contains('tbm=isch')) { // 画像検索ページなら実行しない return; } if (body.getAttribute('marginheight')) { // User-AgentがFirefox textBoxId = 'tsf'; inputNodeId = 'lst-ib'; inputParentNodesClassName = 'lst-d'; textBoxBorderClass = 'lst-td'; classOnfocuse = ['lst-d-f']; } else { // Google Chrome版 (UAがOpera、Google Chrome、IE8以降) textBoxId = 'gbqf'; inputNodeId = 'gbqfq'; inputParentNodesClassName = 'gbqfqwc'; textBoxBorderClass = 'gbqfqw'; classOnfocuse = ['gbqfqwf', 'gsfe_b']; } previousSiblingId = 'xjs'; isTargetParent = function (parent) { return parent.id === 'foot'; }; isTarget = function (target) { return target.id === 'xjs'; }; functionsForFirefox = { isTargetParent: function (parent) { return parent.classList.contains('mw'); }, isTarget: function (target) { var firstElementChild = target.firstElementChild; return firstElementChild && firstElementChild.id === 'foot'; }, }; } else { // IE7版 (UAがIE7以下、またはJavaScriptが無効) textBoxId = 'tsf'; previousSiblingId = 'nav'; isTargetParent = function (parent) { return parent.id === 'foot'; }; isTarget = function (target) { return target.id === 'nav'; }; functionsForFirefox = { isTargetParent: function (parent) { return parent.localName === 'tbody' && parent.parentNode.id === 'mn'; }, isTarget: function (target) { var cells = target.cells; return cells && cells[0] && cells[0].id === 'leftnav'; }, }; } startScript(main, isTargetParent, isTarget, function() { return document.getElementById(previousSiblingId); }, functionsForFirefox); }, function(parent) { return parent.localName === 'html'; }, function(target) { return target.localName === 'body'; }, function() { return document.body; }); function main() { var style, sheet, cssRules, original, previousSibling, bottomForm, textBoxBorder, textBoxBorderClassList, inputParentNodes, submitButton, submitButtonClassList; // スタイルシートの設定 document.head.insertAdjacentHTML('beforeend', '<style> \ #foot form { \ margin-top: 13px; \ } \ \ #foot > form { \ margin-bottom: 1em; \ } \ \ /*------------------------------------ \ Firefox版 \ */ \ #foot .nojsv { \ display: none; \ } \ #foot .tsf-p { \ width: 631px; \ padding-left: 8px; \ } \ #nav { \ margin-bottom: initial !important; \ } \ </style>'); // 検索ボックスを取得 original = document.getElementById(textBoxId); if (!original) { return; } // 複製 bottomForm = original.cloneNode(true); // 移動先を取得 previousSibling = document.getElementById(previousSiblingId); // 挿入 previousSibling.parentNode.insertBefore(bottomForm, previousSibling.nextSibling); // ページ描画後のスクリプトによる書き換えを待機 if (inputParentNodesClassName) { inputParentNodes = document.getElementsByClassName(inputParentNodesClassName); startScript(function() { // 後から挿入された検索窓を複製 var table = inputParentNodes[0].firstElementChild.cloneNode(true); // オートコンプリートを有効に table.getElementsByTagName('input')[0].removeAttribute('autocomplete'); // 下の検索窓を置き換え inputParentNodes[1].replaceChild(table, inputParentNodes[1].firstElementChild); }, function(parent) { return parent.id === 'gs_lc0'; }, function(target) { return target.id === inputNodeId; }, function() { return document.querySelector('#' + inputNodeId + '[style]'); }); } // 検索窓にフォーカスが移った時 if (textBoxBorderClass) { textBoxBorder = bottomForm.getElementsByClassName(textBoxBorderClass)[0]; textBoxBorderClassList = textBoxBorder.classList; textBoxBorder.addEventListener('focus', function() { DOMTokenList.prototype.add.apply(textBoxBorderClassList, classOnfocuse); }, true); textBoxBorder.addEventListener('blur', function() { DOMTokenList.prototype.remove.apply(textBoxBorderClassList, classOnfocuse); }, true); // 検索窓をクリックしたとき textBoxBorder.addEventListener('click', function(event) { if (event.target.localName !== 'input') { bottomForm.elements.namedItem('q').focus(); } }); } // 検索窓にマウスが載ったとき submitButton = bottomForm.getElementsByClassName('gbqfb')[0]; if (submitButton) { submitButtonClassList = submitButton.classList; bottomForm.addEventListener('mouseover', function(event) { var target = event.target; if (textBoxBorder.contains(target)) { // 検索窓 textBoxBorderClassList.add('gbqfqw-hvr', 'gsfe_a'); } else if (submitButton.contains(target)) { // 検索ボタン submitButtonClassList.add('gbqfb-hvr'); } }); bottomForm.addEventListener('mouseout', function(event) { var relatedTarget = event.relatedTarget; if (!textBoxBorder.contains(relatedTarget)) { // 検索窓 textBoxBorderClassList.remove('gbqfqw-hvr', 'gsfe_a'); } if (!submitButton.contains(relatedTarget)) { // 検索ボタン submitButtonClassList.remove('gbqfb-hvr'); } }); } } /** * 挿入された節の親節が、目印となる節の親節か否かを返すコールバック関数。 * @callback isTargetParent * @param {(Document|Element)} parent * @returns {boolean} */ /** * 挿入された節が、目印となる節か否かを返すコールバック関数。 * @callback isTarget * @param {(DocumentType|Element)} target * @returns {boolean} */ /** * 目印となる節が文書に存在するか否かを返すコールバック関数。 * @callback existsTarget * @returns {boolean} */ /** * 目印となる節が挿入された直後に関数を実行する。 * @param {Function} main - 実行する関数。 * @param {isTargetParent} isTargetParent * @param {isTarget} isTarget * @param {existsTarget} existsTarget * @param {Object} [callbacksForFirefox] * @param {isTargetParent} [callbacksForFirefox.isTargetParent] - Firefoxにおける{@link isTargetParent}。 * @param {isTarget} [callbacksForFirefox.isTarget] - Firefoxにおける{@link isTarget}。 * @param {boolean} [timeoutSinceStopParsingDocument=0] - DOM構築完了後に監視を続けるミリ秒数。 * @version 2014-07-21 */ function startScript(main, isTargetParent, isTarget, existsTarget) { /** * {@link checkExistingTarget}で{@link startMain}を実行する間隔(ミリ秒)。 * @constant {number} */ var INTERVAL = 10; /** * {@link checkExistingTarget}で{@link startMain}を実行する回数。 * @constant {number} */ var LIMIT = 500; /** * 実行済みなら真。 * @type {boolean} */ var alreadyCalled = false; // 指定した節が既に存在していれば、即実行 startMain(); if (alreadyCalled) { return; } // FirefoxのMutationObserverは、HTMLのDOM構築に関して要素をまとめて挿入したと見なすため、isTargetParent、isTargetを変更 var callbacksForFirefox = arguments[4]; if (callbacksForFirefox && typeof sidebar !== 'undefined') { if (callbacksForFirefox.isTargetParent) { isTargetParent = callbacksForFirefox.isTargetParent; } if (callbacksForFirefox.isTarget) { isTarget = callbacksForFirefox.isTarget; } } var observer = new MutationObserver(mutationCallback); observer.observe(document, { childList: true, subtree: true, }); var timeoutSinceStopParsingDocument = arguments[5] || 0; if (document.readyState === 'complete') { // DOMの構築が完了していれば onDOMContentLoaded(); } else { document.addEventListener('DOMContentLoaded', onDOMContentLoaded); } /** * {@link startMain}を実行し、スクリプトが開始されていなければさらに{@link timeoutSinceStopParsingDocument}ミリ秒待機し、 * スクリプトが開始されていなければ{@link stopObserving}を実行する。 */ function onDOMContentLoaded() { startMain(); if (timeoutSinceStopParsingDocument === 0) { if (!alreadyCalled) { stopObserving(); } } else { window.setTimeout(function () { if (!alreadyCalled) { stopObserving(); } }, timeoutSinceStopParsingDocument); } document.removeEventListener('DOMContentLoaded', onDOMContentLoaded); } /** * 目印となる節が挿入されたら、監視を停止し、{@link checkExistingTarget}を実行する。 * @param {MutationRecord[]} mutations - A list of MutationRecord objects. * @param {MutationObserver} observer - The constructed MutationObserver object. */ function mutationCallback(mutations, observer) { var slice = Array.prototype.slice, mutation, target, addedNodes, addedNode, i, j, l, l2; for (i = 0, l = mutations.length; i < l; i++) { mutation = mutations[i]; target = mutation.target; if (target.nodeType === Node.ELEMENT_NODE && isTargetParent(target)) { // 子が追加された節が要素節で、かつその節についてisTargetParentが真を返せば addedNodes = slice.call(mutation.addedNodes); for (j = 0, l2 = addedNodes.length; j < l2; j++) { addedNode = addedNodes[j]; if (addedNode.nodeType === Node.ELEMENT_NODE && isTarget(addedNode)) { // 追加された子が要素節で、かつその節についてisTargetが真を返せば observer.disconnect(); checkExistingTarget(0); return; } } } } } /** * {@link startMain}を実行し、スクリプトが開始されていなければ再度実行。 * @param {number} count - {@link startMain}を実行した回数。 */ function checkExistingTarget(count) { startMain(); if (!alreadyCalled && count < LIMIT) { window.setTimeout(checkExistingTarget, INTERVAL, count + 1); } } /** * 指定した節が存在するか確認し、存在すれば{@link stopObserving}を実行しスクリプトを開始。 */ function startMain() { if (!alreadyCalled && existsTarget()) { stopObserving(); main(); } } /** * 監視を停止する。 */ function stopObserving() { alreadyCalled = true; if (observer) { observer.disconnect(); } } } /** * ECMAScript仕様のPolyfill。 */ function polyfill() { if (!String.prototype.hasOwnProperty('contains')) { /** * Determines whether one string may be found within another string, returning true or false as appropriate. * @param {string} searchString - A string to be searched for within this string. * @param {number} [position=0] - The position in this string at which to begin searching for searchString. * @returns {boolean} * @see {@link http://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.contains 21.1.3.6 String.prototype.contains (searchString, position = 0 )} * @see {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/contains String.contains - JavaScript | MDN} * @version polyfill-2013-11-05 * @name String.prototype.contains */ Object.defineProperty(String.prototype, 'contains', { writable: true, enumerable: false, configurable: true, value: function (searchString) { return this.indexOf(searchString, arguments[1]) !== -1; }, }); } // Polyfill for Firefox 24 ESR if (!('EPSILON' in Number)) { // Bug 814014 – implement the new classList specification which permits adding/removing several classes with one call <https://bugzilla.mozilla.org/show_bug.cgi?id=814014> var DOMTokenListPrototype = DOMTokenList.prototype; var handler = { apply: function (addOrRemove, domTokenList, argumentList) { for (var i = 0, l = argumentList.length; i < l; i++) { addOrRemove.call(domTokenList, argumentList[i]); } }, }; DOMTokenListPrototype.add = new Proxy(DOMTokenListPrototype.add, handler); DOMTokenListPrototype.remove = new Proxy(DOMTokenListPrototype.remove, handler); } } })();