Greasy Fork is available in English.

pixiv 検索オプションを追加

検索オプションを、以前のようにラジオボタンで選択出来るようにする / This is a search option add-on script for pixiv. Enables you to select search mode by radio buttons (legacy feature).

2014/09/04時点のページです。最新版はこちら。

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name        pixiv 検索オプションを追加
// @namespace   http://loda.jp/script/
// @id          pixiv-search-box-347021
// @version     2.5.2
// @description 検索オプションを、以前のようにラジオボタンで選択出来るようにする / This is a search option add-on script for pixiv. Enables you to select search mode by radio buttons (legacy feature).
// @match       http://www.pixiv.net/*
// @exclude     http://www.pixiv.net/member_illust.php?*mode=manga*
// @exclude     http://www.pixiv.net/member_illust.php?*mode=big*
// @exclude     http://www.pixiv.net/apps.php*
// @domain      www.pixiv.net
// @match       https://booth.pm/*
// @exclude     https://booth.pm/users/*
// @domain      booth.pm
// @run-at      document-start
// @grant       dummy
// @icon        data:image/vnd.microsoft.icon;base64,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
// @author      100の人
// @homepage    https://greasyfork.org/ja/scripts/265-pixiv-%E6%A4%9C%E7%B4%A2%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E8%BF%BD%E5%8A%A0
// @license     Creative Commons Attribution 4.0 International Public License; http://creativecommons.org/licenses/by/4.0/
// ==/UserScript==

(function () {
'use strict';

polyfill();

// L10N
Gettext.setLocalizedTexts({
	'en': {
		'完全一致': 'Exact match',
		'部分一致': 'Partial match',
		'タイトル・キャプション': 'Title/Description',
		'小説': 'Novels',
		'タグ': 'Tags',
		'キーワード': 'Keyword',
		'本文': 'Content',
		'ユーザー': 'User',
		'グループ': 'Groups',
		'BOOTH': '',
		'すべて': 'All',
		'検索': 'Search',
		'小説検索': 'Search novel',
		'ユーザー検索': 'Search user',
		'グループ検索': 'Search group',
		'商品検索...': 'Search',
		'https://booth.pm/ja/search/': 'https://booth.pm/en/search/',
	},
	'fr': {
		'完全一致': 'Concordance parfaite',
		'部分一致': 'Concordance partielle',
		'タイトル・キャプション': 'Titre, Légende',
		'小説': 'Roman',
		'タグ': 'Mots-clés',
		'キーワード': 'Mots-clés',
		'本文': 'Contenu',
		'ユーザー': 'Utilisateur',
		'グループ': 'Groups',
		'BOOTH': '',
		'すべて': 'Tout',
		'検索': 'Rechercher',
		'小説検索': 'Rechercher un roman',
		'ユーザー検索': '',
		'グループ検索': 'Rechercher un groupe',
		'商品検索...': '',
		'https://booth.pm/ja/search/': '',
	},
	'ko': {
		'完全一致': '완전 일치',
		'部分一致': '부분 일치',
		'タイトル・キャプション': '제목・캡션',
		'小説': '소설',
		'タグ': '태그',
		'キーワード': '키워드',
		'本文': '본문',
		'ユーザー': '유저',
		'BOOTH': '',
		'グループ': '그룹',
		'すべて': '전체',
		'検索': '검색',
		'小説検索': '소설 검색',
		'ユーザー検索': '유저 검색',
		'グループ検索': '그룹 검색',
		'商品検索...': '',
		'https://booth.pm/ja/search/': '',
	},
	'ru': {
		'完全一致': 'Полное совпадение',
		'部分一致': 'Частичное совпадение',
		'タイトル・キャプション': 'Заголовок',
		'小説': 'Рассказы',
		'タグ': 'Метка',
		'キーワード': 'Ключевые слова',
		'本文': 'Текст',
		'ユーザー': 'Пользователь',
		'グループ': 'Группа',
		'BOOTH': '',
		'すべて': 'Все',
		'検索': 'Поиск',
		'小説検索': 'Искать рассказ',
		'ユーザー検索': 'Искать пользователя',
		'グループ検索': 'Искать группу',
		'商品検索...': '',
		'https://booth.pm/ja/search/': '',
	},
	'th': {
		'完全一致': '',
		'部分一致': '',
		'タイトル・キャプション': 'ชื่อและคำบรรยาย',
		'小説': 'นิยาย',
		'タグ': 'แท็ก',
		'キーワード': 'คีย์เวิร์ด',
		'本文': '',
		'ユーザー': 'ผู้ใช้',
		'グループ': '',
		'BOOTH': '',
		'すべて': 'ทั้งหมด',
		'検索': 'ค้นหา',
		'小説検索': '',
		'ユーザー検索': '',
		'グループ検索': '',
		'商品検索...': '',
		'https://booth.pm/ja/search/': '',
	},
	'zh': {
		'完全一致': '完全相同',
		'部分一致': '部分相同',
		'タイトル・キャプション': '题目/简述',
		'小説': '小说',
		'タグ': '标签',
		'キーワード': '关键词',
		'本文': '内容',
		'ユーザー': '用户',
		'グループ': '群组',
		'BOOTH': '',
		'すべて': '全部',
		'検索': '搜索',
		'小説検索': '搜索小说',
		'ユーザー検索': '搜索用户',
		'グループ検索': '搜索群组',
		'商品検索...': '',
		'https://booth.pm/ja/search/': '',
	},
	'zh-tw': {
		'完全一致': '完全相同',
		'部分一致': '部分相同',
		'タイトル・キャプション': '題目/簡述',
		'小説': '小說',
		'タグ': '標籤',
		'キーワード': '關鍵詞',
		'本文': '內容',
		'ユーザー': '用戶',
		'グループ': '群組',
		'BOOTH': '',
		'すべて': '全部',
		'検索': '搜索',
		'小説検索': '搜索小說',
		'ユーザー検索': '搜索用戶',
		'グループ検索': '搜索群組',
		'商品検索...': '',
		'https://booth.pm/ja/search/': '',
	},
	'es': {
		'完全一致': 'Coincidencia exacta',
		'部分一致': 'Coincidencia parcial',
		'タイトル・キャプション': 'Título/Descripción',
		'小説': 'Novelas',
		'タグ': 'Etiquetas',
		'キーワード': 'Palabra clave',
		'本文': 'Mensaje',
		'ユーザー': 'Usuarios',
		'グループ': 'Grupo',
		'BOOTH': '',
		'すべて': 'Todos',
		'検索': 'Buscar',
		'小説検索': 'Buscar novela',
		'ユーザー検索': 'Buscar usuario',
		'グループ検索': 'Buscar grupo',
		'商品検索...': '',
		'https://booth.pm/ja/search/': '',
	},
});



if (window.location.host === 'booth.pm') {
	startScript(main,
			function (parent) { return parent.localName === 'nav'; },
			function (target) { return target.classList.contains('ctrl-nav'); },
			function () { return document.getElementsByClassName('ctrl-nav')[0]; }, {
				isTargetParent: function (parent) { return parent.localName === 'html'; },
				isTarget: function (target) { return target.localName === 'body'; },
			});
} else {
	startScript(main,
			function (parent) { return parent.localName === 'body'; },
			function (target) { return target.id === 'wrapper'; },
			function () { return document.getElementById('wrapper'); });
}

function main() {
	var loggedin = !document.body.classList.contains('not-logged-in'), booth = window.location.host === 'booth.pm',
			form, submitButton, word = document.getElementById(booth ? 'query' : 'suggest-input'), mode, subMode, tabs,
			input, searchParams;

	// 言語の設定
	Gettext.setLocale(booth ? window.navigator.language : document.documentElement.lang);

	// スタイルシートの設定
	document.head.insertAdjacentHTML('beforeend', '<style> \
		.ui-search, \
		.global-nav .item-search-box .item-search { \
			display: flex; \
			align-items: center; \
			width: initial; \
			/* BOOTH */ \
			max-width: initial; \
		} \
		.ui-search { \
			background: #FFFFFF; \
			padding: 0.4em 2em; \
			border-left: 1px solid #D6DEE5; \
			border-right: 1px solid #D6DEE5; \
			border-bottom: 1px solid #D6DEE5; \
			border-radius: 0 0 5px 5px; \
			justify-content: center; \
			/* 通知が検索窓に隠れる問題の修正 */ \
			z-index: 98; \
			/* トップページ・pixivについて */ \
			margin-bottom: 10px; \
		} \
		.not-logged-in .ui-search { \
			/* ログイン前 */ \
			border-top: initial; \
			border-top-left-radius: initial; \
			border-top-right-radius: initial; \
		} \
		\
		/*------------------------------------ \
			検索窓 \
		*/ \
		.ui-search .container, \
		.global-nav .item-search-box .twitter-typeahead { \
			flex-grow: 1; \
			flex-shrink: 0; \
			width: initial; \
			max-width: 250px; \
			} \
		.global-nav .item-search-box .twitter-typeahead { \
			max-width: 356px; \
			} \
		\
		/*------------------------------------ \
			送信ボタン \
		*/ \
		.ui-search input.submit { \
			position: static; \
			margin-right: 1em; \
		} \
		\
		/*------------------------------------ \
			検索オプション \
		*/ \
		.ui-search label, \
		.item-search label { \
			padding: 0 0.7em; \
			display: flex; \
			align-items: center; \
			white-space: nowrap; \
		} \
		.ui-search label input { \
			margin-right: 0.3em; \
			width: initial; \
		} \
		.item-search label, \
		.item-search .sub-options { \
			/* BOOTH */ \
			font-size: 12px; \
			font-weight: normal; \
		} \
		\
		/*------------------------------------ \
			副検索モード \
		*/ \
		.sub-options label:not(:first-of-type) { \
			display: none; \
			position: absolute; \
			z-index: 1; \
			width: 13em; \
			height: 2em; \
			border: solid 1px #D6DEE5; \
			border-top: none; \
			border-bottom: none; \
			background: #FFFFFF; \
		} \
		.sub-options::after { \
			content: ""; \
			padding: 0 0.7em; \
			display: none; \
			position: absolute; \
			z-index: 1; \
			width: 13em; \
			height: 17px; \
			border: solid 1px #FFFFFF; \
			border-top: none; \
			border-bottom: none; \
			bottom: 0; \
		} \
		.item-search .sub-options::after { \
			/* BOOTH */ \
			top: 23px; \
			bottom: initial; \
		} \
		.sub-options label:nth-of-type(3) { \
			margin-top: 2em; \
		} \
		.sub-options label:nth-of-type(4) { \
			margin-top: 4em; \
		} \
		.sub-options label:nth-of-type(5) { \
			margin-top: 6em; \
		} \
		.sub-options label:last-of-type { \
			border-bottom: 1px solid #D6DEE5; \
			border-radius: 0 0 5px 5px; \
		} \
		.sub-options:hover label { \
			display: flex; \
		} \
		.sub-options:hover::after { \
			display: block; \
		} \
		\
		/*------------------------------------ \
			副検索モードが右側にはみ出す問題に対処 \
		*/ \
		.ctrl-nav { \
			/* お買い物ガイド */ \
			position: relative; \
			z-index: 1; \
		} \
		.ctrl-nav::after { \
			content: ""; \
			position: absolute; \
			width: 100%; \
			border-bottom: solid 1px #D3D3D3; \
			left: -1px; \
			top: 48px; \
		} \
		\
		/*------------------------------------ \
			ページ本体 \
		*/ \
		#wrapper { \
			margin-top: initial; \
		} \
		\
		/*==================================== \
			移動元のスペースを詰める \
		*/ \
		/*------------------------------------ \
			ヘッダ \
		*/ \
		.header .layout-wrapper { \
			height: 82px; \
		} \
		/*------------------------------------ \
			サイト名 \
		*/ \
		.header-logo { \
			display: none; \
		} \
		/*------------------------------------ \
			ヘッダ内広告 \
		*/ \
		#header-banner { \
			margin-left: 990px; \
			width: calc(50% - 515px); \
		} \
		#header-banner .multi-ads-area, \
		#header-banner .multi-ads-area > div, \
		#header-banner .multi-ads-area > div > div iframe, \
		#header-banner .multi-ads-area > iframe { \
			width: 100% !important; \
		} \
		\
		/*==================================== \
			BOOTHについて、表示領域の幅が狭い場合 \
		*/ \
		@media screen and (max-width: 1250px) { \
			/*------------------------------------ \
				検索フォーム \
			*/ \
			.global-nav .item-search-box .item-search { \
				position: absolute; \
				top: 48px; \
				left: 0; \
				right: -421px; \
				height: 30px; \
				margin-top: 1px; \
			} \
			\
			/*------------------------------------ \
				検索窓\
			*/ \
			.global-nav .item-search-box .twitter-typeahead { \
				position: absolute !important; \
				width: 356px; \
				top: -40px; \
				left: 150px; \
			} \
			\
			/*------------------------------------ \
				副検索モード \
			*/ \
			.item-search :nth-last-child(-n+2).sub-options label:not(:first-of-type) { \
				right: initial; \
			} \
			.item-search :nth-last-child(-n+2).sub-options::after { \
				right: initial; \
				border-right-color: #FFFFFF; \
			} \
			\
			/*------------------------------------ \
				ページ本体 \
			*/ \
			.page-wrap { \
				padding-top: 78px; \
			} \
			\
			/*------------------------------------ \
				副検索モード \
			*/ \
			.item-search .sub-options::after { \
				height: 6px; \
				top: initial; \
				bottom: 1px; \
			} \
		} \
	</style>');

	/**
	 * 検索オプションを設定するラジオボタンのHTML文字列。
	 * @type {string}
	 */
	var optionsHTML = ' \
		<label> \
			<input data-placeholder="' + h(_('検索')) + '" data-word-name="word" data-form-action="http://www.pixiv.net/search.php" value="s_tag_full" name="s_mode" type="radio" />'
			+ h(_('完全一致')) +
		'</label> \
		<label> \
			<input data-placeholder="' + h(_('検索')) + '" data-word-name="word" data-form-action="http://www.pixiv.net/search.php" value="s_tag" name="s_mode" type="radio" />'
			+ h(_('部分一致')) +
		'</label> \
		<label> \
			<input data-placeholder="' + h(_('検索')) + '" data-word-name="word" data-form-action="http://www.pixiv.net/search.php" value="s_tc" name="s_mode" type="radio" />'
			+ h(_('タイトル・キャプション')) +
		'</label> \
		<div id="s_novel" class="sub-options" title="' + h(_('小説')) + '"> \
			<label> \
				<input data-placeholder="' + h(_('小説検索')) + '" data-word-name="word" data-form-action="http://www.pixiv.net/novel/search.php" value="s_novel" name="s_mode" type="radio" /> \
				<img alt="' + h(_('小説')) + '" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAARBAMAAADNtor0AAAAD1BMVEVldC2Spb6susrCzdr9//waY6iPAAAAAXRSTlMAQObYZgAAAEFJREFUCNdjYBAUZIABERdDBNNZAM6ECQsCmY6CQCDAIAJiugABJtPZ2NiEfFFDIROYqIuzMkzUxcXZCMIUhAEBACaMGgfSfm2+AAAAAElFTkSuQmCC" /> \
			</label> \
			<label> \
				<input data-mode-name="" data-word-name="tag" data-form-action="/novel/tags.php" value="s_tag_full" name="s_sub_mode" type="radio" /> \
				' + h(_('タグ')) + ' \
			</label> \
			<label> \
				<input value="s_tag" name="s_sub_mode" type="radio" /> \
				' + h(_('キーワード')) + ' \
			</label> \
			<label> \
				<input value="s_tc" name="s_sub_mode" type="radio" /> \
				' + h(_('本文')) + ' \
			</label> \
		</div>' +
		(loggedin ? '<label title="' + h(_('ユーザー')) + '">\
			<input data-placeholder="' + h(_('ユーザー検索')) + '" data-word-name="nick" data-form-action="http://www.pixiv.net/search_user.php" value="s_usr" name="s_mode" type="radio" /> \
				<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" width="16px" height="16px"> \
					<title>' + h(_('ユーザー')) + '</title> \
					<path fill="#809DB8" d="M848,348 l98,-20 q28,0 54,22 q38,32 48,44 q22,26 34,26 q16,0 26,-4 q14,-6 52,2 q32,6 48,24 q18,20 23,42 t5,50 q0,32 2,48 q-4,24 -2,38 q6,36 6,62 t-6,44 t12,28 t38,10 h22 q28,0 40,46 q8,30 8,60 q0,14 -2,30 l-6,46 q-2,16 -6,22 q-6,10 -10,16 t-14,14 l-18,12 l-24,16 q-18,10 -30,18 q-22,62 -50,102 q-34,48 -58,70 l-22,22 q-10,96 -10,118 v6 q0,8 2,16 q0,8 4,22 q4,18 12,28 l20,28 q10,14 30,28 q8,6 46,26 q26,14 62,24 q46,12 82,18 q88,12 138,28 q60,18 102,44 t62,40 t50,46 q28,30 30,32 q20,22 40,98 q20,74 20,140 v66 h-1768 v-72 q0,-42 14,-126 q16,-92 34,-106 q8,-6 32,-34 t46,-48 t62,-46 q36,-24 100,-44 q66,-22 140,-32 q60,-8 102,-22 q40,-12 74,-32 t50,-34 q26,-24 34,-36 q10,-16 16,-30 q12,-18 10,-20 q-4,-6 -2,-6 v-132 q-4,-2 -12,-8 q-8,-4 -28,-22 q-14,-10 -40,-36 q-18,-18 -38,-50 t-32,-64 l-36,-18 q-20,-10 -24,-14 q-4,-2 -12,-18 q-8,-14 -8,-16 q0,-4 -2,-18 t-4,-22 q0,-4 2,-10 t5,-26 t3,-38 q0,-20 8,-38 q10,-32 12,-36 q8,-14 18,-24 t22,-10 h14 q8,-2 18,-12 q12,-12 8,-30 q2,-64 2,-134 q0,-22 8,-50 q10,-38 18,-58 q12,-32 38,-56 t60,-32 l52,-12 h-2 q2,0 6,-2 q10,-2 12,-2 v-6 v-4 q-2,-4 0,-6 q0,-2 8,-4 t22,-2 z" /> \
				</svg> \
			</label>' : '') +
		'<div id="s_group" class="sub-options" title="' + h(_('グループ')) + '"> \
			<label> \
				<input data-placeholder="' + h(_('グループ検索')) + '" data-mode-name="mode" data-word-name="word" data-form-action="http://www.pixiv.net/group/search_group.php" value="s_group" name="s_mode" type="radio" /> \
				<img alt="' + h(_('グループ')) + '" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEWLpryswdDV3ubr8POkfP3KAAAAT0lEQVQI12NYBQQMYGLd7/e/GFYtX/6LYfX27fsYVqU/i2JYwX4hjGEJk4MYw0Y2hSiGLUwNcgzrVr9aBxLjY1jCDOJGP93FsPrf/ldgUwDsuCQfQnDv1AAAAABJRU5ErkJggg==" /> \
			</label> \
			<label> \
				<input value="keyword_all" name="s_sub_mode" type="radio" />'
				+ h(_('すべて')) +
			'</label> \
			<label> \
				<input value="tag_full" name="s_sub_mode" type="radio" />'
				+ h(_('完全一致')) +
			'</label> \
			<label> \
				<input value="tag" name="s_sub_mode" type="radio" />'
				+ h(_('部分一致')) +
			'</label> \
			<label> \
				<input value="keyword" name="s_sub_mode" type="radio" />'
				+ h(_('タイトル・キャプション')) +
			'</label> \
		</div> \
		<label title="' + h(_('BOOTH')) + '"> \
			<input data-placeholder="' + h(_('商品検索...')) + '" data-form-action="' + h(_('https://booth.pm/ja/search/')) + '" value="s_booth" name="s_mode" type="radio"> \
			<img src="https://booth.pm/favicon.ico" width="16" alt="' + h(_('BOOTH')) + '" /> \
		</label>';

	var wrapper = document.getElementById('wrapper');
	if (loggedin) {
		// ログイン後、またはBOOTH
		form = word.form;
		submitButton = form.querySelector('[type="submit"]');

		word.required = true;

		if (booth) {
			// 送信ボタンの移動
			var observer;
			var containers = document.getElementsByClassName('twitter-typeahead');
			if (containers[0]) {
				containers[0].appendChild(submitButton);
			} else {
				observer = new MutationObserver(function (mutations, observer) {
					if (mutations.some(function (mutation) {
						return Array.prototype.some.call(mutation.addedNodes, function (node) {
							return node.nodeType === Node.ELEMENT_NODE && node.classList.contains('twitter-typeahead');
						});
					})) {
						observer.disconnect();
						containers[0].appendChild(submitButton);
					}
				});
				observer.observe(form, {
					childList: true,
				});
			}

			// ページが書き換えられたとき
			observer = new MutationObserver(function (mutations, observer) {
				if (mutations.some(function (mutation) { return mutation.target.id === 'mini-carts'; })) {
					var newForm = document.getElementsByClassName('item-search')[0];
					form.dataset.searchParams = newForm.dataset.searchParams;
					newForm.parentElement.replaceChild(form, newForm);
				}
			});
			observer.observe(document, {
				childList: true,
				subtree: true,
			});
		} else {
			// デフォルトの検索オプションを取得・削除
			input = form.s_mode || form.mode;
			subMode = mode = input ? input.value : 's_tag';
			if (input) {
				input.remove();
			}

			// フォームの移動
			wrapper.insertBefore(form, wrapper.firstChild);
		}

		// 検索オプションを設定するラジオボタンの追加
		form.insertAdjacentHTML('beforeend', optionsHTML);
	} else {
		// ログイン前
		// 検索語句の取得
		var searchWord;
		searchParams = new URLSearchParams(window.location.search.replace('?', ''));
		var smallForm = document.getElementsByClassName('search-small')[0];
		if (smallForm) {
			searchWord = smallForm.word.value;
			smallForm.remove();
			// デフォルトの検索オプションを取得
			input = smallForm.s_mode || smallForm.mode;
		} else {
			searchWord = searchParams.get('word') || '';
		}
		subMode = mode = input ? input.value : 's_tag';

		// 検索フォームを構築する
		wrapper.insertAdjacentHTML('afterbegin', '<form class="ui-search"> \
			<div class="container"> \
				<input required="" id="suggest-input" name="word" value="' + h(searchWord) + '" placeholder="' + h(_('検索')) + '"> \
			</div> \
			<input class="submit sprites-search-old" type="submit">'
			+ optionsHTML +
		'</form>');

		form = wrapper.firstElementChild;
		word = form.word;
		submitButton = form.querySelector('[type="submit"]');
	}

	if (booth) {
		mode = 's_booth';
	} else {
		var pathname = window.location.pathname;
		switch (pathname.split('/')[1]) {
			case 'search.php':
				if (!loggedin) {
					mode = subMode = searchParams.get('s_mode');
				}
				break;
			case 'novel':
				mode = 's_novel';
				if (!loggedin) {
					word.placeholder = _('小説検索');
					subMode = searchParams.get('s_mode') || 's_tag';
				}
				if (pathname === '/novel/tags.php') {
					subMode = 's_tag_full';
				}
				break;
			case 'group':
				mode = 's_group';
				if (!loggedin) {
					word.placeholder = _('グループ検索');
					subMode = searchParams.get('mode') || 'keyword_all';
				}
				break;
		}
	}

	form.addEventListener('submit', function (event) {
		var searchMode, subOption, hiddenParams, i, l;

		if (!/\S/.test(word.value)) {
			// 空白以外の文字が入力されていなければ
			word.value = '';
			return;
		}

		searchMode = form.querySelector('[name="s_mode"]:checked');
		if (booth) {
			if (searchMode.value === 's_booth') {
				// BOOTHからBOOTHに移動するとき
				return;
			} else {
				// BOOTHからpixivに移動するとき
				event.stopPropagation();
				event.preventDefault();
				submitButton.removeAttribute('name');
			}
		} else {
			if (searchMode.value === 's_booth') {
				// pixivからBOOTHに移動するとき
				event.preventDefault();
				window.location.assign(searchMode.dataset.formAction + encodeURIComponent(word.value));
				return;
			}
		}

		subOption = form.querySelector('[name="s_sub_mode"]:checked');

		if ((subOption || searchMode).value.endsWith('tag_full') && /[^  ][  ]+[^  ]/.test(word.value)) {
			// 完全一致タグ検索で、先頭・末尾以外に半角スペース・全角スペースが含まれていれば
			if (subOption) {
				searchMode.checked = false;
				searchMode.click();
			} else {
				// イラスト
				searchMode.value = 's_tag';
			}
		}

		form.action = searchMode.dataset.formAction;
		if (searchMode.dataset.wordName) {
			word.name = searchMode.dataset.wordName;
		}
		if (searchMode.dataset.modeName) {
			searchMode.name = searchMode.dataset.modeName;
		} else if (searchMode.dataset.modeName === '') {
			searchMode.removeAttribute('name');
		}

		if (subOption) {
			// 副検索モードが存在すれば
			searchMode.value = subOption.value;
			subOption.removeAttribute('name');
			if (subOption.dataset.formAction) {
				form.action = subOption.dataset.formAction;
			}
			if (subOption.dataset.wordName) {
				word.name = subOption.dataset.wordName;
			}
			if (subOption.dataset.modeName) {
				searchMode.name = subOption.dataset.modeName;
			} else if (subOption.dataset.modeName === '') {
				searchMode.removeAttribute('name');
			}
		}

		if (form.action !== window.location.origin + window.location.pathname) {
			// サービス間をまたぐ場合、不要なパラメーターは送信しない
			Array.prototype.forEach.call(form.querySelectorAll('[type="hidden"]'), function (hiddenParam) {
				hiddenParam.disabled = true;
			});
		}

		if (event.defaultPrevented) {
			// httpsからhttpに移動する際のセキュリティ警告を回避
			var searchParams = new URLSearchParams();
			Array.prototype.forEach.call(form, function (element) {
				if (element.name && !element.disabled && (element.type !== 'checkbox' && element.type !== 'radio' || element.checked)) {
					searchParams.append(element.name, element.value);
				}
			});
			window.location.assign(form.action + '?' + searchParams);
		}
	});

	// 副検索モードの選択
	form.addEventListener('change', function (event) {
		var subOptions = event.target.parentElement.parentElement, subOption;
		if (event.target.name === 's_mode') {
			// 検索モードの選択なら
			if (subOptions.classList.contains('sub-options')) {
				// 副検索モードが存在すれば
				subOptions.querySelector('[value="s_tag"], [value="keyword_all"]').checked = true;
			} else {
				subOption = form.querySelector('[name="s_sub_mode"]:checked');
				if (subOption) {
					subOption.checked = false;
				}
			}
			word.placeholder = event.target.dataset.placeholder;
		} else if (event.target.name === 's_sub_mode') {
			// 副検索モードの選択なら
			subOption = subOptions.firstElementChild.firstElementChild;
			subOption.checked = true;
			word.placeholder = subOption.dataset.placeholder;
		}
	});

	// ラベルをダブルクリックで検索
	form.addEventListener('dblclick', function (event) {
		var target = event.target;
		if (target['matches' in target ? 'matches' : /* Firefox */ 'mozMatchesSelector']('label, label *')) { // Bug 886308 – Implement Element.matches() <https://bugzilla.mozilla.org/show_bug.cgi?id=886308>
			submitButton.click();
		}
	});

	// 現在の検索モードを設定
	form.querySelector(mode === subMode ? '[value="' + mode + '"]' : '#' + mode + ' [value="' + subMode + '"]').click();

	// 副検索モードが右側にはみ出す問題に対処
	if (!booth && document.getElementById('s_group').offsetLeft > 795) {
		document.head.insertAdjacentHTML('beforeend', '<style> \
			#s_group label:not(:first-of-type) { \
				right: -1px; \
			} \
			#s_group::after { \
				right: -1px; \
				border-right-color: transparent; \
			} \
		</style>');
	}
}



/**
 * 挿入された節の親節が、目印となる節の親節か否かを返すコールバック関数。
 * @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-09-04
 */
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 MozSettingsEvent !== 'undefined') {
		isTargetParent = callbacksForFirefox.isTargetParent || isTargetParent;
		isTarget = callbacksForFirefox.isTarget || 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);
		}
	}

	/**
	 * 目印となる節が挿入されたら、監視を停止し、{@link checkExistingTarget}を実行する。
	 * @param {MutationRecord[]} mutations - A list of MutationRecord objects.
	 * @param {MutationObserver} observer - The constructed MutationObserver object.
	 */
	function mutationCallback(mutations, observer) {
		var mutation, target, nodeType, addedNodes, addedNode, i, j, l, l2;
		for (i = 0, l = mutations.length; i < l; i++) {
			mutation = mutations[i];
			target = mutation.target;
			nodeType = target.nodeType;
			if ((nodeType === Node.ELEMENT_NODE) && isTargetParent(target)) {
				// 子が追加された節が要素節で、かつその節についてisTargetParentが真を返せば
				addedNodes = Array.prototype.slice.call(mutation.addedNodes);
				for (j = 0, l2 = addedNodes.length; j < l2; j++) {
					addedNode = addedNodes[j];
					nodeType = addedNode.nodeType;
					if ((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();
		}
		document.removeEventListener('DOMContentLoaded', onDOMContentLoaded);
	}
}

/**
 * 国際化・地域化関数の読み込み、ECMAScriptとWHATWG仕様のPolyfill。
 */
function polyfill() {
	/**
	 * DOM関連のメソッド。
	 */
	var DOMUtils = {
		/**
		 * XMLの特殊文字を文字参照に置換する。
		 * @param {string} str - プレーンな文字列。
		 * @returns {string} HTMLとして扱われる文字列。
		 */
		convertSpecialCharactersToCharacterReferences: function (str) {
			return str.replace(/[&<>"']/g, function (specialCharcter) {
				return '&#x' + specialCharcter.charCodeAt(0).toString(16) + ';'
			});
		},
	};
	window.h = DOMUtils.convertSpecialCharactersToCharacterReferences;

	/**
	 * 以下のような形式の翻訳リソース。すべての言語について、msgidは欠けていないものとする。
	 * {@link Gettext.DEFAULT_LOCALE}のリソースを必ず含む。{@link Gettext.ORIGINAL_LOCALE}のリソースは無視される。
	 * {
	 *     'IETF言語タグ': {
	 *         '翻訳前 (msgid)': '翻訳後 (msgstr)',
	 *         ……
	 *     },
	 *     ……
	 * }
	 * @typedef {Object} LocalizedTexts
	 */

	/**
	 * i18n。
	 * @version 2014-07-10
	 */
	window.Gettext = {
		/**
		 * 翻訳対象文字列 (msgid) の言語。IETF言語タグの「language」サブタグ。
		 * @constant {string}
		 */
		ORIGINAL_LOCALE: 'ja',

		/**
		 * クライアントの言語の翻訳リソースが存在しないとき、どの言語に翻訳するか。IETF言語タグの「language」サブタグ。
		 * @constant {string}
		 */
		DEFAULT_LOCALE: 'en',

		/**
		 * 翻訳リソースを追加する。
		 * @param {LocalizedTexts} localizedTexts
		 */
		setLocalizedTexts: function (localizedTexts) {
			this.multilingualLocalizedTexts = localizedTexts;
		},

		/**
		 * クライアントの言語を設定する。
		 * @param {string} clientLang - IETF言語タグ(「language」と「language-REGION」にのみ対応)。
		 */
		setLocale: function (clientLang) {
			var splitedClientLang = clientLang.split('-', 2);
			this.language = splitedClientLang[0].toLowerCase();
			this.langtag = this.language + (splitedClientLang[1] ? '-' + splitedClientLang[1].toUpperCase() : '');
			if (this.language === 'ja') {
				// ja-JPをjaと同一視
				this.langtag = this.language;
			}
		},

		/**
		 * テキストをクライアントの言語に変換する。
		 * @param {string} message - 翻訳前。
		 * @returns {string} 翻訳後。
		 */
		gettext: function (message) {
			// クライアントの言語が翻訳元の言語なら、そのまま返す
			return this.langtag === this.ORIGINAL_LOCALE && message
					// クライアントの言語の翻訳リソースが存在すれば、それを返す
					|| this.langtag in this.multilingualLocalizedTexts && this.multilingualLocalizedTexts[this.langtag][message]
					// 地域下位タグを取り除いた言語タグの翻訳リソースが存在すれば、それを返す
					|| this.language in this.multilingualLocalizedTexts && this.multilingualLocalizedTexts[this.language][message]
					// 既定言語の翻訳リソースが存在すれば、それを返す
					|| this.DEFAULT_LOCALE in this.multilingualLocalizedTexts && this.multilingualLocalizedTexts[this.DEFAULT_LOCALE][message]
					// そのまま返す
					|| message;
		},

		/**
		 * クライアントの言語。{@link Gettext.setLocale}から変更される。
		 * @type {string}
		 * @access private
		 */
		langtag: 'ja',

		/**
		 * クライアントの言語のlanguage部分。{@link Gettext.setLocale}から変更される。
		 * @type {string}
		 * @access private
		 */
		language: 'ja',

		/**
		 * 翻訳リソース。{@link Gettext.setLocalizedTexts}から変更される。
		 * @type {LocalizedTexts}
		 * @access private
		 */
		multilingualLocalizedTexts: {},
	};
	window._ = Gettext.gettext.bind(Gettext);

	// Polyfill for Opera and Google Chrome
	if (!''.endsWith) {
		/**
		 * Determines whether a string ends with the characters of another string, returning true or false as appropriate.
		 * @param {string} searchString - The characters to be searched for at the end of this string.
		 * @param {number} [endPosition] - Search within this string as if this string were only this long; defaults to this string's actual length, clamped within the range established by this string's length.
		 * @returns {boolean}
		 * @see {@link http://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.endswith 21.1.3.7 String.prototype.endsWith (searchString [, endPosition] )}
		 * @see {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith String.endsWith - JavaScript | MDN}
		 * @version polyfill-2013-11-05
		 * @name String.prototype.endsWith
		 */
		Object.defineProperty(String.prototype, 'endsWith', {
			writable: true,
			enumerable: false,
			configurable: true,
			value: function (searchString) {
				var searchStr = String(searchString),
						endPosition = arguments[1],
						len = this.length,
						end = endPosition === undefined ? len : Math.min(Math.max(Math.floor(endPosition) || 0, 0), len);
				return this.substring(end - searchStr.length, end) === searchStr;
			},
		});

		/**
		 * 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, Opera and Google Chrome
	if (typeof URLSearchParams === 'undefined') {
		/**
		 * A URLSearchParams object has an associated list of name-value pairs, which is initially empty.
		 * @constructor
		 * @param {(string|URLSearchParams)} [init=""]
		 * @see {@link http://url.spec.whatwg.org/#interface-urlsearchparams Interface URLSearchParams - URL Standard}
		 * @version polyfill-2014-03-18
		 * @name URLSearchParams
		 */
		Object.defineProperty(window, 'URLSearchParams', {
			writable: true,
			enumerable: false,
			configurable: true,
			value: function (init) {
				var strings, string, index, name, value, i, l;
				this._pairs = [];
				if (init) {
					if (init instanceof URLSearchParams) {
						for (i = 0, l = init._pairs.length; i < l; i++) {
							this._pairs.push([init._pairs[i][0], init._pairs[i][1]]);
						}
					} else {
						strings = init.split('&');
						if (!strings[0].contains('=')) {
							strings[0] = '=' + strings[0];
						}
						for (i = 0, l = strings.length; i < l; i++) {
							string = strings[i];
							if (string === '') {
								continue;
							}
							index = string.indexOf('=');
							if (index !== -1) {
								name = string.slice(0, index);
								value = string.slice(index + 1);
							} else {
								name = string;
								value = '';
							}
							this._pairs.push([
								decodeURIComponent(name.replace(/\+/g, ' ')),
								decodeURIComponent(value.replace(/\+/g, ' '))
							]);
						}
					}
				}
			}
		});
		/**
		 * Append a new name-value pair whose name is name and value is value, to the list of name-value pairs.
		 * @param {string} name
		 * @param {string} value
		 * @name URLSearchParams#append
		 */
		Object.defineProperty(URLSearchParams.prototype, 'append', {
			writable: true,
			enumerable: false,
			configurable: true,
			value: function (name, value) {
				this._pairs.push([String(name), String(value)]);
			}
		});
		/**
		 * Remove all name-value pairs whose name is name.
		 * @param {string} name
		 * @name URLSearchParams#delete
		 */
		Object.defineProperty(URLSearchParams.prototype, 'delete', {
			writable: true,
			enumerable: false,
			configurable: true,
			value: function (name) {
				var i;
				for (i = 0; i < this._pairs.length; i++) {
					if (this._pairs[i][0] === name) {
						this._pairs.splice(i, 1);
						i--;
					}
				}
			}
		});
		/**
		 * Return the value of the first name-value pair whose name is name, and null if there is no such pair.
		 * @param {string} name
		 * @name URLSearchParams#get
		 * @returns {?string}
		 */
		Object.defineProperty(URLSearchParams.prototype, 'get', {
			writable: true,
			enumerable: false,
			configurable: true,
			value: function (name) {
				var i, l;
				for (i = 0, l = this._pairs.length; i < l; i++) {
					if (this._pairs[i][0] === name) {
						return this._pairs[i][1];
					}
				}
				return null;
			}
		});
		/**
		 * Return the values of all name-value pairs whose name is name, in list order, and the empty sequence otherwise.
		 * @param {string} name
		 * @name URLSearchParams#getAll
		 * @returns {string[]}
		 */
		Object.defineProperty(URLSearchParams.prototype, 'getAll', {
			writable: true,
			enumerable: false,
			configurable: true,
			value: function (name) {
				var pairs = [], i, l;
				for (i = 0, l = this._pairs.length; i < l; i++) {
					if (this._pairs[i][0] === name) {
						pairs.push(this._pairs[i][1]);
					}
				}
				return pairs;
			}
		});
		/**
		 * If there are any name-value pairs whose name is name, set the value of the first such name-value pair to value and remove the others.
		 * Otherwise, append a new name-value pair whose name is name and value is value, to the list of name-value pairs.
		 * @param {string} name
		 * @param {string} value
		 * @name URLSearchParams#set
		 */
		Object.defineProperty(URLSearchParams.prototype, 'set', {
			writable: true,
			enumerable: false,
			configurable: true,
			value: function (name, value) {
				var flag, i;
				for (i = 0; i < this._pairs.length; i++) {
					if (this._pairs[i][0] === name) {
						if (flag) {
							this._pairs.splice(i, 1);
							i--;
						} else {
							this._pairs[i][1] = String(value);
							flag = true;
						}
					}
				}
				if (!flag) {
					this.append(name, value);
				}
			}
		});
		/**
		 * Return true if there is a name-value pair whose name is name, and false otherwise.
		 * @param {string} name
		 * @name URLSearchParams#has
		 * @returns {boolean}
		 */
		Object.defineProperty(URLSearchParams.prototype, 'has', {
			writable: true,
			enumerable: false,
			configurable: true,
			value: function (name) {
				var i, l;
				for (i = 0, l = this._pairs.length; i < l; i++) {
					if (this._pairs[i][0] === name) {
						return true;
					}
				}
				return false;
			}
		});
		/**
		 * Return the serialization of the URLSearchParams object's associated list of name-value pairs.
		 * @name URLSearchParams#toString
		 * @returns {string}
		 */
		Object.defineProperty(URLSearchParams.prototype, 'toString', {
			writable: true,
			enumerable: false,
			configurable: true,
			value: function () {
				return this._pairs.map(function (pair) {
					return encodeURIComponent(pair[0]) + '=' + encodeURIComponent(pair[1]);
				}).join('&');
			}
		});
	}
}

})();