js(async () => {
const projectName = 'programming-notes';
const pageTitle = '補完windowとあいまい検索を組み合わせるテスト';
const promises = [
import(`/api/code/${projectName}/scrapbox-suggest-container/test-dom.js`),
//import(`/api/code/${projectName}/scrapbox-suggest-container/test-dark-theme.js`),
import(`/api/code/${projectName}/scrapbox-suggest-container/script.js`),
];
const promise = import(`/api/code/${projectName}/${pageTitle}/test1-project-list.js`);
const worker = new Worker(`/api/code/${projectName}/${pageTitle}/test1-worker.js`);
worker.postMessage({type: 'fetch', projects: (await promise).projects});
const [{editor, cursor},] = await Promise.all(promises);
// 入力補完windowを作る
const suggestBox = document.createElement('suggest-container');
editor.append(suggestBox);
// とりあえず、cursorに追随するだけにする
const observer = new MutationObserver(() =>{
suggestBox.show({
top: parseInt(cursor.style.top) + 14,
left: parseInt(cursor.style.left),
});
});
observer.observe(cursor, {attributes: true});
// あいまい検索して、候補を入力補完windowに追加する
window.search = (word, {limit = 30, timeout = 10000,} = {}) => {
// 時間がかかるようであればLoading表示をする
const timer = setTimeout(() => {
const image = /paper-dark-dark|default-dark/
.test(document.head.parentElement.dataset.projectTheme) ?
'https://img.icons8.com/ios/180/FFFFFF/loading.png' :
'https://img.icons8.com/ios/180/loading.png';
suggestBox.pushFirst({text: 'Loading...', image,});
}, 1000);
worker.postMessage({type: 'search', word, limit, timeout});
worker.addEventListener('message', ({data: {links}}) => {
clearTimeout(timer);
suggestBox.clear();
suggestBox.push(...links.flat().map(link => {
return {
text: link,
link: `https://scrapbox.io${link}`,
onClick: () => window.open(`https://scrapbox.io${link}`),
};
}));
}, {once: true});
};
})();
test1-project-list.jsexport const projects = [
'hub',
'villagepump',
'motoso',
'shokai',
'nishio',
/*'masui',
'rakusai',
'yuiseki',
'june29',
'ucdktr2016',
'rashitamemo',
'thinkandcreateteck',
'customize',
'scrapboxlab',
'scrasobox',
'foldrr',
'scrapbox-drinkup',
'public-mrsekut',
'mrsekut-p',
'marshmallow-rm',
'wkpmm',
'sushitecture',
'nwtgck',
'dojineko',
'kadoyau',
'inteltank',
'sta',
'kn1cht',
'miyamonz',
'rmaruon',
'MISONLN41',
'yuta0801',
'choiyakiBox',
'choiyaki-hondana',
'spud-oimo',
'keroxp',
'aioilight',*/
];
test1-worker.jsconst pageTitle = '補完windowとあいまい検索を組み合わせるテスト';
self.importScripts('/api/code/programming-notes/WebWorker用asearch/script.js');
// 検索候補
const list = [];
self.addEventListener('message', message => {
switch (message.data.type) {
case 'search':
search(message.data);
break;
case 'fetch':
fetch_(message.data.projects);
break;
}
});
async function search({word, limit, timeout}) {
//_log(`start searching for ${word}...: limit = ${limit}`);
const result = fuzzySearch({
query: word.split('/').join(' '),
source: list,
limit, timeout,
});
//_log('finished: %o', result);
self.postMessage({links: result,});
}
async function fetch_(projects) {
_log('Loading links from %o', projects);
const result = (await Promise.all(projects
.map(project => fetchExternalLinks(project))
)).flat();
_log(`Finish loading ${result.length} links from %o`, projects);
list.push(...result);
}
async function fetchExternalLinks(project) {
let followingId = null;
let temp = [];
_log(`Start loading links from ${project}...`);
do {
_log(`Loading links from ${project}: followingId = ${followingId}`);
const json = await (!followingId ?
fetch(`/api/pages/${project}/search/titles`) :
fetch(`/api/pages/${project}/search/titles?followingId=${followingId}`)
).then(res => {
followingId = res.headers.get('X-Following-Id');
return res.json();
});
temp.push(...json.flatMap(page => [...page.links, page.title]).map(link => `/${project}/${link}`));
} while(followingId);
const links = [...new Set(temp)]; // 重複を取り除く
_log(`Loaded ${links.length} links from /${project}`);
return links;
}
// debug用
function _log(msg, ...objects) {
console.log(`[search-worker @${pageTitle}/test1-worker.js] ${msg}`, ...objects);
}