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/07/13 時点のページです。最新バージョンを参照してください。

質問やレビューの投稿はこちらへ、スクリプトの通報はこちらへお寄せください。
// ==UserScript==
// @name        pixiv 検索オプションを追加
// @namespace   http://loda.jp/script/
// @id          pixiv-search-box-347021
// @version     2.5.0
// @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 { \
			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-07-06
 */
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);
		}
	}

	/**
	 * 目印となる節が挿入されたら、監視を停止し、{@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.setlang}から変更される。
	 * @type {string}
	 * @access private
	 */
	langtag: 'ja',

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

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

// Polyfill for Blink
if (!String.prototype.hasOwnProperty('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;
		},
	});
}

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 and Blink
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('&');
		}
	});
}
}

})();