参加している他のprojectに同じページがあったら教えてほしい
already existsみたいなやつを、自分が参加している他のprojectにも拡張したいyosider.icon
同じタイトルのページを別のprojectでもう作ってたっけ?という時に、あるならすぐに飛びたい
project横断検索でもできるが、タイトルをコピーして検索→横断検索→projectに移動→pageに移動とやや手間
ページを作るときだけじゃなくていいか
自分が参加しているprojectだけじゃなく、各自でprojectを指定できるようにしたほうがいい?
自分が参加しているprojectだけなら、/scrapboxlab/api/projectsですべて取得できます
参加していないprojectも入れるなら、同じタイトルのページを取得するより、似たタイトルのページを検索した方がいい?
(WIP)external-completion的なことをリンクだけじゃなくタイトルについてもやる的な
実装
PageMenuのボタンを押したら、検索して同名ページへのリンク一覧をItemとして出すとか?
指定したプロジェクトの同名ページをfetchし、status codeが200ならmenuにappendする?
code:run.js_(js)
const projects = "villagepump","hub", "shokai","nishio","rashitamemo";
for (const project of projects) {
fetch("https://scrapbox.io/api/pages/" + project + /${scrapbox.Page.title})
.then((response) => {
console.log(response.ok)
if(response.ok==true){
window.open("https://scrapbox.io/"+ project + /${scrapbox.Page.title})
}
}
)
}
参加しているプロジェクトだと、ページが存在せずともtrueになって開いてしまう
404じゃないからか
status codeを利用しないで処理しよう
window.open()
きれいに1つずつ開けない気がする
2つ以上開いてしまうことがある
Fetch の使用 - Web API | MDN
Fetch API - Web API | MDN
code:run.js__(js)
const projects = "villagepump", "hub", "shokai", "nishio", "rashitamemo";
for (const project of projects) {
fetch(https://scrapbox.io/api/pages/${project}/${scrapbox.Page.title})
.then((body) => body.json())
.then((data) => {
console.log(data.lines.length);
if (data.lines.length != 1) {
window.open(https://scrapbox.io/${project}/${scrapbox.Page.title});
}
});
}
linesが0なら開かない
お、ロジックはできたぞ
エラーがいろいろ出ているが
page menuにappendするか?
Body.json() - Web API | MDN
https://gyazo.com/676238d800a673a77be27d8c310e2d24
ScrapboxのUserScriptテンプレートまとめ - Qiita
code:run.js
const projects = "villagepump", "hub", "shokai", "nishio", "rashitamemo";
scrapbox.PageMenu.addMenu({
title: "OtherProjects",
image: "https://gyazo.com/676238d800a673a77be27d8c310e2d24/raw",
});
for (const project of projects) {
fetch(/api/pages/${project}/${scrapbox.Page.title})
.then((body) => body.json())
.then((data) => {
console.log(data.lines.length);
if (data.lines.length != 1) {
scrapbox.PageMenu("OtherProjects").addItem({
title: () => /${project}/${scrapbox.Page.title},
onClick: () =>
window.open(
https://scrapbox.io/${project}/${scrapbox.Page.title}
),
});
}
});
}
できたぁ〜〜dnin.icon*3
参加している他のprojectに同じページがあったら教えてほしい#6026b06de5172d0000648bc5
今度は押したときに実行するようにするか
手直ししてみたtakker.icon
response.okと行数で判断する
押すたびにページを取得し直す
fetchを待たない
参加しているprojectすべてから検索する
https://gyazo.com/0e17f17bf495aaa983a08e8e12bd441e https://gyazo.com/0e17f17bf495aaa983a08e8e12bd441e.mp4
試し方
code:js
(async () => {
const {execute} = await import('/api/code/programming-notes/参加している他のprojectに同じページがあったら教えてほしい/run2.js');
execute("villagepump", "hub", "shokai", "nishio", "rashitamemo");
})();
code:run2.js
const id = "OtherProjects";
export async function execute(extraProjects = []) {
const response = await fetch('/api/projects');
const json = await response.json();
[...new Set([])]は配列の重複を除去するために使っている
code:run2.js
const projects = [...new Set([
...extraProjects,
...json.projects.map(({name}) => name),
])
].filter(project => project !== scrapbox.Project.name); // 現在のprojectは除く
scrapbox.PageMenu.addMenu({
title: id,
image: "https://gyazo.com/676238d800a673a77be27d8c310e2d24/raw",
onClick: async () => {
const menu = scrapbox.PageMenu(id);
menu.removeAllItems();
menu.emitChange();
const isFound = await Promise.all(projects.map(project => addItem(project, menu)));
if (isFound.some(i => i)) return;
menu.addItem({ title: 'No page found.', onClick: () => {} });
},
});
}
forEachはPromiseを待ってくれないことを利用?yosider.icon
Array.prototype.forEach()#forEach_expects_a_synchronous_function - JavaScript | MDN
forloopでも同じことできます
code:.js
for (const project of projects) {
addItem(project);
}
特に待つ必要もないので、awaitしなかっただけですtakker.icon
/icons/なるほど.iconyosider.icon
ヒットするページでクリックした後、ヒットしないページでクリックすると、前のページでの結果が残ったままになるyosider.icon
scrapbox.io/:project/index.jsを見てみたら、scrapbox.PageMenu.removeAllItem()では最後にscrapbox.PageMenu(:id).emitChange()されていなかった
scrapbox.PageMenu.addItem()ではされている
仕様なのか…?
scrapbox.PageMenu(:id).emitChange()なんてあったのか。/icons/知らんかった.icon
emitChange()を追加したら直った
調査していただき感謝ですtakker.icon
変だなあと思いつつ放置してた
確かに直感とは違う挙動ではある
1つもヒットしなかったら「見つかりませんでした」的なことを表示するにはどうしたらいいんだろうyosider.icon
Promise.all()で全てのfetchが終わるのを待ったあと、itemsの数を数えればできそう
すぐ思いつくのは、DOMの数を数える方法
もしかしたらitemsを数えるためのmethodがあるかもしれない
smartphoneからcodingすることになるとは考えもしなかったtakker.icon
つよすぎyosider.icon
ちょっとした修正なら簡単(狂気)takker.icon
動いたyosider.icon
consoleに404が何個も出てしまうのが気になるかもyosider.icon
extraProjectにページが存在しない時に出る
→Failed to load resource: the server responded with a status of 404 (Not Found)
code:run2.js
async function addItem(project, menu) {
const response = await fetch(/api/pages/${project}/${scrapbox.Page.title});
if (!response.ok) return false;
const {lines} = await response.json();
//console.log(lines);
if (lines.length < 3 && !lines1?.text) return false; // タイトルを除いて1行以内かつ1行目が空のとき、空ページだと判断する
menu.addItem({
title: /${project}/${scrapbox.Page.title},
onClick: () =>
window.open(
https://scrapbox.io/${project}/${scrapbox.Page.title}
),
});
return true;
}
JavaScript.icon
MDN.icon
Qiita.icon