main.js(async () => {
const projectName = 'programming-notes';
const pageTitle = 'editorから検索語句を取得して補完windowに渡すテスト';
const promises = [
import(`/api/code/${projectName}/scrapbox-dom-accessor/script.js`),
import(`/api/code/${projectName}/scrapbox-cursor-position/script.js`),
import(`/api/code/${projectName}/${pageTitle}/worker-promise.js`),
import(`/api/code/${projectName}/${pageTitle}/test1-project-list.js`),
import(`/api/code/${projectName}/JSのkeyをVim_key_codeに変換するscript/script.js`),
import(`/api/code/${projectName}/${pageTitle}/asyncSingleton.js`),
import(`/api/code/${projectName}/scrapbox-keyboard-emulation/script.js`),
import(`/api/code/${projectName}/scrapbox-char-accessor/script.js`),
//import(`/api/code/${projectName}/scrapbox-suggest-container/test-dark-theme.js`),
import(`/api/code/${projectName}/scrapbox-suggest-container/script.js`),
];
const worker = new Worker(`/api/code/${projectName}/${pageTitle}/test1-worker.js`);
const [{scrapboxDOM}, {cursor}, {postToWorker}, {projects}, {js2vim}, {asyncSingleton}, {press}, {char: c}] = await Promise.all(promises);
// 入力補完windowを作る
const suggestBox = document.createElement('suggest-container');
scrapboxDOM.editor.append(suggestBox);
await postToWorker(worker, {type: 'fetch', projects});
// tabキーで選択する
scrapboxDOM.editor.addEventListener('keydown', e => {
if (suggestBox.hidden) return;
// programで生成したkeyboard eventは無視する
if (!e.isTrusted) return;
switch(js2vim(e)) {
case '<C-i>':
e.preventDefault();
e.stopPropagation();
(suggestBox.selectedItem ?? suggestBox.firstItem)?.click?.({}, true);
return;
case '<Tab>':
e.preventDefault();
e.stopPropagation();
suggestBox.selectNext({wrap: true});
return;
case '<S-Tab>':
e.preventDefault();
e.stopPropagation();
suggestBox.selectPrevious({wrap: true});
return;
case '<CR>':
e.preventDefault();
e.stopPropagation();
suggestBox.firstItem.click();
case undefined:
return;
// その他の入力はscrapboxにそのまま渡す
default:
scrapboxDOM.textInput.focus();
return;
}
});
// あいまい検索して、候補を入力補完windowに追加する
const search = async (word, index, {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: 'Searching...', image,});
}, 1000);
const {links} = await postToWorker(worker, {type: 'search', word, limit, timeout});
clearTimeout(timer);
suggestBox.clear();
scrapboxDOM.textInput.focus();
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}]`;
scrapboxDOM.textInput.focus();
press('Home');
press('Home');
for (let i = 0; i < index; i++) {
press('ArrowRight');
}
for (let i = 0; i < `[${word}]`.length; i++) {
press('ArrowRight', {shiftKey: true});
}
insertText(text);
},
};
}));
};
const postSearch = asyncSingleton(search);
let prevSearch = '';
let state = 'input';
const observer = new MutationObserver(() =>{
const cursor_ = cursor();
console.log('[test:editorから検索語句を取得して補完windowに渡すテスト] ', cursor_.left?.text, cursor_.right?.text, cursor_);
const link = cursor_.left?.link ?? cursor_.right?.link;
console.log({clientLeft: link?.DOM?.clientLeft, clientTop: link?.DOM?.clientTop});
if (!link?.text?.startsWith?.('/')) {
suggestBox.mode = '';
suggestBox.hide();
return;
}
const firstIndex = link.headChar.index;
suggestBox.mode = 'auto';
const editorRect = scrapboxDOM.editor.getBoundingClientRect();
const {left, bottom} = link.DOM.getBoundingClientRect();
suggestBox.position({
top: bottom - editorRect.top,
left: left - editorRect.left,
});
console.log({prevSearch,text: link?.text});
if (prevSearch === link?.text) return;
prevSearch = link?.text;
postSearch(prevSearch, firstIndex);
});
observer.observe(scrapboxDOM.cursor, {attributes: true});
})();