generated at
増井俊之


繰り返し実行 (Ctrl-Rで再実行)
script.js__
import "https://scrapbox.io/api/code/again/Scrapbox/script.js"
KeyScriptenの導入で不要になったはず

style.css
.grid-style-item[data-page-title*="settings"], .grid-style-item[data-page-title*="ブログ:"], .grid-style-item[data-page-title*="Tips:"], .grid-style-item[data-page-title*="..."] {display: none !important;}

ScrapExecによるコードブロック評価
script.js
import '/api/code/masui/ScrapExec/script.js'
alert.js
alert('abc');

ScrapCalcによる式評価
script.js
import '/api/code/masui/ScrapCalc/script.js'
style.css
@import '/api/code/masui/ScrapCalc/style.css';

メニューに検索を追加
script.js
scrapbox.PageMenu.addItem({ title: () => "> google Site", onClick: () => window.open(`https://www.google.com/search?q=${encodeURIComponent(window.scrapbox.Page.title)}+site:scrapbox.io`) })

メニューにいろいろ追加
翻訳メニュー
script.js
import '/api/code/masui/Scrapboxテキストを翻訳する/script.js'

横断検索
script.js
import '/api/code/masui/選択テキストから横断検索する/script.js'

使わないPopup Menuを消す
style.css
.popup-menu .strike-button, .popup-menu .italic-button, .popup-menu .link-button, .popup-menu .strong-button { display: none !important; }


script.jsxxxx
if(location.href == "https://scrapbox.io/masui/masui-random"){ const button = $('.random-jump-button') if (button) { button[0].click() } }

abc みたいな表記のテスト
style.css
.deco-\! { color: #000; border-radius: 4px; padding: 4px; background-color: #ff0; font-size: 1.2em; }

style.css
/* .two-two { width: 150px !important; height: 165px !important; } */ body { } .page { //opacity: 0.93; } li.page-list-item { //opacity: 0.93; }

script.jsxxx
$('head > link[rel=icon]').attr('href','/api/pages/masui/壁紙/icon');

Enterキーで新規ページ作成
不要になったようだ
script.js
/* $('body').on('keydown',function(e){ // Enterキーで新規ページ作成 if(e.target.tagName != "TEXTAREA" && e.target.tagName != "INPUT"){ if(e.key == 'Enter'){ var project = location.href.split('/')[3]; location.href = `/${project}/new`; } } }); */ /* $('.btn.btn-default').on('click',function(){ */ $('button').on('click',function(){ var s = $('.form-control').val(); if(s == ''){ var project = location.href.split('/')[3]; location.href = `/${project}/new`; } });


新規作成ボタンを消す
style.css
.new-button { /* 新規ボタンを消す */ visibility: hidden; }

音声入力
script.jsxxx
import '/api/code/shokai/音声入力Menu/script.js'

左上のメニューの右側にプロジェクト名を表示し、それをクリックするとトップに戻る
script.jsxxx
var __title = $('<a>').attr('href','/') //.text('🏠 ' + $('.project-home .title').text()) .text($('.project-home .title').text()) .css('color','#555') .css('font-size','20px') .hover( function () { $(this).css('text-decoration','none'); }) var __div = $('<div>') .append(__title) .css('margin-left','40px') .css('margin-top','12px') $('.navbar .container .row .col-brand').append(__div)

スクリーンセーバ
script.js
import 'https://scrapbox.io/api/code/masui/ScrapboxSaver/script.js';

script.jsxxx
const intervalPeriod = 10000 let isRunning = false let interval = undefined scrapbox.PageMenu.addMenu({ title: 'random-screen-saver', image: 'https://gyazo.com/c08a5e4439ded1540bc05b31da9d58c9/raw' }) scrapbox.PageMenu('random-screen-saver').addItem({ title: () => (isRunning)? "Stop screen saver." : "Start screen saver!", onClick: () => { if (isRunning) { isRunning = false clearInterval(interval) } else { isRunning = true clickRandomButton() interval = setInterval(clickRandomButton, intervalPeriod) } } }) function clickRandomButton() { const button = $('.random-jump-button') if (!button) return button[0].click() }

script.js
/* LineId --- 24文字のstring interface commit.changes { _update: LineId; lines: { origText: string; text: string; }; } | { _insert: LineId | "_end"; lines: { id: LineId; text: string; }; } | { _update: LineId; lines: { text: string; origText: string; }; } | { title: string; titleLc: string; } | { descriptions: string[]; } | { links: string[]; } */ scrapbox.PageMenu.addMenu({ title: '履歴スライダー', image: 'https://1.bp.blogspot.com/-UZtkSEX0wh4/U5l5_dNcEsI/AAAAAAAAhWs/UzJGVzyiX8Y/s800/kaichu_dokei.png', onClick: () => { const a = location.href.split('/'); const host = a[2]; const project = a[3]; const page = a[4]; const pageUrl = `https://${host}/api/pages/${project}/${page}`; fetch(pageUrl) .then(res => res.json()) .then(pageData => { const commitUrl = `https://${host}/api/commits/${project}/${pageData.id}`; return fetch(commitUrl); }) .then(res => res.json()) .then(commitData => { // returns all changes of all commits return commitData.commits.reduce((all, rawCommit) => { const cs = rawCommit.changes.map(rawChange => { const change = {}; if (rawChange._insert) { change.type = '_insert'; change.targetId = rawChange[change.type]; } else if (rawChange._update) { change.type = '_update'; change.targetId = rawChange[change.type]; } else if (rawChange._delete) { change.type = '_delete'; change.targetId = rawChange[change.type]; } else if (rawChange.title) { change.type = 'title'; } else if (rawChange.descriptions) { change.type = 'descriptions'; } else if (rawChange.links) { change.type = 'links'; } else { console.info('unknown type. commit change: ', rawChange); } if (rawChange.lines) { change.lines = rawChange.lines; } return change; }); return [ ...all, ...cs, ]; }, []); }) .then(changes => { // 行の文字列のコレクション // - すべての履歴それぞれのtextを順に入れておく const texts = []; // すべてのhistoryを配列で持つ // - [{ id: LindeId, updatedAt: [idx1, ... ], deletedAt?: idx }] const allHistory = changes.reduce((history, change, i) => { if (change.type === '_insert' || change.type === '_update') { texts.push(change.lines.text); } else if (change.type === '_delete') { texts.push(null); } const textLastIndex = texts.length - 1; // console.log({ text: change.lines && change.lines.text, texts, textLastIndex, history }); // 最初のイベントは _insert か _update のはずなのでとにかく保存 if (history.length === 0) { let id; if (change.type === '_insert') { id = change.lines.id; } else if (change.type === '_update') { id = change.targetId; } return [{ id, updatedAt: [textLastIndex] }]; } if (change.type === '_insert') { const line = { id: change.lines.id, updatedAt: [textLastIndex], }; if (change.targetId === '_end') { history.push(line); } else { const lineIndex = history.findIndex(li => li.id === change.targetId); if (lineIndex === -1) { console.info(`_insert: line index not found. commit change (${i}):`, change); return history; } history.splice(lineIndex, 0, line); } } else if (change.type === '_update') { const lineIndex = history.findIndex(h => h.id === change.targetId); if (lineIndex === -1) { console.info(`_update: line index not found. commit change (${i}):`, change); return history; } history[lineIndex].updatedAt.push(textLastIndex); } else if (change.type === '_delete') { const lineIndex = history.findIndex(h => h.id === change.targetId); if (!lineIndex) { console.info('line index not found. commit change:', change); return history; } history[lineIndex].deletedAt = lineIndex; } else { return history; } return history; }, []); // console.log(allHistory); return { texts, allHistory }; }) .then(({ texts, allHistory }) => { const getHistory = time => { return allHistory.reduce((all, line) => { const updated = line.updatedAt.filter(u => u <= time).pop(); const deleted = line.deletedAt <= time; if (!updated || deleted) { return all; } return [...all, { id: line.id, textIndex: updated }]; }, []); }; const showText = time => { return getHistory(time).map(line => { return texts[line.textIndex]; }).join('\n'); }; // console.log(getHistory(100)); // console.log(showText(100)); const historyContainer = document.createElement('div'); historyContainer.classList.add('history-container'); Object.entries({ 'background-color': '#555555', position: 'fixed', 'z-index': '90000', top: '5px', left: '5px', width: 'calc( 100% - 10px )', 'max-height': '100%', border: '3px solid #22cc77', overflow: 'scroll', }).forEach(([key, value]) => historyContainer.style.setProperty(key, value)); document.querySelector('body').appendChild(historyContainer); const historyCloseButton = document.createElement('button'); historyCloseButton.classList.add('history-close-button'); Object.entries({ 'font-size': '30px', 'line-height': '1em', padding: '0', position: 'fixed', 'z-index': '90001', top: '10px', right: '10px', width: '30px', height: '30px', }).forEach(([key, value]) => historyCloseButton.style.setProperty(key, value)); historyContainer.appendChild(historyCloseButton); historyCloseButton.insertAdjacentText('beforeend', '×'); const historyBackground = document.createElement('div'); historyBackground.classList.add('history-background'); Object.entries({ position: 'fixed', 'z-index': '89999', top: '0', right: '0', width: '100%', height: '100%', 'background-color': 'rgba(255, 255, 255, 0.4)', }).forEach(([key, value]) => historyBackground.style.setProperty(key, value)); document.querySelector('body').appendChild(historyBackground); const historyPre = document.createElement('pre'); historyPre.classList.add('history-pre'); Object.entries({ width: '100%', 'max-height': '100%', }).forEach(([key, value]) => historyPre.style.setProperty(key, value)); historyPre.insertAdjacentHTML('beforeend', showText(texts.length)); historyContainer.appendChild(historyPre); const historySlider = document.createElement('input'); historySlider.classList.add('history-slider'); Object.entries({ position: 'fixed', 'z-index': '99999', top: '10px', width: '90%', }).forEach(([key, value]) => historySlider.style.setProperty(key, value)); historySlider.type = 'range'; historySlider.min = '0'; historySlider.max = `${texts.length}`; historySlider.value = `${texts.length}`; historySlider.step = 1; historyContainer.appendChild(historySlider); const removeHistoryContainer = () => { historyContainer.parentNode.removeChild(historyContainer); historyBackground.parentNode.removeChild(historyBackground); }; historyCloseButton.addEventListener('click', removeHistoryContainer); historyBackground.addEventListener('click', removeHistoryContainer); const updateHistory = e => { const time = e.target.value; historyPre.innerHTML = showText(time); }; historySlider.addEventListener('input', updateHistory); historySlider.addEventListener('change', updateHistory); }); }, });