generated at
編集バーを生やすUserScript
Scrapboxの編集画面に編集バーを生やすUserScriptのこと
記号を入力しやすくなる
スマホからscrapbox編集するのつらい問題を解決する手法の1つ

>@ryot_g: これつけたらScrapboxがめちゃくちゃ使いやすくなった
>

ryota知らないうちにページができてる笑
ありがとうございます
下にコード置いておきます
問題点
ryota編集バーの下に文字が隠れちゃう事がある
ので気になる方は右端とかに寄せてみてもいいかもしれません
もしソフトウェアキーボード表示時の、強制スクロール位置調整方法を知ってたら教えて欲しいです!!
ryotaページ一覧では編集バーを表示しないようにしているが、検索結果ページなどで表示されてしまう
たぶん直せるけどめんどくて直してません
だれか、、、お願いします
javascript
$('body').append('<div class="input_supporter" id="input_supporter"><button class="ins_btn" id="ins_link">[]</button><button class="ins_btn" id="ins_hash">#</button><button class="ins_btn" id="ins_asterisk">*</button><button class="ins_btn" id="ins_slash">/</button><button class="ins_btn" id="ins_greater">></button><button class="ins_btn" id="ins_code">``</button><button class="ins_btn" id="ins_period">.</button><button class="ins_btn" id="ins_plus">+</button></div>'); if(location.pathname === "/project_name/") { $('#input_supporter').addClass('ins_invisible'); } // domの更新を検知 const target = document.getElementsByClassName("page-wrapper")[0]; const observer = new MutationObserver((recs) => { if (!recs[0].target.classList.contains("enter")) { if(location.pathname === "/project_name/") { $('#input_supporter').addClass('ins_invisible'); } else { $('#input_supporter').removeClass('ins_invisible'); } } }); observer.observe(target, {attributes: true, attributeFilter: ["class"]}); const ins_input = function(value) { const cursor = document.getElementById('text-input'); cursor.focus(); document.execCommand('insertText', null, value); }; $('#ins_link').on('touchend', () => ins_input("[]")); $('#ins_hash').on('touchend', () => ins_input("#")); $('#ins_asterisk').on('touchend', () => ins_input("*")); $('#ins_slash').on('touchend', () => ins_input("/")); $('#ins_greater').on('touchend', () => ins_input("> ")); $('#ins_code').on('touchend', () => ins_input("``")); $('#ins_period').on('touchend', () => ins_input(".")); $('#ins_plus').on('touchend', () => ins_input("+"));

style.css
.input_supporter { position: fixed; right: 0; bottom: 0; left: 0; justify-content: space-between; display: none; width: 100%; border-radius: 8px 8px 0 0; background: #FFF; border: solid 1px #37352f17; box-shadow: rgb(15 15 15 / 5%) 0px 0px 0px 1px, rgb(15 15 15 / 10%) 0px 3px 6px, rgb(15 15 15 / 20%) 0px 9px 24px; z-index: 300; } .ins_btn { width: 12.5%; width: calc(100% / 8); padding: 12px 0; background: none; border: none; color: #111; } .ins_btn:not(:first-child) { border-left: solid 1px #37352f17; } .ins_invisible { display: none !important; } @media (max-width: 767px) { .input_supporter { display: flex; } .status-bar { bottom: 46px; } .page-status { border-bottom: 1px solid var(--tool-light-color, #a9aaaf); border-radius: 3px 0 0 3px; } }

すごいyosider
なるほど。単純に下に生やすだけでいいみたいですねtakker
code readingしつつ書き直してみる
あー、 .page-status の位置を調節しないといけないのか
単純にDOMを挿入しただけだと重なってしまう
script.js
import { defaultSettings, setup } from "./mod.js"; setup(defaultSettings);
mod.js
const c=["[]","#","*","/",">","``",".",">","+"].map(t=>({title:t,onClick:()=>t})),r=t=>{const d=u();d.append(...t.map(({title:p,className:i,onClick:a})=>l(p,a,i)));const o=document.createElement("div"),e=o.attachShadow({mode:"open"}),n=document.createElement("style");n.textContent=".input-supporter{position:fixed;right:0;bottom:0;left:0;justify-content:space-between;width:100%;border-radius:8px 8px 0 0;background:#FFF;border:solid 1px #37352f17;box-shadow:#0f0f0f0d 0 0 0 1px,#0f0f0f1a 0 3px 6px,#0f0f0f33 0 9px 24px;z-index:300}.ins-btn{width:12.5%;width:calc(100% / 8);padding:12px 0;background:none;border:none;color:#111}.ins-btn:not(:first-child){border-left:solid 1px #37352f17}@media (max-width: 767px){.input-supporter{display:flex}}",e.appendChild(n),e.appendChild(d),document.body.append(o);const s=()=>o.style.display=scrapbox.Layout==="page"?"":"none";s(),scrapbox.addListener("layout:changed",s)},u=()=>{const t=document.createElement("div");return t.classList.add("input-supporter"),t},l=(t,d,o)=>{const e=document.createElement("button");return e.classList.add("ins-btn"),o&&e.classList.add(o),e.textContent=t,e.addEventListener("click",()=>{const n=document.getElementById("text-input");if(!n)throw Error("#text-input is not ditected.");n.focus(),n.value=d();const s=new InputEvent("input",{bubbles:!0});n.dispatchEvent(s)}),e};export{c as defaultSettings};export{r as setup};
sh
deno cache -r=https://scrapbox.io https://scrapbox.io/api/code/villagepump/編集バーを生やすUserScript/mod.ts
mod.ts
/// <reference no-default-lib="true" /> /// <reference lib="esnext" /> /// <reference lib="dom" /> import type { Scrapbox } from "https://raw.githubusercontent.com/scrapbox-jp/types/0.3.2/userscript.ts"; declare const scrapbox: Scrapbox; export interface Button { title: string; onClick: () => string; className?: string; }; export const defaultSettings: Button[] = ["[]", "#", "*", "/", ">", "``", ".", ">", "+"] .map( (text) => ({ title: text, onClick: () => text, }) ); export const setup = (settings: Button[]) => { const supporter = makeSupporter(); supporter.append(...settings.map( ({ title, className, onClick }) => makeButton(title, onClick, className) )); const app = document.createElement("div"); const shadowRoot = app.attachShadow({ mode: "open" }); const style = document.createElement("style"); style.textContent = ".input-supporter{position:fixed;right:0;bottom:0;left:0;justify-content:space-between;width:100%;border-radius:8px 8px 0 0;background:#FFF;border:solid 1px #37352f17;box-shadow:#0f0f0f0d 0 0 0 1px,#0f0f0f1a 0 3px 6px,#0f0f0f33 0 9px 24px;z-index:300}.ins-btn{width:12.5%;width:calc(100% / 8);padding:12px 0;background:none;border:none;color:#111}.ins-btn:not(:first-child){border-left:solid 1px #37352f17}@media (max-width: 767px){.input-supporter{display:flex}}"; shadowRoot.appendChild(style); shadowRoot.appendChild(supporter); document.body.append(app); const changeVisible = () => app.style.display = scrapbox.Layout === "page" ? "" : "none"; changeVisible(); scrapbox.addListener("layout:changed", changeVisible); }; const makeSupporter = () => { const div = document.createElement("div"); div.classList.add("input-supporter"); return div; }; const makeButton = (title: string, onClick: () => string, className?: string) => { const button = document.createElement("button"); button.classList.add("ins-btn"); if (className) button.classList.add(className); button.textContent = title; button.addEventListener("click", () => { const cursor = document.getElementById('text-input') as HTMLTextAreaElement | null; if (!cursor) { throw Error("#text-input is not ditected."); } cursor.focus(); cursor.value = onClick(); const event = new InputEvent("input", { bubbles: true }); cursor.dispatchEvent(event); }); return button; };
scrapbox-userscript-stdで直接 .page-status に生やしたらどうだろう?
あっだめだ。クリックイベントとか対応してなかった
機能追加しないと
mod2.ts
/// <reference no-default-lib="true" /> /// <reference lib="esnext" /> /// <reference lib="dom" /> import { useStatusBar, insertText } from "https://raw.githubusercontent.com/takker99/scrapbox-userscript-std/0.12.1/browser/dom/mod.ts"; import type { Scrapbox } from "https://raw.githubusercontent.com/scrapbox-jp/types/0.3.2/userscript.ts"; declare const scrapbox: Scrapbox; export interface Button { title: string; onClick: () => string; className?: string; }; export const defaultSettings: Button[] = ["[]", "#", "*", "/", ">", "``", ".", ">", "+"] .map( (text) => ({ title: text, onClick: () => text, }) ); export const setup = (settings: Button[]) => { const supporter = makeSupporter(); supporter.append(...settings.map( ({ title, className, onClick }) => makeButton(title, onClick, className) )); const app = document.createElement("div"); const shadowRoot = app.attachShadow({ mode: "open" }); const style = document.createElement("style"); style.textContent = ".input-supporter{position:fixed;right:0;bottom:0;left:0;justify-content:space-between;width:100%;border-radius:8px 8px 0 0;background:#FFF;border:solid 1px #37352f17;box-shadow:#0f0f0f0d 0 0 0 1px,#0f0f0f1a 0 3px 6px,#0f0f0f33 0 9px 24px;z-index:300}.ins-btn{width:12.5%;width:calc(100% / 8);padding:12px 0;background:none;border:none;color:#111}.ins-btn:not(:first-child){border-left:solid 1px #37352f17}@media (max-width: 767px){.input-supporter{display:flex}}"; shadowRoot.appendChild(style); shadowRoot.appendChild(supporter); document.body.append(app); const changeVisible = () => app.style.display = scrapbox.Layout === "page" ? "" : "none"; changeVisible(); scrapbox.addListener("layout:changed", changeVisible); }; const makeSupporter = () => { const div = document.createElement("div"); div.classList.add("input-supporter"); return div; }; const makeButton = (title: string, onClick: () => string, className?: string) => { const button = document.createElement("button"); button.classList.add("ins-btn"); if (className) button.classList.add(className); button.textContent = title; button.addEventListener("click", () => { insertText(onClick()); }); return button; };