行選択⇄ブロック選択をするpopupmenu
code:script.js
// ==UserScript==
// @name Cosense Mobile Select/ExpandUntilBlank PopupMenu Button
// @namespace http://tampermonkey.net/
// @version 1.3
// @description 行選択 → 次の空行手前まで一気にブロック選択
// @match *://*/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// -----------------------------
// textarea と行取得関数
// -----------------------------
function a() {
const ta = document.getElementById("text-input");
if (!ta) throw Error("#text-input not found");
return ta;
}
function f() {
const linesDiv = document.getElementsByClassName("lines").item(0);
if (!linesDiv) throw Error("div.lines not found");
const key = Object.keys(linesDiv).find(k => k.startsWith("__reactFiber"));
if (!key) throw Error("div.lines missing __reactFiber");
return linesDivkey.return.stateNode.props.lines;
}
function d() {
const ta = a();
const key = Object.keys(ta).find(k => k.startsWith("__reactFiber"));
if (!key) throw Error("textarea missing __reactFiber");
return takey.return.return.stateNode.props;
}
function h() {
const ta = a();
const key = Object.keys(ta).find(k => k.startsWith("__reactFiber"));
if (!key) throw Error("textarea missing __reactFiber");
const stores = takey.return.return.stateNode._stores;
const selection = stores.find(s => s.constructor.name === "Selection");
if (!selection) throw Error("Selection store not found");
return { selection };
}
function O() { return h().selection; }
// -----------------------------
// 選択拡張ロジック
// -----------------------------
let expanded = false; // 1回目か2回目かのフラグ
function toggleSelectExpand() {
const { position } = d();
const lines = f();
if (!position || !linesposition.line) return;
if (!expanded) {
// --- 1回目: カーソル行だけ選択 ---
O().setRange({
start: { line: position.line, char: 0 },
end: { line: position.line, char: linesposition.line.text.length }
});
expanded = true;
} else {
// --- 2回目: 空行の手前まで一気に選択 ---
let endLine = position.line;
for (let i = position.line + 1; i < lines.length; i++) {
if (linesi.text.trim() === "") break; // 空行に到達したら止める
endLine = i;
}
O().setRange({
start: { line: position.line, char: 0 },
end: { line: endLine, char: linesendLine.text.length }
});
expanded = false; // また次回は1行からスタート
}
a().focus(); // フォーカス保持
}
// -----------------------------
// popupmenu に追加
// -----------------------------
scrapbox.PopupMenu.addButton({
title: "Select",
/*"\uf248",*/ // fa-object-ungroup のUnicode
onClick: toggleSelectExpand
});
// -----------------------------
// Font Awesome 用のスタイルを注入
// -----------------------------
const style = document.createElement("style");
style.textContent = `
.selections .popup-menu .button-container .button {
font-family: "Font Awesome 5 Free", "Font Awesome 5 Brands", sans-serif;
/*font-weight: 900; solid アイコン */
font-size: 14px;
line-height: 2;
}
`;
document.head.appendChild(style);
})();
code:js
// ==UserScript==
// @name Cosense Mobile Select PopupMenu Button
// @namespace http://tampermonkey.net/
// @version 1.0
// @description popupmenu に選択ボタンを追加(iOS キーボードを閉じない)
// @match *://*/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// -----------------------------
// textarea と行取得関数
// -----------------------------
function a() {
const ta = document.getElementById("text-input");
if (!ta) throw Error("#text-input not found");
return ta;
}
function f() {
const linesDiv = document.getElementsByClassName("lines").item(0);
if (!linesDiv) throw Error("div.lines not found");
const key = Object.keys(linesDiv).find(k => k.startsWith("__reactFiber"));
if (!key) throw Error("div.lines missing __reactFiber");
return linesDivkey.return.stateNode.props.lines;
}
function d() {
const ta = a();
const key = Object.keys(ta).find(k => k.startsWith("__reactFiber"));
if (!key) throw Error("textarea missing __reactFiber");
return takey.return.return.stateNode.props;
}
function h() {
const ta = a();
const key = Object.keys(ta).find(k => k.startsWith("__reactFiber"));
if (!key) throw Error("textarea missing __reactFiber");
const stores = takey.return.return.stateNode._stores;
const selection = stores.find(s => s.constructor.name === "Selection");
if (!selection) throw Error("Selection store not found");
return { selection };
}
function O() { return h().selection; }
// -----------------------------
// 現在カーソル行を選択
// -----------------------------
function selectCurrentLine() {
const { position } = d();
const lines = f();
if (!position || !linesposition.line) return;
O().setRange({
start: { line: position.line, char: 0 },
end: { line: position.line, char: linesposition.line.text.length }
});
a().focus(); // フォーカスを保持してキーボードを閉じない
}
// -----------------------------
// popupmenu に追加
// -----------------------------
scrapbox.PopupMenu.addButton({
title: "🖍", // ペンマーク
onClick: selectCurrentLine
});
})();