<!DOCTYPE html>
<title>?</title>
<meta charset="utf-8">
<style>
li label { color: green; font-weight: bold; padding-right: 1ex;}
</style>
<body>
<div>
<label>KeyWord:</label>
<input type="search" autofocus>
<em>space で区切ることも可能</em>
<ul id="list"></ul>
</div>
<script>
{
class DelayWork {
constructor (callBackFunc, wait = 500) {
this.callBackFunc = callBackFunc;
this.wait = wait;
this.timerID = null;
}
start (...arg) {
if (! this.timerID) {
let cbfunc = () => {
this.timerID = null;
this.callBackFunc (...arg);
};
this.timerID = setTimeout (cbfunc, this.wait);
}
return this;
}
stop () {
if (this.timerID)
clearTimeout (this.timerID);
this.timerID = null;
return this;
}
}
class DelayHandler {
constructor (handler, wait = 300) {
let cbFunc;
switch (Object.prototype.toString.call (handler)) {
case '[object Object]' :
if ('handleEvent' in handler)
if ('function' === typeof handler.handleEvent)
cbFunc = handler.handleEvent.bind (handler);
break;
case '[object Function]' :
cbFunc = handler; break;
default:
throw new Error ('Not handleEvent'); break;
}
this.handler = new DelayWork (cbFunc, this.wait);
this.wait = wait;
}
handleEvent (event) {
this.handler.stop ().start (event);
}
}
const
Article_DEF_OPTION = { };
class Article {
constructor (title = '', key = title, text = '', date = new Date, option = { }) {
if (1 > title.length)
arguments.length;
this.title = title;
this.text = text;
this.key = key;
this.date = date;
this.option = Object.assign ({ }, Article_DEF_OPTION, option);
}
}
const
Book_DEF_OPTION = { };
class Book {
constructor (book = [ ], option = { }) {
this.book = book;
this.option = Object.assign ({ }, Book_DEF_OPTION, option);
}
append (...args) {
this.book.push (new Article (...args));
return this;
}
load (ary) {
ary.forEach (args => this.append (...args));
return this;
}
}
const
ExBook_DEF_OPTION = { },
REG_NORMALIZATION = /[-\/\\^$*+?.()|\[\]{}]/g,
REG_SPLITER = /\s+/g,
REG_TRIM = /(^\s+|\s+$|\s+(?=\s))/g,
REG_KEY = (str) => {
let [a, ...bc] = str.replace(REG_NORMALIZATION, '\\$&').split (REG_SPLITER);
return new RegExp (a + bc.map (s => `(?=.*${s})`).join (''), 'i');
};
class ExBook extends Book {
constructor (book = [ ], display, option = { }) {
super (book, Object.assign ({ }, ExBook_DEF_OPTION, option));
this.display = display;
this.found = [ ];
this.key = '';
}
find (arg = '') {
let
key = arg.replace (REG_TRIM, ''),
len = key.length;
if (len) {
let cnt = this.key.length;
if (! cnt || len < cnt)
this.found = this.book.slice ();
if (key !== this.key) {
let reg = REG_KEY (key);
this.found = this.found.filter (rec => reg.test (rec.key));
this.key = key;
this.display.write (this.found.slice());
}
}
else {
this.display.cls ();
this.key = '';
}
return this;
}
handleEvent (event) {
this.find (event.target.value);
}
}
const
Display_DEF_OPTION = {
disp_row : 1,
disp_wait : 30,
disp_max : 30
},
createElement = function (n) { return this.createElement (n) },
createRow = (function (doc) {
let [li, label, span] = ['li', 'label', 'span'].map (createElement, doc)
li.appendChild (label);
li.appendChild (span);
return function (title, text) {
label.textContent = title;
span.textContent = text;
return li.cloneNode (true);
};
})(document);
class Display {
constructor (target, option = { }) {
option = Object.assign ({ }, Display_DEF_OPTION, option)
this.target = target;
this.option = option;
this.loop = new DelayWork (this.outByBit.bind (this), option.disp_wait);
}
write (rows = [ ]) {
this.cls ();
this.outByBit (rows.splice (0, this.option.disp_max));
return this;
}
outByBit (rows) {
let
fgm = this.target.ownerDocument.createDocumentFragment (),
part = rows.splice (0, this.option.disp_row);
this.target.appendChild (part.reduce ((a,b)=>{
a.appendChild (createRow (b.title + ":", b.text));
return a;
}, fgm));
if (rows.length)
this.loop.start (rows);
return this;
}
cls () {
this.loop.stop ();
for (let p = this.target, e; e = p.firstChild; )
e.remove ();
return this;
}
}
this.Article = Article;
this.Book = ExBook;
this.Display = Display;
this.DelayHandler = DelayHandler;
}
const
notes = `
[ Array.prototype.push | array push ] 配列の最後に要素を追加する
[ Array.prototype.pop | array pop ] 配列の最後から要素を削除し、その要素を返す
[Array.prototype.map | array map] 配列から生成した配列を返す
[ array.prototype.slice | array slice ] 配列から指定した要素を削除する
`;
let reg, ary, words = [ ];
{
let text = '(.+?)';
let spc = '\\s*';
let text2 = '([\\s\\S]+?)';
let title = '\\['+ spc + text + '(?:' + spc + '\\|' + spc + text + ')?'+ spc + '\\]';
let note = spc + text2 + '(?=\\s*\\[|\\s*$)';
reg = new RegExp (title + note , 'gi');
}
while (ary = reg.exec (notes)) {
let [, ...arg] = ary;
console.log(arg);
words.push (new Article (...arg));
}
let dic = new Book (words, new Display (document.getElementById ('list')));
document.querySelector ('input[type="search"]')
.addEventListener ('input', new DelayHandler (dic), false);
</script>