補完windowのonClickテスト
やること
テキスト入力
別のactionを登録可能にする
Ctrl+クリック/Enterで新しいタブでページを開く
<C-i>でアイコン記法を入力する
見つかったバグ
/icons/done.icon特になし
code:js
(async () => {
const projectName = 'programming-notes';
const pageTitle = '補完windowのonClickテスト';
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});
// 入力補完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});
// tabキーで選択する
editor.addEventListener('keydown', e => {
if (this.hidden) return;
if (e.key === 'i' && e.ctrlKey) {
e.preventDefault();
e.stopPropagation();
suggestBox.selectedItem.click({}, true);
return;
}
if (e.key !== 'Tab') return;
if (e.altKey || e.ctrlKey) return;
e.preventDefault();
e.stopPropagation();
if (e.shiftKey) {
suggestBox.selectPrevious({wrap: true});
} else {
suggestBox.selectNext({wrap: 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) ?
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: (e, icon) => {
if (e.ctrlKey) {
window.open(https://scrapbox.io${link});
return;
}
const text = icon ? [${link}.icon] : [${link}];
insertText(text);
},
};
}));
}, {once: true});
};
function insertText(text) {
const cursor = document.getElementById('text-input');
cursor.focus();
cursor.value = text;
const uiEvent = document.createEvent('UIEvent');
uiEvent.initEvent('input', true, false);
cursor.dispatchEvent(uiEvent);
}
})();
入力補完に使うscrapbox projects
code:test1-project-list.js
export const projects = [
'hub',
'villagepump',
];
worker code
code:test1-worker.js
const pageTitle = '補完windowのonClickテスト';
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();
});
} while(followingId);
_log(Loaded ${links.length} links from /${project});
return links;
}
// debug用
function _log(msg, ...objects) {
console.log([search-worker @${pageTitle}/test1-worker.js] ${msg}, ...objects);
}