scrapbox-cursor-jumper
新しいの作った
/icons/hr.icon
提供する関数
jumpToChar
指定した文字にcursorを移動させる
jumpToLF
指定した行の末尾にcursorを移動させる
2つともwindowのscrollを伴う
code
指定した文字にcursorを移動させる
リンク、code blockの先頭、画像、動画、tableがあるとjumpできない
code:script.js
/**
* @param {string} id - 移動したい行のid
* @param {number} index - 移動したい文字の番号 (span.c-{n}のnと同じ)
* XXKeyは同時に押しているとみなしたいmetaKeyを入れる
* @return {void}
*/
export function jumpToChar({id, index, margin = 0, shiftKey = false, ctrlKey = false, altKey = false} = {}) {
const char = document.getElementById(id).getElementsByClassName(c-${index})0; scrollToElement({element: char, margin: margin});
const {left, top, height} = char.getBoundingClientRect();
const mouseOptions = {
button: 0,
clientX: left,
clientY: top + height / 2,
bubbles: true,
cancelable: true,
shiftKey: shiftKey,
ctrlKey: ctrlKey,
altKey: altKey,
view: window
};
// cursorを移動する
char.dispatchEvent(new MouseEvent("mousedown", mouseOptions));
char.dispatchEvent(new MouseEvent("mouseup", mouseOptions));
}
指定した行の末尾にcursorを移動させる
任意の行で実行できる
動画、tableでは未確認 (多分動く)
2020-11-28 19:43:04 折返し行にも対応できるようになったはず
code:script.js
/**
* @param {string} id - 移動したい行のid
* XXKeyは同時に押しているとみなしたいmetaKeyを入れる
* @return {void}
*/
export function jumpToLF({id, margin = 0, shiftKey = false, ctrlKey = false, altKey = false} = {}) {
const line = document.getElementById(id).getElementsByClassName('text')0; //console.log('Go to %o', line);
scrollToElement({element: line, margin: margin});
const {right, top, height} = line.getBoundingClientRect();
const breakNum = getLineBreakNum({line: line});
//console.log(right = ${right}, top = ${top}, height = ${height}, breakNum = ${breakNum});
const mouseOptions = {
button: 0,
clientX: right,
clientY: top + height - height / (2 * breakNum),
bubbles: true,
cancelable: true,
shiftKey: shiftKey,
ctrlKey: ctrlKey,
altKey: altKey,
view: window
};
line.dispatchEvent(new MouseEvent("mousedown", mouseOptions));
line.dispatchEvent(new MouseEvent("mouseup", mouseOptions));
}
Utilites
指定した要素が画面内に表示されるように上下にscrollする
状況によってscroll方法を変える
既に画面内にある
何もしない
画面の下に隠れている
要素が画面の丁度下に見えるようにscrollする
画面の上に隠れている
要素が画面の丁度上に見えるようにする
option
margin
要素と画面枠との間隔
少し隙間を開けたいときにpixel単位で指定する
defaultは0
画面内に要素があるときは無視する
code:script.js
function scrollToElement({element, margin = 0} = {}) {
const {top, bottom} = element.getBoundingClientRect();
// 画面内なら何もしない
if (top >= margin && bottom + margin <= window.innerHeight) return;
// 画面の上に隠れているとき
if (top < margin) {
window.scrollBy(0, top - margin);
return;
}
// 画面の下に隠れているとき
if (bottom + margin > window.innerHeight) {
window.scrollBy(0, bottom + margin - window.innerHeight);
return;
}
}
画面上に描画されている実際の行数を取得する
何回折り返されているかを調べる
line: HTMLSpanElement
code:script.js
function getLineBreakNum({line}) {
if (!line) return undefined;
const lineHeight = parseInt(getComputedStyle(line).lineHeight);
const breakNum = Math.floor(line.getBoundingClientRect().height / lineHeight);
return breakNum < 1 ? 1: breakNum;
}
テストコード
code:test.js
import {installCDN} from '/api/code/villagepump/install-CDN/script.js'
import {jumpToLF} from '/api/code/takker/scrapbox-cursor-jumper/script.js';
(async () => {
await installCDN({id: 'mousetrap-for-scrapbox', src: '//cdnjs.cloudflare.com/ajax/libs/mousetrap/1.6.5/mousetrap.min.js'});
const editor = document.getElementById('editor');
const moustrapOnEdit = new Mousetrap(editor);
const lines = document.getElementsByClassName('lines')0; for (let i = 0; i < 10; i++) {
moustrapOnEdit.bind(alt+g ctrl+${i}, e =>{
_log(${e.key} is pressed.);
e.stopPropagation();
e.preventDefault();
jumpToLF({id: getLineId(i), margin: 50})
});
moustrapOnEdit.bind(alt+x ctrl+${i}, e =>{
_log(${e.key} is pressed.);
e.stopPropagation();
e.preventDefault();
jumpToLF({id: getLineId(lines.children.length - 1 - i), margin: 50})
});
}
function _log(msg, ...objects){
if (objects.length > 0) {
console.log([scrapbox-vim-bindings] ${msg}, objects);
return;
}
console.log([scrapbox-vim-bindings] ${msg});
}
function getLineId(number) {
return lines.childrennumber.id; }
})();
以下、試行錯誤
/icons/hr.icon
code:script_old.js
export function jumpCursor({id, index, shiftKey = false, ctrlKey = false, altKey = false} = {}) {
const char = document.getElementById(id).getElementsByClassName(c-${index})0; console.log(char);
const {left, top,width,height} = char.getBoundingClientRect();
const mouseOptions = {
button: 0,
clientX: left,
clientY: top,
bubbles: true,
cancelable: true,
shiftKey: shiftKey,
ctrlKey: ctrlKey,
altKey: altKey,
view: window
};
char.dispatchEvent(new MouseEvent("mousedown", mouseOptions));
char.dispatchEvent(new MouseEvent("mouseup", mouseOptions));
}
既知の問題
code blockの先頭には飛べない
リンクがあると正常に飛べない
リンクやcode blockの影響を受けないように、末尾にcursorを置いてみる
これでもうまく行かない
code:script_old.js
export function jumpCursor2({id, shiftKey = false, ctrlKey = false, altKey = false} = {}) {
const char = [...document.getElementById(id).querySelectorAll('spanclass^="c-"')].pop(); console.log(char);
const {right, top, height} = char.getBoundingClientRect();
const mouseOptions = {
button: 0,
clientX: right + 5, //すこし後ろにずらす
clientY: top + height/2,
bubbles: true,
cancelable: true,
shiftKey: shiftKey,
ctrlKey: ctrlKey,
altKey: altKey,
view: window
};
char.dispatchEvent(new MouseEvent("mousedown", mouseOptions));
char.dispatchEvent(new MouseEvent("mouseup", mouseOptions));
}
lineを直接押せないかな?
2020-11-24 12:24:17 押せた!
code:script_old.js
export function jumpLF({id, shiftKey = false, ctrlKey = false, altKey = false} = {}) {
const line = document.getElementById(id).getElementsByClassName('text')0; console.log(line);
const {right, top, height} = line.getBoundingClientRect();
const mouseOptions = {
button: 0,
clientX: right,
clientY: top + height/2,
bubbles: true,
cancelable: true,
shiftKey: shiftKey,
ctrlKey: ctrlKey,
altKey: altKey,
view: window
};
line.dispatchEvent(new MouseEvent("mousedown", mouseOptions));
line.dispatchEvent(new MouseEvent("mouseup", mouseOptions));
}
テストコードtakker.icon
code:test_old.js
import {installCDN} from '/api/code/villagepump/install-CDN/script.js'
import {jumpCursor, jumpCursor2, jumpLF} from '/api/code/takker/scrapbox-cursor-jumper/script_old.js';
test();
async function test() {
await installCDN({id: 'mousetrap-for-scrapbox', src: '//cdnjs.cloudflare.com/ajax/libs/mousetrap/1.6.5/mousetrap.min.js'});
const editor = document.getElementById('editor');
const moustrapOnEdit = new Mousetrap(editor);
const lines = document.getElementsByClassName('lines')0; for (let i = 0; i < 10; i++) {
moustrapOnEdit.bind(alt+g ctrl+${i}, e =>{
_log(${e.key} is pressed.);
e.stopPropagation();
e.preventDefault();
window.scroll(0,0);
jumpLF({id: getLineId(i)})
});
moustrapOnEdit.bind(alt+x ctrl+${i}, e =>{
_log(${e.key} is pressed.);
e.stopPropagation();
e.preventDefault();
const tailLine = lines.lastElementChild;
const {bottom} = tailLine.getBoundingClientRect();
window.scrollBy(0,bottom - window.innerHeight);
jumpLF({id: getLineId(lines.children.length - 1 - i)})
});
}
function _log(msg, ...objects){
if (objects.length > 0) {
console.log([scrapbox-vim-bindings] ${msg}, objects);
return;
}
console.log([scrapbox-vim-bindings] ${msg});
}
function getLineId(number) {
return lines.childrennumber.id; }
function getLastLineId() {
return lines.lastElementChild.id;
}
}