morimorima t
https://gyazo.com/91033976aaa21a248f6bc6d77f0ca4ef
さまざまなカスタマイズを参考にさせていただいています。
ありがとうございます。
code:script.js
import '/api/code/shokai/音声入力Menu/script.js'
code:script.js
import '/api/code/daiiz/omakase-links/script.js'
というわけで、3つ登録
05:23 -----------------------------------
タイムスタンプのフォーマットを変更→ /help-jp/日付と時刻を入力する
code:script.js
scrapbox.TimeStamp.addFormat(']YYYY/MM/DD[');
区切り線作成→ /help-jp/日付と時刻を入力する
code:script.js
scrapbox.TimeStamp.addFormat('], hh:mm -----------------------------------[');
scrapbox.TimeStamp.addFormat('], [[]YYYY/MM/DD[ ------------------------------[]]');
code:script.js
$('body').attr('data-daiiz-rel-bubble', 'off'); // 関連ページを吹き出し表示する
$('body').attr('data-daiiz-text-bubble', 'on'); // リンク先ページのテキストを表示する
$('body').attr('data-daiiz-icon-button', 'on'); // アイコンをボタンにする
$('body').attr('data-daiiz-paste-url-title', 'ctrl'); // URL titleの形でペーストする プロジェクト名と期日を追加するようにした。
batsu.icon プロジェクト名が入ってない
code:script.js
scrapbox.PopupMenu.addButton({
title:'Todo',
onClick: text =>{
const lines = text
.map(line => line.replace(/[\\]/g, '').replace(/^\s+/, '')) // 入力ダイアログを表示 + 入力内容を user に代入
const projectname = window.prompt(lines + "のプロジェクト名", "");
const limit = window.prompt(lines+ "の期日", "");
const param = {
'text': lines,
'priority': 1,
'limit': limit,
'projectName': projectname,
'token':"4117fa21541dcc59b1e84b0f67ff1d3e5af7bd41",
}
console.log(lines)
const query = Object.keys(param)
.map(key => ${key}=${encodeURIComponent(param[key])})
.join('&')
const url = https://script.google.com/macros/s/AKfycbySUswu98dAtjYaIpOqAfEKKTPwbeNLtlB70PgRY8v6jR8awa4/exec?${query}
window.open(url)
return '' + lines + '';
}
})
☑️︎ いい感じ ( 15:03 )
☑️ かなり ( 15:03 )
☑️ とても ( 15:03 )
☑️ 素敵 ( 15:03 )
code:script.js
setTimeout(() => {
// チェックボックスとして使用する文字のリスト
const textArea = document.getElementById('text-input');
const keydownEvent = {
event: document.createEvent('Event'),
dispatch: function(keycode, withShift = false, withCommand = false) {
this.event.keyCode = keycode;
this.event.shiftKey = withShift;
this.event.metaKey = withCommand;
textArea.dispatchEvent(this.event);
}
};
keydownEvent.event.initEvent('keydown', true, true);
const inputEvent = {
event: document.createEvent('Event'),
dispatch: function(string) {
textArea.value = string;
textArea.dispatchEvent(this.event);
}
};
inputEvent.event.initEvent('input', true, true);
const isBoxCharSpan = (element) => {
if (element.tagName !== 'SPAN') return false;
const boxReg = new RegExp(^(${checkBoxList.join('|')})$);
for (const className of element.classList) {
if (/^c\-\d+$/.test(className)) {
return boxReg.test(element.textContent);
}
}
return false;
};
const startsWithBoxReg = new RegExp('^\\s*(' + checkBoxList.join('|') + ')');
// ボックスクリックでオンオフする
$('#app-container').off('click.toggleCheckBox', '.lines');
$('#app-container').on('click.toggleCheckBox', '.lines', event => {
const target = event.target;
if (!isFirstElementChild(target)||!isBoxCharSpan(target)) return;
setTimeout(() => {
let lineString;
try {
lineString = getCursorLineString();
} catch (err) {
console.log(err);
return;
}
if (!startsWithBoxReg.test(lineString)) return;
const targetX = target.getBoundingClientRect().left;
const cursorX = document.getElementsByClassName('cursor')0.getBoundingClientRect().left; if (cursorX <= targetX) {
keydownEvent.dispatch(39); // →
}
keydownEvent.dispatch(8); // Backspace
const newBox = (() => {
const trimmedLineString = lineString.trim();
for (let i = 0; i < checkBoxList.length; i++) {
if (trimmedLineString.startsWith(checkBoxListi)) { if (i + 1 < checkBoxList.length) {
return checkBoxListi + 1; } else {
}
}
}
})();
inputEvent.dispatch(newBox);
// この下のコメントアウトを解除すると、checked時に取消線を入れて時刻を追記します
// Mac、Porterでのみ動作します
if (/Mobile/.test(navigator.userAgent) || newBox === checkBoxList0) return; setTimeout(() => {
keydownEvent.dispatch(39, true, true); // shift + command + →
inputEvent.dispatch('-');
keydownEvent.dispatch(39, false, true); // command + →
const now = moment().format('HH:mm');
inputEvent.dispatch([, ( ${now} )]);
}, 50);
}, 50);
});
// ボックス行で改行すると次行にボックス自動挿入
$('#text-input').off('keydown.autoInsertCheckBox');
$('#text-input').on('keydown.autoInsertCheckBox', event => {
switch (event.key) {
case 'Enter': {
let lineString;
try {
lineString = getCursorLineString();
} catch (err) {
console.log(err);
return;
}
if (!startsWithBoxReg.test(lineString)) return;
setTimeout(() => {
let lineString;
try {
lineString = getCursorLineString();
} catch (err) {
console.log(err);
return;
}
if (!startsWithBoxReg.test(lineString)) {
inputEvent.dispatch(checkBoxList0); }
}, 50);
return;
}
default: {
return;
}
}
});
function isFirstElementChild(element) {
return element.parentNode.firstElementChild === element;
}
function getCursorLineString() {
return document.querySelector('.lines div.line.cursor-line').textContent;
}
}, 1500);
/customize/文字列を選択してScrapbox内検索
code:script.js
scrapbox.PopupMenu.addButton({
title: 'ドット太字',
onClick: text => text.split('\n').map(line => [. ${line}]).join('\n')
});
scrapbox.PopupMenu.addButton({
title: 'マーク',
onClick: text => text.split('\n').map(line => [# ${line}]).join('\n')
});
scrapbox.PopupMenu.addButton({
title: '見出し',
onClick: text => text.split('\n').map(line => [+ ${line}]).join('\n')
});
scrapbox.PopupMenu.addButton({
title: '画像縮小',
onClick: text => text.split('\n').map(line => [** ${line}]).join('\n')
});
scrapbox.PopupMenu.addButton({
title: '画像結合',
onClick: text => text.split('\n').map(line => [| ${line}]).join('\n')
});
scrapbox.PopupMenu.addButton({
title: '引用',
onClick: text => text.split('\n').map(line => code:quote \n ${line}).join('\n')
});
scrapbox.PopupMenu.addButton({
title: '検索',
onClick: function (text) {
var projectName = 'thinkingnote';
}
});
深いインデントをしまうスライダー
code:script.js
// 設定
// MAX_INDENT: 最大のインデント数を調整する
const MAX_INDENT=10
// それぞれの行にインデント数のclassをつける
scrapbox.Page.lines.map(l => {
return {id: l.id, indent: l.text.match(/^\s+/)}
}).forEach((l) => {
let indent;
if(l.indent == null) {
indent = 0;
} else {
indent = l.indent0.length; }
document.getElementById(L${l.id}).classList.add(indent-${indent})
})
// スライダーを作る関数
const createSlider = function() {
const slider = document.createElement('input');
slider.setAttribute('type', 'range');
slider.setAttribute('min', '0');
slider.setAttribute('max', MAX_INDENT);
slider.setAttribute('step', '1');
slider.setAttribute('type', 'range');
slider.setAttribute('value', '0');
let dom = document.createElement('div');
dom.appendChild(slider);
return dom;
};
// スタイルをつくる
const style = document.createElement('style');
style.type = 'text/css';
document.querySelector('head').appendChild(style);
const setCSS = function(level) {
let css = "";
for(var i=0; i < level; i++) {
css += .indent-${MAX_INDENT-i};
if(i < level - 1) {
css += ', ';
}
}
css += `{
display: none;
}`;
style.innerHTML = css;
};
// スライダーを追加する
const root = document.querySelector('.page-menu');
const slider = createSlider();
root.appendChild(slider);
// スライダーのインプットがあったらCSSを更新
slider.addEventListener('input', (e) => {
setCSS(e.target.valueAsNumber);
})
選択範囲をtweet
code:script.js
scrapbox.PopupMenu.addButton({
title: 'Tweet',
onClick: text => {
const lines = text
.map(line => line.replace(/[\\]/g, '').replace(/^\s+/, '')) const url = https://twitter.com/intent/tweet?&text=${encodeURIComponent(lines.join('\n'))}
const width = 550
const height = 420
const option = width=${width},height=${height},left=${(window.innerWidth - width) / 2},top=${(window.innerHeight - height) / 2},scrollbars=yes,resizable=yes,toolbar=no,location=yes
window.open(url, '_blank', option)
}
});
/thinkandcreateteck/禅モードZ (ZZen mote)
code:script.js
scrapbox.PageMenu.addItem({
title: 'Zen mode',
onClick: e => {
var bg = "#e2e2e2" // ここにお好きな背景色を入れてね(テーマの背景が黒なら black で)
var style = document.getElementById('__zen__')
if (style) { style.remove(); e.currentTarget.innerText = 'Zen mode'; return }
else e.currentTarget.innerText = String.fromCharCode(0x02713) + ' Zen mode'
var css = body, .page { background-color:${bg} !important; background-image:none !important } +
'.navbar:not(:hover), .line .telomere:not(:hover), .col-page-side:not(:hover) { opacity:0 }'
style = document.createElement('style')
style.setAttribute('id', '__zen__')
style.appendChild(document.createTextNode(css))
document.head.appendChild(style)
}
});
code:button.js
(function(){for(var g=0,c=document.querySelector(".lines"),c=c.querySelectorAll(".line"),d=!1,e=1;e<c.length;e++){var a=ce.querySelector(".text").cloneNode(!0),b=a.querySelector('img.iconsrc="/api/pages/icons/hr/icon"');if(d&&b)break;if(b)d=!0;else if(d){for(var b=a.querySelectorAll(".formula"),f=0;f<b.length;f++){var h=bf,k=h.querySelector("annotation");h.innerHTML=" $"+k.innerHTML+"$ "}a=a.innerText.trim().replace(/ /g,"");g+=a.length}}alert(g+" \u6587\u5b57")})(); code:script.js
p=0;
document.ontouchstart= function(e){
}
document.ontouchmove= function(e){
if(x-p>4){pressKey(39);p=x;}
if(p-x>4){pressKey(37);p=x;}
}
function pressKey( code ){
k = document.createEvent("Event");
k.initEvent( "keydown" ,true,true);
k.keyCode = code;
document.getElementById( "text-input" ).dispatchEvent(k);
}
code:script.js
const loadTitles = ({useLinks}) => {
fetch(/api/pages/${scrapbox.Project.name}/search/titles, {
credentials: 'same-origin'
}).then(res => {
return res.json()
}).then(data => {
let titles = data.map(p => p.title)
if (useLinks) {
data.map(p => {
p.links.map(l => {if (!titles.includes(l)) titles.push(l)})
})
}
titles = titles.sort((a, b) => b.length - a.length)
window.titles = titles
console.log('omakase-links-✨: load titles, links')
scrapbox.PopupMenu.addButton({
onClick: autoLink
})
})
}
// 既に記法になっているなどの理由で、置換すべきでない範囲を取得する
const detectLocked = text => {
const syntax = /\[*\.+?\\]*/g const locked = text.split('').map(c => false)
let res
while (res = syntax.exec(text)) {
}
return locked
}
const autoLink = text => {
if (!window.titles || !text) return text
const locked = detectLocked(text)
const matched = text.split('').map(c => null)
for (const title of window.titles) {
const regexp = new RegExp(escapeTitle(title), 'gi')
let res, found = false
while (!found && (res = regexp.exec(text))) {
const idx = res.index
if (matchedidx === null && !lockedidx) { found = true
for (let i = 0; i < len; i++) {
if (i === 0 || i === len - 1) {
if (i === 0) c = [${c}
if (i === len - 1) c = ${c}]
} else {
}
}
}
}
}
// 無駄にテロメアがupdateされるのを防ぐ為、何も置換しない時は何も返さない
if (matched.join('').length === 0) return
// 配列matchedでnullの位置を、元のtextの文字に置き換える
return matched.map((c, idx) => c === null ? textidx : c).join('') }
const escapeTitle = title => {
return title.replace(/[$-\/?-^{|}/g, '\\$&') }
// 置換候補をリアルタイムで更新できないのがツライところ
// しかし、毎回API呼んでると時間かかるので、ひとまず妥協
if (!window.titles) loadTitles({useLinks: true})
/public-minaph/Scrapboxリンクを同じタブで開く
code:script.js
scrapbox.on("lines:changed", () => {
});
/noratetsu/●別タブで開くリンクにアイコンを添える
code:style.css
.line span:not(.modal-image):not(.pointing-device-map) > a.link:not(.icon)::after,
font-family: 'Font Awesome 5 Free';
content: ' \f360';
font-weight: 900;
font-size: 0.9rem;
padding-right: 0.5rem;
display: inline-block;
}