// ==UserScript==
// @name pixiv 検索オプションを追加
// @name:ja pixiv 検索オプションを追加
// @namespace http://loda.jp/script/
// @id pixiv-search-box-347021
// @version 2.6.0
// @description This is a search option add-on script for pixiv. Enables you to select search mode by radio buttons (legacy feature).
// @description:ja 検索オプションを、以前のようにラジオボタンで選択出来るようにする。
// @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/scripts/265
// @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; \
} \
.ui-search div.container { \
border-radius: 0; \
} \
.global-nav .item-search-box .twitter-typeahead { \
max-width: 356px; \
} \
#suggest-input { \
width: 100%; \
} \
\
/*------------------------------------ \
送信ボタン \
*/ \
.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 {number} [timeoutSinceStopParsingDocument=0] - DOM構築完了後に監視を続けるミリ秒数。
* @version 2014-11-25
* @global
*/
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) {
for (var mutation of mutations) {
var target = mutation.target;
if (target.nodeType === Node.ELEMENT_NODE && isTargetParent(target)) {
// 子が追加された節が要素節で、かつその節についてisTargetParentが真を返せば
for (var addedNode of mutation.addedNodes) {
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();
}
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 (typeof URLSearchParams === 'undefined') {
/** @namespace URL */
/**
* @param {string} input
* @returns {Array.<Array.<string>>} List of name-value pairs where both name and value hold a string.
* @see [application/x-www-form-urlencoded – URL Standard]{@link https://url.spec.whatwg.org/#concept-urlencoded-string-parser}
* @memberof URL
* @function
* @private
*/
var parseXWWWFormUrlencoded = function (input) {
var output = [];
for (var bytes of input.split('&')) {
if (bytes !== '') {
bytes = bytes.replace(/\+/g, ' ');
var index = bytes.indexOf('=');
var name, value;
if (index !== -1) {
name = bytes.slice(0, index);
value = bytes.slice(index + 1);
} else {
name = bytes;
value = '';
}
output.push([decodeURIComponent(name), decodeURIComponent(value)]);
}
}
return output;
};
/**
* @param {string} input - A byte sequence.
* @returns {string}
* @see [application/x-www-form-urlencoded – URL Standard]{@link https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer}
* @memberof URL
* @function
* @private
*/
var serializeXWWWFormUrlencodedByte = function (input) {
return encodeURIComponent(input).replace(/%20/g, '+').replace(/[!~'()]+/g, escape);
};
/**
* @param {Array.<Array.string>} pairs - List of name-value pairs pairs.
* @returns {string}
* @see [application/x-www-form-urlencoded – URL Standard]{@link https://url.spec.whatwg.org/#concept-urlencoded-serializer}
* @memberof URL
* @function
* @private
*/
var serializeXWWWFormUrlencodedString = function (pairs) {
return pairs.map(function (pair) {
return serializeXWWWFormUrlencodedByte(pair[0]) + '=' + serializeXWWWFormUrlencodedByte(pair[1]);
}).join('&');
};
var _URLSearchParams_list = new WeakMap();
var _URLSearchParams_urlObjects = new WeakMap();
/**
* A URLSearchParams object has an associated list of name-value pairs, which is initially empty.
* @param {(string|URLSearchParams)} [init=""]
* @see [URLSearchParams Interface – URL Standard]{@link https://url.spec.whatwg.org/#interface-urlsearchparams}
* @version polyfill-2015-07-30
* @license CC-BY-4.0
* @constructor URLSearchParams
*/
Object.defineProperty(window, 'URLSearchParams', {
writable: true,
enumerable: false,
configurable: true,
value: function (init) {
if (init === undefined) {
init = '';
} else if (!(init instanceof URLSearchParams) && typeof init !== 'string') {
init = String(init);
}
/**
* A URLSearchParams object has an associated list of name-value pairs, which is initially empty.
* @type {Array.<Array.<string, string>>}
* @private
* @memberof URLSearchParams#
*/
var list = [];
if (init instanceof URLSearchParams) {
for (var pair of _URLSearchParams_list.get(init)) {
list.push(pair[0], pair[1]);
}
} else if (init !== '') {
list = parseXWWWFormUrlencoded(init);
}
_URLSearchParams_list.set(this, list);
/**
* A URLSearchParams object has an associated list of zero or more url objects, which is initially empty.
* @type {Set.<Array.<string, string>>}
* @private
* @member URLSearchParams#urlObjects
*/
_URLSearchParams_urlObjects.set(this, new Set());
}
});
/**
* @see [URLSearchParams Interface – URL Standard]{@link https://url.spec.whatwg.org/#concept-URLSearchParams-update}
* @param {(URL|HTMLAnchorElement|HTMLAreaElement|Location)} [excluded]
* @function
* @private
* @function URLSearchParams#runQueryUpdateSteps
*/
var _URLSearchParams_runQueryUpdateSteps = function (excluded) {
var list = _URLSearchParams_list.get(this);
var search = excluded
? excluded.search
: (list[0] ? '?' + serializeXWWWFormUrlencodedString(list) : '');
for (var urlObject of _URLSearchParams_urlObjects.get(this)) {
if (urlObject !== excluded) {
urlObject.search = search;
}
}
};
Object.defineProperties(URLSearchParams.prototype, /** @lends URLSearchParams# */ {
/**
* 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
* @function
*/
append: {
writable: true,
enumerable: false,
configurable: true,
value: function (name, value) {
if (arguments.length < 2) {
throw new TypeError('Failed to execute \'append\' on \'URLSearchParams\': 2 argument required, but only ' + arguments.length + ' present.');
}
_URLSearchParams_list.get(this).push([String(name), String(value)]);
_URLSearchParams_runQueryUpdateSteps.call(this);
}
},
/**
* Remove all name-value pairs whose name is name.
* @param {string} name
* @function
*/
'delete': {
writable: true,
enumerable: false,
configurable: true,
value: function (name) {
if (arguments.length < 1) {
throw new TypeError('Failed to execute \'delete\' on \'URLSearchParams\': 1 argument required, but only ' + arguments.length + ' present.');
}
var list = _URLSearchParams_list.get(this);
for (var i = 0, l = list.length; i < l; i++) {
if (list[i][0] === name) {
list.splice(i, 1);
i--;
l--;
}
}
_URLSearchParams_runQueryUpdateSteps.call(this);
}
},
/**
* Return the value of the first name-value pair whose name is name, and null if there is no such pair.
* @param {string} name
* @returns {?string}
* @function
*/
get: {
writable: true,
enumerable: false,
configurable: true,
value: function (name) {
if (arguments.length < 1) {
throw new TypeError('Failed to execute \'get\' on \'URLSearchParams\': 1 argument required, but only ' + arguments.length + ' present.');
}
for (var pair of _URLSearchParams_list.get(this)) {
if (pair[0] === name) {
return pair[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
* @returns {string[]}
* @function
*/
getAll: {
writable: true,
enumerable: false,
configurable: true,
value: function (name) {
if (arguments.length < 1) {
throw new TypeError('Failed to execute \'getAll\' on \'URLSearchParams\': 1 argument required, but only ' + arguments.length + ' present.');
}
var values = [];
for (var pair of _URLSearchParams_list.get(this)) {
if (pair[0] === name) {
values.push(pair[1]);
}
}
return values;
}
},
/**
* 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
* @function
*/
set: {
writable: true,
enumerable: false,
configurable: true,
value: function (name, value) {
if (arguments.length < 2) {
throw new TypeError('Failed to execute \'set\' on \'URLSearchParams\': 2 argument required, but only ' + arguments.length + ' present.');
}
var list = _URLSearchParams_list.get(this);
var flag;
for (var i = 0, l = list.length; i < l; i++) {
if (list[i][0] === name) {
if (flag) {
list.splice(i, 1);
i--;
l--;
} else {
list[i][1] = String(value);
flag = true;
}
}
}
if (!flag) {
list.push([String(name), String(value)]);
}
_URLSearchParams_runQueryUpdateSteps.call(this);
}
},
/**
* Return true if there is a name-value pair whose name is name, and false otherwise.
* @param {string} name
* @returns {boolean}
* @function
*/
has: {
writable: true,
enumerable: false,
configurable: true,
value: function (name) {
if (arguments.length < 1) {
throw new TypeError('Failed to execute \'has\' on \'URLSearchParams\': 1 argument required, but only ' + arguments.length + ' present.');
}
for (var pair of _URLSearchParams_list.get(this)) {
if (pair[0] === name) {
return true;
}
}
return false;
}
},
/**
* Return the serialization of the URLSearchParams object's associated list of name-value pairs.
* @returns {string}
* @function
*/
toString: {
writable: true,
enumerable: false,
configurable: true,
value: function () {
return serializeXWWWFormUrlencodedString(_URLSearchParams_list.get(this));
}
},
/**
* @returns {Iterator.<Array.<string, string>>}
* @function
*/
entries: {
writable: true,
enumerable: false,
configurable: true,
value: function* () {
for (var pair of _URLSearchParams_list.get(this)) {
yield [pair[0], pair[1]];
}
}
},
/**
* @returns {Iterator.<string>}
* @function
*/
keys: {
writable: true,
enumerable: false,
configurable: true,
value: function* () {
for (var pair of _URLSearchParams_list.get(this)) {
yield pair[0];
}
}
},
/**
* @returns {Iterator.<string>}
* @function
*/
values: {
writable: true,
enumerable: false,
configurable: true,
value: function* () {
for (var pair of _URLSearchParams_list.get(this)) {
yield pair[1];
}
}
},
});
/**
* The value pairs to iterate over are the list name-value pairs with the key being the name and the value the value.
* @returns {Iterator.<Array.<string, string>>}
* @function URLSearchParams#@@iterator
*/
Object.defineProperty(URLSearchParams.prototype, Symbol.iterator, {
writable: true,
enumerable: false,
configurable: true,
value: function* () {
for (var pair of _URLSearchParams_list.get(this)) {
yield [pair[0], pair[1]];
}
}
});
/** @namespace URLUtils */
var _URLUtils_queryObject = new WeakMap();
/**
* @member {URLSearchParams} URLUtilsSearchParams#searchParams
*/
for (var interfaceObject of [URL, HTMLAnchorElement, HTMLAreaElement]) {
Object.defineProperty(interfaceObject.prototype, 'searchParams', {
enumerable: false,
configurable: true,
get: function () {
var queryObject = _URLUtils_queryObject.get(this);
if (!queryObject) {
// If query object is null,
// set query object to a new URLSearchParams object using query,
queryObject = new URLSearchParams(this.search.replace('?', ''));
_URLUtils_queryObject.set(this, queryObject);
// and then append the context object to query object’s list of url objects.
_URLSearchParams_urlObjects.get(queryObject).add(this);
}
return queryObject;
},
set: function (object) {
if (!(object instanceof Object)) {
throw new TypeError('Value being assigned to ' + Object.prototype.toString.call(this).match(/ (.+)\]/)[1] + '.searchParams is not an object.');
} else if (!(object instanceof URLSearchParams)) {
throw new TypeError('Value being assigned to ' + Object.prototype.toString.call(this).match(/ (.+)\]/)[1] + '.searchParams does not implement interface URLSearchParams.');
}
var queryObject = _URLUtils_queryObject.get(this);
// Remove the context object from query object’s list of url objects.
if (queryObject) {
_URLSearchParams_urlObjects.get(queryObject).delete(this);
}
// Append the context object to object’s list of url objects.
_URLSearchParams_urlObjects.get(object).add(this);
// Set query object to object.
_URLUtils_queryObject.set(this, object);
}
});
}
/**
* @private
* @function URLUtils#updateSearchParams
*/
var _URLUtils_updateSearchParams = function () {
var searchParams = this.searchParams;
var search = this.search;
_URLSearchParams_list.set(searchParams, search ? parseXWWWFormUrlencoded(search.replace('?', '')) : []);
_URLSearchParams_runQueryUpdateSteps.call(searchParams, this);
};
var _pushState = History.prototype.pushState;
History.prototype.pushState = function () {
_pushState.apply(this, arguments);
_URLUtils_updateSearchParams.call(window.location);
};
var _replaceState = History.prototype.replaceState;
History.prototype.replaceState = function () {
_replaceState.apply(this, arguments);
_URLUtils_updateSearchParams.call(window.location);
};
window.addEventListener('popstate', function (event) {
_URLUtils_updateSearchParams.call(window.location);
});
new MutationObserver(function (mutations) {
for (var record of mutations) {
var target = record.target;
var name = target.localName;
if (name === 'a' || name === 'area') {
_URLUtils_updateSearchParams.call(target);
}
}
}).observe(document, {
attributeFilter: ['href'],
subtree: true,
});
}
}
})();