shio
塩澤一洋 | shio | shio.icon
しおざわかずひろ | Kazuhiro Shiozawa | Καζουχίρο Σιοζάουα
成蹊大学法学部 教授
多摩美術大学 非常勤講師
写真家
写真も原則としてshio.iconが撮影したものです。
このサイトの写真は Display P3(広色域) を前提に制作しています。色管理に対応していない環境では、見え方が異なることがあります。
Photos are intended to be viewed in Display P3–capable environments.
難しいことをやさしくするのが学者の役目、それを面白くするのが教員の役目、と考える法律学者兼大学教員です。
shioのアイコン
https://gyazo.com/ff355efb9b506690daabc4ed30c3ce24
shiologyのURLに飛べるQRコード
https://gyazo.com/fbf6d96be7b8bbc8b3e308e8ab638760
https://gyazo.com/9fa13e6cbc6fcb79d43283de13d557e3https://gyazo.com/76aca7ee0786f867badcb0cabe9ed9ff https://gyazo.com/e6a53caa434fcbf17e0262779159b908
/icons/-.icon
UserScripts
NewWorkボタン
code:script.js
scrapbox.PageMenu.addMenu({
title: "NewWork",
onClick: () => {
func();
},
});
function func() {
var project = location.pathname.split("/");
var title = scrapbox.Page.title;
var number = Number(title.substr(0, 5));
var now = new Date();
var path =
"/" +
(number + 1).toString().padStart(5, "0") +
"?body=" + "No. " +
"[" +
(number + 1).toString().padStart(5, "0") +
"/" +
(number + 1).toString().padStart(5, "0") +
"], by shio / 塩澤一洋\n[" +
now.getFullYear() +
"-" +
(now.getMonth() + 1).toString().padStart(2, "0") +
"-" +
now.getDate().toString().padStart(2, "0") +
"], " +
now.getFullYear() +
"年" +
"[" +
(now.getMonth() + 1) +
"月" +
now.getDate() +
"日]\n\n\n\n◀[" +
(number + 2).toString().padStart(5, "0") +
"]\n▶[" +
title +
"]" +
"\nhttps://gyazo.com/c8df74caca3d9181fc391a27f9150b54";
const encoded = encodeURI(path);
window.location.href = encoded;
}
tweet menu
code:script.js
scrapbox.PageMenu.addItem({
title: 'Tweet',
onClick: () => window.open(
https://twitter.com/intent/tweet?url=${encodeURIComponent(location.href)}&text=${encodeURIComponent("shiology新着記事💕\n" + window.scrapbox.Page.title)}
)
})
日付書式 control+tで日付を入力
code:script.js
// 1. 既存のタイムスタンプフォーマットをすべて削除
cosense.TimeStamp.removeAllFormats();
// 2. 好きなフォーマットだけを追加(Ctrl+T でこの順にトグル)
cosense.TimeStamp.addFormat("]YYYY-MM-DD[ HH:mm:ss");
cosense.TimeStamp.addFormat("YYYY-MM-DD HH:mm:ss");
cosense.TimeStamp.addFormat("]YYYY-MM-DD[");
cosense.TimeStamp.addFormat("YYYY-MM-DD");
cosense.TimeStamp.addFormat("]M月D日[");
cosense.TimeStamp.addFormat("]YYYYMMDD[");
cosense.TimeStamp.addFormat("YYYYMMDD");
文字カウントポップアップ
code:script.js
cosense.PopupMenu.addButton({
title(text) {
const chars = text.replace(/\r\n/g, '').length; const trimmed = text.trim();
const words = trimmed ? trimmed.split(/\r\n\s+/).length : 0; return ${chars}c ${words}w;
},
onClick: () => {},
});
全角半角変換などをする「format」メニュ
1. 箇条書きの先頭を全てTabに置き換える
2. 文中の全角・半角空白を取り除く
3. 文字化けを修正する (今回は での を での に直す)
4. 全角英数字を半角英数字に置き換える
5. 全角括弧を半角括弧に置き換える
6. 括弧で囲まれた前後に空白を入れる
7. コードブロック記法の前後に空白を入れる
code:script.js
// PopupMenu が存在する場合だけボタンを追加
if (cosense.PopupMenu && typeof cosense.PopupMenu.addButton === 'function') {
cosense.PopupMenu.addButton({
title: 'format',
onClick(text) {
return text
.split('\n')
.map(line =>
line
// 行頭のスペース類をタブに
.replace(/^\s*/, s => s.replace(/\s/g, '\t'))
// 濁点付きかな(び・ガ等)だけを対象にコードを1つ進める
String.fromCharCode(s.charCodeAt(0) + 1)
)
// 全角英数字 → 半角
String.fromCharCode(s.charCodeAt(0) - 0xFEE0)
)
.replace('(', '(')
.replace(')', ')')
.replace(/\S\(/g, s => s.charAt(0) + ' (')
.replace(/\)\S/g, s => ') ' + s.charAt(1))
.replace(/\S.*/g, s => s.charAt(0) + ' ' + s.slice(1))
.replace(/.*\S/g, s => s.slice(0, -1) + ' ' + s.slice(-1))
)
.join('\n');
},
});
}
選択範囲に引用符をつける
code:script.js
cosense.PopupMenu.addButton({
title: 'quote',
onClick(text) {
return text.split(/\n/).map(line => > ${line}).join('\n');
},
});
文字数常時表示
code:script.js
(() => {
if (!window.scrapbox) return;
const fmt = n => new Intl.NumberFormat('en-US').format(n);
// overlay element(右下固定)
let wrapper = document.getElementById('__charCounterOverlay__');
if (!wrapper) {
wrapper = document.createElement('div');
wrapper.id = '__charCounterOverlay__';
wrapper.style.position = 'fixed';
wrapper.style.bottom = '24px'; // お好みの位置に調整可
wrapper.style.right = '10px';
wrapper.style.zIndex = '9999';
wrapper.style.fontSize = '12px';
wrapper.style.opacity = '0.8';
wrapper.style.padding = '3px 8px';
wrapper.style.borderRadius = '4px';
wrapper.style.background = 'rgba(0,0,0,0.08)';
wrapper.style.pointerEvents = 'none';
document.body.appendChild(wrapper);
}
// current page lines
const getLines = () => (scrapbox.Page && scrapbox.Page.lines) || null;
// calc characters with rules:
// - ブラケット内の URL は削除し、残り(例: 07864)は数える
// - ブラケット内の装飾記号 (* /) は除外
// - ブラケット文字 自体は常に除外
// - ブラケット外の URL はそのまま文字としてカウント
// - スペース(全角・半角)はカウント対象(改行は除外)
const calcChars = rawText => {
try {
let text = String(rawText);
text = text.replace(/\[(^\]*)\]/g, (_m, inner) => { const trimmed = inner.trim();
if (/^https?:\/\/\S+$/.test(trimmed)) return '';
let t = inner.replace(/https?:\/\/\S+/g, '');
t = t.replace(/*//g, ''); return t;
});
text = text.replace(/[\\]/g, ''); text = text.replace(/\r\n/g, ''); return text.length;
} catch (_e) {
return rawText ? String(rawText).length : 0;
}
};
// 実際の更新処理
const doUpdate = () => {
const lines = getLines();
if (!lines || !lines.length) {
wrapper.textContent = '';
return;
}
const text = lines.map(l => l.text).join('\n');
const chars = calcChars(text);
wrapper.textContent = ${fmt(chars)} chars;
};
// デバウンス用タイマー
let pending = null;
const scheduleUpdate = (delay) => {
if (pending) clearTimeout(pending);
pending = setTimeout(() => {
pending = null;
doUpdate();
}, delay);
};
// 初期表示(Page.lines が入るタイミングの揺らぎに備えて数回試す)
requestAnimationFrame(doUpdate);
setTimeout(doUpdate, 200);
setTimeout(doUpdate, 1000);
// events
if (typeof scrapbox.on === 'function') {
// ページ切替時はすぐ更新(ただし1ティック後)
scrapbox.on('page:changed', () => {
scheduleUpdate(0);
});
// 編集中は 150ms デバウンスしてから再計算
scrapbox.on('lines:changed', () => {
scheduleUpdate(150);
});
}
})();