--- /dev/null
+<?php
+// PukiWiki - Yet another WikiWikiWeb clone.
+// search2.inc.php
+// Copyright 2017 PukiWiki Development Team
+// License: GPL v2 or (at your option) any later version
+//
+// Search2 plugin - Show detail result using JavaScript
+
+define('PLUGIN_SEARCH2_MAX_LENGTH', 80);
+define('PLUGIN_SEARCH2_MAX_BASE', 16); // #search(1,2,3,...,15,16)
+
+// Show a search box on a page
+function plugin_search2_convert()
+{
+ $args = func_get_args();
+ return plugin_search_search_form('', '', $args);
+}
+
+function plugin_search2_action()
+{
+ global $vars, $_title_search, $_title_result;
+
+ $action = isset($vars['action']) ? $vars['action'] : '';
+ $base = isset($vars['base']) ? $vars['base'] : '';
+ $bases = array();
+ if ($base !== '') {
+ $bases[] = $base;
+ }
+ if ($action === '') {
+ $q = isset($vars['q']) ? $vars['q'] : '';
+ if ($q === '') {
+ return array('msg' => $_title_search,
+ 'body' => plugin_search2_search_form($q, '', $bases));
+ } else {
+ $msg = str_replace('$1', htmlsc($q), $_title_result);
+ return array('msg' => $msg,
+ 'body' => plugin_search2_search_form($q, '', $bases));
+ }
+ } else if ($action === 'query') {
+ $text = isset($vars['q']) ? $vars['q'] : '';
+ header('Content-Type: application/json; charset=UTF-8');
+ plugin_search2_do_search($text, $base);
+ exit;
+ }
+}
+
+function plugin_search2_do_search($query_text, $base)
+{
+ global $whatsnew, $non_list, $search_non_list;
+ global $_msg_andresult, $_msg_orresult, $_msg_notfoundresult;
+ global $search_auth;
+
+ $retval = array();
+
+ $b_type_and = true; // AND:TRUE OR:FALSE
+ $key_candidates = preg_split('/\s+/', $query_text, -1, PREG_SPLIT_NO_EMPTY);
+ for ($i = count($key_candidates) - 1; $i >= 0; $i--) {
+ if ($key_candidates[$i] === 'OR') {
+ $b_type_and = false;
+ unset($key_candidates[$i]);
+ }
+ }
+ $key_candidates = array_merge($key_candidates);
+ $keys = get_search_words($key_candidates);
+ foreach ($keys as $key=>$value)
+ $keys[$key] = '/' . $value . '/S';
+
+ $pages = get_existpages();
+
+ // Avoid
+ if ($base != '') {
+ $pages = preg_grep('/^' . preg_quote($base, '/') . '/S', $pages);
+ }
+ if (! $search_non_list) {
+ $pages = array_diff($pages, preg_grep('/' . $non_list . '/S', $pages));
+ }
+ natsort($pages);
+ $pages = array_flip($pages);
+ unset($pages[$whatsnew]);
+ $page_names = array_keys($pages);
+
+ $found_pages = array();
+ $readable_page_index = -1;
+ $scan_page_index = -1;
+ $last_read_page_name = null;
+ foreach ($page_names as $page) {
+ $b_match = FALSE;
+ $pagename_only = false;
+ $scan_page_index++;
+ if (! is_page_readable($page)) {
+ if ($search_auth) {
+ // $search_auth - 1: User can know page names that contain search text if the page is readable
+ continue;
+ }
+ // $search_auth - 0: All users can know page names that conntain search text
+ $pagename_only = true;
+ }
+ $readable_page_index++;
+ // Search for page name and contents
+ $body = get_source($page, TRUE, TRUE, TRUE);
+ $target = $page . "\n" . remove_author_header($body);
+ foreach ($keys as $key) {
+ $b_match = preg_match($key, $target);
+ if ($b_type_and xor $b_match) break; // OR
+ }
+ if ($b_match) {
+ // Found!
+ $filemtime = null;
+ $author_info = get_author_info($body);
+ if ($author_info === false || $pagename_only) {
+ $updated_at = get_date_atom(filemtime(get_filename($page)));
+ }
+ if ($pagename_only) {
+ // The user cannot read this page body
+ $found_pages[] = array('name' => (string)$page,
+ 'url' => get_page_uri($page), 'updated_at' => $updated_at,
+ 'body' => '', 'pagename_only' => 1);
+ } else {
+ $found_pages[] = array('name' => (string)$page,
+ 'url' => get_page_uri($page), 'updated_at' => $updated_at,
+ 'body' => (string)$body);
+ }
+ }
+ $last_read_page_name = $page;
+ }
+ $message = str_replace('$1', htmlsc($query_text), str_replace('$2', count($found_pages),
+ str_replace('$3', count($page_names), $b_type_and ? $_msg_andresult : $_msg_orresult)));
+ $search_done = (boolean)($scan_page_index + 1 === count($page_names));
+ $result_obj = array(
+ 'message' => $message,
+ 'q' => $query_text,
+ 'read_page_count' => $readable_page_index + 1,
+ 'scan_page_count' => $scan_page_index + 1,
+ 'page_count' => count($page_names),
+ 'last_read_page_name' => $last_read_page_name,
+ 'search_done' => $search_done,
+ 'results' => $found_pages);
+ $obj = $result_obj;
+ if (!defined('PKWK_UTF8_ENABLE')) {
+ if (SOURCE_ENCODING === 'EUC-JP') {
+ mb_convert_variables('UTF-8', 'CP51932', $obj);
+ } else {
+ mb_convert_variables('UTF-8', SOURCE_ENCODING, $obj);
+ }
+ }
+ print(json_encode($obj, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
+}
+
+function plugin_search2_search_form($s_word = '', $type = '', $bases = array())
+{
+ global $_btn_search;
+ global $_search_pages, $_search_all;
+ global $_msg_andresult, $_msg_orresult, $_msg_notfoundresult;
+ global $_search_detail, $_search_searching;
+ global $_msg_unsupported_webbrowser, $_msg_use_alternative_link;
+
+ $script = get_base_uri();
+ $h_search_text = htmlsc($s_word);
+
+ $base_option = '';
+ if (!empty($bases)) {
+ $base_msg = '';
+ $_num = 0;
+ $check = ' checked';
+ foreach($bases as $base) {
+ ++$_num;
+ if (PLUGIN_SEARCH2_MAX_BASE < $_num) break;
+ $s_base = htmlsc($base);
+ $base_str = '<strong>' . $s_base . '</strong>';
+ $base_label = str_replace('$1', $base_str, $_search_pages);
+ $base_msg .=<<<EOD
+ <div>
+ <label>
+ <input type="radio" name="base" value="$s_base" $check> $base_label
+ </label>
+ </div>
+EOD;
+ $check = '';
+ }
+ $base_msg .=<<<EOD
+<label><input type="radio" name="base" value=""> $_search_all</label>
+EOD;
+ $base_option = '<div class="small">' . $base_msg . '</div>';
+ }
+ $_search2_result_notfound = htmlsc($_msg_notfoundresult);
+ $_search2_result_found = htmlsc($_msg_andresult);
+ $_search2_search_wait_milliseconds = PLUGIN_SEARCH2_SEARCH_WAIT_MILLISECONDS;
+ $result_page_panel =<<<EOD
+<div id="_plugin_search2_search_status"></div>
+<div id="_plugin_search2_message"></div>
+<input type="checkbox" id="_plugin_search2_detail" checked><label for="_plugin_search2_detail">$_search_detail</label>
+<input type="hidden" id="_plugin_search2_msg_searching" value="$_search_searching">
+<input type="hidden" id="_plugin_search2_msg_result_notfound" value="$_search2_result_notfound">
+<input type="hidden" id="_plugin_search2_msg_result_found" value="$_search2_result_found">
+<input type="hidden" id="_search2_search_wait_milliseconds" value="$_search2_search_wait_milliseconds">
+EOD;
+ if ($h_search_text == '') {
+ $result_page_panel = '';
+ }
+
+ $plain_search_link = '<a href="' . $script . '?cmd=search' . '">' . htmlsc($_btn_search) . '</a>';
+ $alt_msg = str_replace('$1', $plain_search_link, $_msg_use_alternative_link);
+ return <<<EOD
+<noscript>
+ <p>$_msg_unsupported_webbrowser $alt_msg</p>
+</noscript>
+<p class="_plugin_search2_nosupport_message" style="display:none;">
+ $_msg_unsupported_webbrowser $alt_msg
+</p>
+<form action="$script" method="GET" class="_plugin_search2_form">
+ <div>
+ <input type="hidden" name="cmd" value="search2">
+ <input type="search" name="q" value="$h_search_text" size="30">
+ <input type="submit" value="$_btn_search">
+ </div>
+$base_option
+</form>
+$result_page_panel
+<ul id="result-list">
+</ul>
+EOD;
+}
--- /dev/null
+// PukiWiki - Yet another WikiWikiWeb clone.
+// search2.js
+// Copyright
+// 2017 PukiWiki Development Team
+// License: GPL v2 or (at your option) any later version
+//
+// PukiWiki search2 pluign - JavaScript client script
+window.addEventListener && window.addEventListener('DOMContentLoaded', function() {
+ function enableSearch2() {
+ var aroundLines = 2;
+ var maxResultLines = 20;
+ var minBlockLines = 5;
+ var minSearchWaitMilliseconds = 100;
+ var kanaMap = null;
+ function escapeHTML (s) {
+ if(typeof s !== 'string') {
+ s = '' + s;
+ }
+ return s.replace(/[&"<>]/g, function(m) {
+ return {
+ '&': '&',
+ '"': '"',
+ '<': '<',
+ '>': '>'
+ }[m];
+ });
+ }
+ function doSearch(searchText, session, startIndex) {
+ var url = './?cmd=search2&action=query';
+ var props = getSiteProps();
+ url += '&encode_hint=' + encodeURIComponent('\u3077');
+ if (searchText) {
+ url += '&q=' + encodeURIComponent(searchText);
+ }
+ if (session.base) {
+ url += '&base=' + encodeURIComponent(session.base);
+ }
+ url += '&start=' + startIndex;
+ fetch (url
+ ).then(function(response){
+ if (response.ok) {
+ return response.json();
+ } else {
+ throw new Error(response.status + ': ' +
+ + response.statusText + ' on ' + url);
+ }
+ }).then(function(obj) {
+ showResult(obj, session, searchText);
+ })['catch'](function(err){
+ console.log(err);
+ console.log('Error! Please check JavaScript console' + '\n' + JSON.stringify(err) + '|' + err);
+ });
+ }
+ function getMessageTemplate(idText, defaultText) {
+ var messageHolder = document.querySelector('#' + idText);
+ var messageTemplate = (messageHolder && messageHolder.value) || defaultText;
+ return messageTemplate;
+ }
+ function getAuthorInfo(text) {
+
+ }
+ function getPassage(now, dateText) {
+ if (! dateText) {
+ return '';
+ }
+ var units = [{u: 'm', max: 60}, {u: 'h', max: 24}, {u: 'd', max: 1}];
+ var d = new Date();
+ d.setTime(Date.parse(dateText));
+ var t = (now.getTime() - d.getTime()) / (1000 * 60); // minutes
+ var unit = units[0].u, card = units[0].max;
+ for (var i = 0; i < units.length; i++) {
+ unit = units[i].u, card = units[i].max;
+ if (t < card) break;
+ t = t / card;
+ }
+ return '(' + Math.floor(t) + unit + ')';
+ }
+ function removeSearchOperators(searchText) {
+ var sp = searchText.split(/\s+/);
+ if (sp.length <= 1) {
+ return searchText;
+ }
+ var hasOr = false;
+ for (var i = sp.length - 1; i >= 0; i--) {
+ if (sp[i] === 'OR') {
+ hasOr = true;
+ sp.splice(i, 1);
+ }
+ }
+ return sp.join(' ');
+ }
+ function showResult(obj, session, searchText) {
+ var searchRegex = textToRegex(removeSearchOperators(searchText));
+ var ul = document.querySelector('#result-list');
+ if (!ul) return;
+ ul.innerHTML = '';
+ if (! session.scan_page_count) session.scan_page_count = 0;
+ if (! session.read_page_count) session.read_page_count = 0;
+ if (! session.hit_page_count) session.hit_page_count = 0;
+ session.scan_page_count += obj.scan_page_count;
+ session.read_page_count += obj.read_page_count;
+ session.hit_page_count += obj.results.length;
+ session.page_count = obj.page_count;
+
+ var msg = obj.message;
+ var notFoundMessageTemplate = getMessageTemplate('_plugin_search2_msg_result_notfound',
+ 'No page which contains $1 has been found.');
+ var foundMessageTemplate = getMessageTemplate('_plugin_search2_msg_result_found',
+ 'In the page <strong>$2</strong>, <strong>$3</strong> pages that contain all the terms $1 were found.');
+ var searchTextDecorated = findAndDecorateText(searchText, searchRegex);
+ if (searchTextDecorated === null) searchTextDecorated = escapeHTML(searchText);
+ var messageTemplate = foundMessageTemplate;
+ if (session.hit_page_count === 0) {
+ messageTemplate = notFoundMessageTemplate;
+ }
+ msg = messageTemplate.replace(/\$1|\$2|\$3/g, function(m){
+ return {
+ '$1': searchTextDecorated,
+ '$2': session.hit_page_count,
+ '$3': session.read_page_count
+ }[m];
+ });
+ document.querySelector('#_plugin_search2_message').innerHTML = msg;
+
+ setSearchStatus('');
+ var results = obj.results;
+ var now = new Date();
+ results.forEach(function(val, index) {
+ var fragment = document.createDocumentFragment();
+ var li = document.createElement('li');
+ var hash = '#q=' + encodeSearchTextForHash(searchText);
+ var href = val.url + hash;
+ var decoratedName = findAndDecorateText(val.name, searchRegex);
+ if (! decoratedName) {
+ decoratedName = escapeHTML(val.name);
+ }
+ var author = getAuthorHeader(val.body);
+ var updatedAt = '';
+ if (author) {
+ updatedAt = getUpdateTimeFromAuthorInfo(author);
+ } else {
+ updatedAt = val.updated_at;
+ }
+ var liHtml = '<a href="' + escapeHTML(href) + '">' + decoratedName + '</a> ' +
+ getPassage(now, updatedAt);
+ li.innerHTML = liHtml;
+ var a = li.querySelector('a');
+ if (a && a.hash) {
+ if (a.hash !== hash) {
+ // Some browser execute encodeHTML(hash) automatically. Support them.
+ a.href = val.url + '#encq=' + encodeSearchTextForHash(searchText);
+ }
+ }
+ fragment.appendChild(li);
+ var div = document.createElement('div');
+ div.classList.add('search-result-detail');
+ var head = document.createElement('div');
+ head.classList.add('search-result-page-summary');
+ head.innerHTML = escapeHTML(getBodySummary(val.body));
+ div.appendChild(head);
+ var summary = getSummary(val.body, searchRegex);
+ for (var i = 0; i < summary.length; i++) {
+ var pre = document.createElement('pre');
+ pre.innerHTML = summary[i].lines.join('\n');
+ div.appendChild(pre);
+ }
+ fragment.appendChild(div);
+ ul.appendChild(fragment);
+ });
+ }
+ function prepareKanaMap() {
+ if (kanaMap !== null) return;
+ if (!String.prototype.normalize) {
+ kanaMap = {};
+ return;
+ }
+ var dakuten = '\uFF9E';
+ var maru = '\uFF9F';
+ var map = {};
+ for (var c = 0xFF61; c <=0xFF9F; c++) {
+ var han = String.fromCharCode(c);
+ var zen = han.normalize('NFKC');
+ map[zen] = han;
+ var hanDaku = han + dakuten;
+ var zenDaku = hanDaku.normalize('NFKC');
+ if (zenDaku.length === 1) { // +Handaku-ten OK
+ map[zenDaku] = hanDaku;
+ }
+ var hanMaru = han + maru;
+ var zenMaru = hanMaru.normalize('NFKC');
+ if (zenMaru.length === 1) { // +Maru OK
+ map[zenMaru] = hanMaru;
+ }
+ }
+ kanaMap = map;
+ }
+ function textToRegex(searchText) {
+ if (!searchText) return null;
+ var regEscape = /[\\^$.*+?()[\]{}|]/g;
+ // 1:Symbol 2:Katakana 3:Hiragana
+ var regRep = /([\\^$.*+?()[\]{}|])|([\u30a1-\u30f6])|([\u3041-\u3096])/g;
+ var s1 = searchText.replace(/^\s+|\s+$/g, '');
+ var sp = s1.split(/\s+/);
+ var rText = '';
+ prepareKanaMap();
+ for (var i = 0; i < sp.length; i++) {
+ if (rText !== '') {
+ rText += '|'
+ }
+ var s = sp[i];
+ if (s.normalize) {
+ s = s.normalize('NFKC');
+ }
+ var s2 = s.replace(regRep, function(m, m1, m2, m3){
+ if (m1) {
+ // Symbol - escape with prior backslach
+ return '\\' + m1;
+ } else if (m2) {
+ // Katakana
+ var r = '(?:' + String.fromCharCode(m2.charCodeAt(0) - 0x60) +
+ '|' + m2;
+ if (kanaMap[m2]) {
+ r += '|' + kanaMap[m2];
+ }
+ r += ')';
+ return r;
+ } else if (m3) {
+ // Hiragana
+ var katakana = String.fromCharCode(m3.charCodeAt(0) + 0x60);
+ var r = '(?:' + m3 + '|' + katakana;
+ if (kanaMap[katakana]) {
+ r += '|' + kanaMap[katakana];
+ }
+ r += ')';
+ return r;
+ }
+ return m;
+ });
+ rText += '(' + s2 + ')';
+ }
+ return new RegExp(rText, 'ig');
+ }
+ function getAuthorHeader(body) {
+ var start = 0;
+ var pos;
+ while ((pos = body.indexOf('\n', start)) >= 0) {
+ var line = body.substring(start, pos);
+ if (line.match(/^#author\(/, line)) {
+ return line;
+ } else if (line.match(/^#freeze(\W|$)/, line)) {
+ // Found #freeze still in header
+ } else {
+ // other line, #author not found
+ return null;
+ }
+ start = pos + 1;
+ }
+ return null;
+ }
+ function getUpdateTimeFromAuthorInfo(authorInfo) {
+ var m = authorInfo.match(/^#author\("([^;"]+)(;[^;"]+)?/);
+ if (m) {
+ return m[1];
+ }
+ return '';
+ }
+ function getTargetLines(body, searchRegex) {
+ var lines = body.split('\n');
+ var found = [];
+ var foundLines = [];
+ var isInAuthorHeader = true;
+ var lastFoundLineIndex = -1 - aroundLines;
+ var lastAddedLineIndex = lastFoundLineIndex;
+ var blocks = [];
+ var lineCount = 0;
+ for (var index = 0, length = lines.length; index < length; index++) {
+ var line = lines[index];
+ if (isInAuthorHeader) {
+ // '#author line is not search target'
+ if (line.match(/^#author\(/)) {
+ // Remove this line from search target
+ continue;
+ } else if (line.match(/^#freeze(\W|$)/)) {
+ // Still in header
+ } else {
+ // Already in body
+ isInAuthorHeader = false;
+ }
+ }
+ var decorated = findAndDecorateText(line, searchRegex);
+ if (decorated === null) {
+ if (index < lastFoundLineIndex + aroundLines + 1) {
+ foundLines.push('' + (index + 1) + ':\t' + escapeHTML(lines[index]));
+ lineCount++;
+ lastAddedLineIndex = index;
+ }
+ } else {
+ var startIndex = Math.max(Math.max(lastAddedLineIndex + 1, index - aroundLines), 0);
+ if (lastAddedLineIndex + 1 < startIndex) {
+ // Newly found!
+ var block = {
+ startIndex: startIndex,
+ foundLineIndex: index,
+ lines: []
+ };
+ foundLines = block.lines;
+ blocks.push(block);
+ }
+ if (lineCount >= maxResultLines) {
+ foundLines.push('...');
+ return blocks;
+ }
+ for (var i = startIndex; i < index; i++) {
+ foundLines.push('' + (i + 1) + ':\t' + escapeHTML(lines[i]));
+ lineCount++;
+ }
+ foundLines.push('' + (index + 1) + ':\t' + decorated);
+ lineCount++;
+ lastFoundLineIndex = lastAddedLineIndex = index;
+ }
+ }
+ return blocks;
+ }
+ function getSummary(bodyText, searchRegex) {
+ return getTargetLines(bodyText, searchRegex);
+ }
+ function hookSearch2(e) {
+ var form = document.querySelector('form');
+ if (form && form.q) {
+ var q = form.q;
+ if (q.value === '') {
+ q.focus();
+ }
+ }
+ }
+ function getBodySummary(body) {
+ var lines = body.split('\n');
+ var isInAuthorHeader = true;
+ var summary = [];
+ var lineCount = 0;
+ for (var index = 0, length = lines.length; index < length; index++) {
+ var line = lines[index];
+ if (isInAuthorHeader) {
+ // '#author line is not search target'
+ if (line.match(/^#author\(/)) {
+ // Remove this line from search target
+ continue;
+ } else if (line.match(/^#freeze(\W|$)/)) {
+ continue;
+ // Still in header
+ } else {
+ // Already in body
+ isInAuthorHeader = false;
+ }
+ }
+ line = line.replace(/^\s+|\s+$/g, '');
+ if (line.length === 0) continue; // Empty line
+ if (line.match(/^#\w+/)) continue; // Block-type plugin
+ if (line.match(/^\/\//)) continue; // Comment
+ if (line.substr(0, 1) === '*') {
+ line = line.replace(/\s*\[\#\w+\]$/, ''); // Remove anchor
+ }
+ summary.push(line);
+ if (summary.length >= 10) {
+ continue;
+ }
+ }
+ return summary.join(' ').substring(0, 150);
+ }
+ function removeEncodeHint() {
+ // Remove 'encode_hint' if site charset is UTF-8
+ var props = getSiteProps();
+ if (!props.is_utf8) return;
+ var forms = document.querySelectorAll('form');
+ forEach(forms, function(form){
+ if (form.cmd && form.cmd.value === 'search2') {
+ if (form.encode_hint && (typeof form.encode_hint.removeAttribute === 'function')) {
+ form.encode_hint.removeAttribute('name');
+ }
+ }
+ });
+ }
+ function kickFirstSearch() {
+ var form = document.querySelector('._plugin_search2_form');
+ var searchText = form && form.q;
+ if (!searchText) return;
+ if (searchText && searchText.value) {
+ var e = document.querySelector('#_plugin_search2_msg_searching');
+ var msg = e && e.value || 'Searching...';
+ setSearchStatus(msg);
+ var base = '';
+ forEach(form.querySelectorAll('input[name="base"]'), function(radio){
+ if (radio.checked) base = radio.value;
+ });
+ doSearch(searchText.value, {base: base}, 0);
+ }
+ }
+ function setSearchStatus(statusText) {
+ var statusObj = document.querySelector('#_plugin_search2_search_status');
+ if (statusObj) {
+ statusObj.textContent = statusText;
+ }
+ }
+ function forEach(nodeList, func) {
+ if (nodeList.forEach) {
+ nodeList.forEach(func);
+ } else {
+ for (var i = 0, n = nodeList.length; i < n; i++) {
+ func(nodeList[i], i);
+ }
+ }
+ }
+ function replaceSearchWithSearch2() {
+ forEach(document.querySelectorAll('form'), function(f){
+ if (f.action.match(/cmd=search$/)) {
+ f.addEventListener('submit', function(e) {
+ var q = e.target.word.value;
+ var base = '';
+ forEach(f.querySelectorAll('input[name="base"]'), function(radio){
+ if (radio.checked) base = radio.value;
+ });
+ var props = getSiteProps();
+ var loc = document.location;
+ var baseUri = loc.protocol + '//' + loc.host + loc.pathname;
+ if (props.base_uri_pathname) {
+ baseUri = props.base_uri_pathname;
+ }
+ var url = baseUri + '?' +
+ (props.is_utf8 ? '' : 'encode_hint=' +
+ encodeURIComponent('\u3077') + '&') +
+ 'cmd=search2' +
+ '&q=' + encodeSearchText(q) +
+ (base ? '&base=' + encodeURIComponent(base) : '');
+ e.preventDefault();
+ setTimeout(function() {
+ location.href = url;
+ }, 1);
+ return false;
+ });
+ var radios = f.querySelectorAll('input[type="radio"][name="type"]');
+ forEach(radios, function(radio){
+ if (radio.value === 'AND') {
+ radio.addEventListener('click', onAndRadioClick);
+ } else if (radio.value === 'OR') {
+ radio.addEventListener('click', onOrRadioClick);
+ }
+ });
+ function onAndRadioClick(e) {
+ var sp = removeSearchOperators(f.word.value).split(/\s+/);
+ var newText = sp.join(' ');
+ if (f.word.value !== newText) {
+ f.word.value = newText;
+ }
+ }
+ function onOrRadioClick(e) {
+ var sp = removeSearchOperators(f.word.value).split(/\s+/);
+ var newText = sp.join(' OR ');
+ if (f.word.value !== newText) {
+ f.word.value = newText;
+ }
+ }
+ }
+ });
+ }
+ function encodeSearchText(q) {
+ var sp = q.split(/\s+/);
+ for (var i = 0; i < sp.length; i++) {
+ sp[i] = encodeURIComponent(sp[i]);
+ }
+ return sp.join('+');
+ }
+ function encodeSearchTextForHash(q) {
+ var sp = q.split(/\s+/);
+ return sp.join('+');
+ }
+ function findAndDecorateText(text, searchRegex) {
+ var isReplaced = false;
+ var lastIndex = 0;
+ var m;
+ var decorated = '';
+ searchRegex.lastIndex = 0;
+ while ((m = searchRegex.exec(text)) !== null) {
+ isReplaced = true;
+ var pre = text.substring(lastIndex, m.index);
+ decorated += escapeHTML(pre);
+ for (var i = 1; i < m.length; i++) {
+ if (m[i]) {
+ decorated += '<strong class="word' + (i - 1) + '">' + escapeHTML(m[i]) + '</strong>'
+ }
+ }
+ lastIndex = searchRegex.lastIndex;
+ }
+ if (isReplaced) {
+ decorated += escapeHTML(text.substr(lastIndex));
+ return decorated;
+ }
+ return null;
+ }
+ function getSearchTextInLocationHash() {
+ // TODO Cross browser
+ var hash = location.hash;
+ if (!hash) return '';
+ var q = '';
+ if (hash.substr(0, 3) === '#q=') {
+ q = hash.substr(3).replace(/\+/g, ' ');
+ } else if (hash.substr(0, 6) === '#encq=') {
+ q = decodeURIComponent(hash.substr(6).replace(/\+/g, ' '));
+ }
+ return q;
+ }
+ function colorSearchTextInBody() {
+ var searchText = getSearchTextInLocationHash();
+ if (!searchText) return;
+ var searchRegex = textToRegex(removeSearchOperators(searchText));
+ var headReText = '([\\s\\b]|^)';
+ var tailReText = '\\b';
+ var ignoreTags = ['INPUT', 'TEXTAREA', 'BUTTON',
+ 'SCRIPT', 'FRAME', 'IFRAME'];
+ function colorSearchText(element, searchRegex) {
+ var decorated = findAndDecorateText(element.nodeValue, searchRegex);
+ if (decorated) {
+ var span = document.createElement('span');
+ span.innerHTML = decorated;
+ element.parentNode.replaceChild(span, element);
+ }
+ }
+ function walkElement(element) {
+ var e = element.firstChild;
+ while (e) {
+ if (e.nodeType == 3 && e.nodeValue &&
+ e.nodeValue.length >= 2 && /\S/.test(e.nodeValue)) {
+ var next = e.nextSibling;
+ colorSearchText(e, searchRegex);
+ e = next;
+ } else {
+ if (e.nodeType == 1 && ignoreTags.indexOf(e.tagName) == -1) {
+ walkElement(e);
+ }
+ e = e.nextSibling;
+ }
+ }
+ }
+ var target = document.getElementById('body');
+ walkElement(target);
+ }
+ function showNoSupportMessage() {
+ var pList = document.getElementsByClassName('_plugin_search2_nosupport_message');
+ for (var i = 0; i < pList.length; i++) {
+ var p = pList[i];
+ p.style.display = 'block';
+ }
+ }
+ function isEnabledFetchFunctions() {
+ if (window.fetch && document.querySelector && window.JSON) {
+ return true;
+ }
+ return false;
+ }
+ function isEnableServerFunctions() {
+ var props = getSiteProps();
+ if (props.json_enabled) return true;
+ return false;
+ }
+ function getSiteProps() {
+ var empty = {};
+ var propsDiv = document.getElementById('pukiwiki-site-properties');
+ if (!propsDiv) return empty;
+ var jsonE = propsDiv.querySelector('div[data-key="site-props"]');
+ if (!jsonE) return emptry;
+ var props = JSON.parse(jsonE.getAttribute('data-value'));
+ return props || empty;
+ }
+ colorSearchTextInBody();
+ if (! isEnabledFetchFunctions()) {
+ showNoSupportMessage();
+ return;
+ }
+ if (! isEnableServerFunctions()) return;
+ replaceSearchWithSearch2();
+ hookSearch2();
+ removeEncodeHint();
+ kickFirstSearch();
+ }
+ enableSearch2();
+});