txcommand extension
- カテゴリ:
- ChromeExtension
- コメント数:
- Comments: 0
◆ textarea (input でも) にスニペット風な入力でコマンド実行
◆ 単純にスニペット展開もできる
◆ ユーザスクリプトとして拡張機能から使いたいページに挿入する
◆ 単純にスニペット展開もできる
◆ ユーザスクリプトとして拡張機能から使いたいページに挿入する
textarea でコマンドを実行する拡張機能です
拡張機能というよりユーザスクリプトで 拡張機能に登録するものです
イメージはスニペット入力ツールで JavaScript 処理もできるようになったもの
で alert を表示したり
で
と入力したり ができます
もちろんなにするかは自分で定義するわけですけど
↓がサンプル兼テンプレート
start_marker や end_marker で開始と終了の文字を変更できます
textarea 以外でも許可する要素を指定できます
map にコマンドと処理を書きます
好きに JavaScript で処理できるので 直前の文字を見て連番作ったりもできます (expand)
関数じゃなくて文字列を指定するとその文字列に置き換えます
Gist
拡張機能というよりユーザスクリプトで 拡張機能に登録するものです
イメージはスニペット入力ツールで JavaScript 処理もできるようになったもの
@alert;
で alert を表示したり
@fn;
で
function(){
}
と入力したり ができます
もちろんなにするかは自分で定義するわけですけど
↓がサンプル兼テンプレート
start_marker や end_marker で開始と終了の文字を変更できます
textarea 以外でも許可する要素を指定できます
map にコマンドと処理を書きます
好きに JavaScript で処理できるので 直前の文字を見て連番作ったりもできます (expand)
関数じゃなくて文字列を指定するとその文字列に置き換えます
const snip_start_marker = "@"
const snip_end_marker = ";"
const accept_sources = [
"textarea", "input[type=text]"
]
const snimap = {
"test": "てすと",
"run"(elem){
console.log(elem)
},
"tabindent"(elem){
const pre = elem.value
elem.value = pre.replace(/^ {4,}/g, e =>
"\t".repeat(~~(e.length / 4)) + " ".repeat(e.length % 4))
if(elem.value !== pre){
elem.selectionStart = elem.selectionEnd = elem.value.length
}
},
"doctype"(elem){
const text = `<!doctype html>\n<meta charset="utf-8">\n`
elem.value = strinsert(elem.value, elem.selectionStart, text)
setCaret(elem, elem.selectionStart + text.length)
},
"expand"(elem){
let start
{
let i = elem.selectionStart
while(true){
const char = elem.value.charAt(--i)
if(char === "\n" || char === ""){
start = i + 1
break
}
}
}
const snivar = elem.value.slice(start, elem.selectionStart)
const matched = snivar.trim().match(/^(-?\d+) *\: *(-?\d+)$/)
if(!matched) return
const rstart = ~~matched[1]
const rend = ~~matched[2]
if(rstart > rend) return
const text = Array.from(Array(rend - rstart + 1), (e, i) => rstart + i).join("\n")
replaceElementText(elem, text, start, elem.selectionStart)
}
}
function strcut(str, start, end){
return str.substr(0, start) + str.substr(end)
}
function strinsert(str, index, text){
return str.substr(0, index) + text + str.substr(index)
}
function setCaret(elem, start, end = start){
elem.selectionStart = start
elem.selectionEnd = end
}
function replaceElementText(elem, text, start, end = start){
const inipos = elem.selectionStart
elem.value = strinsert(strcut(elem.value, start, end), start, text)
if(inipos >= start){
const newpos = start + text.length
setCaret(elem, newpos)
}
}
function checkSnip(elem){
if(!(elem.selectionStart === elem.selectionEnd && elem.selectionStart)){
return false
}
const end = elem.selectionStart
let start
{
let i = elem.selectionStart
while(true){
const char = elem.value.charAt(--i)
if(char === "\n" || char === ""){
return false
}
if(char === snip_start_marker){
start = i
break
}
}
}
const snip = elem.value.slice(start + 1, end)
if(!(snip in snimap)){
return false
}
return {start, end, key: snip}
}
window.addEventListener("keydown", eve => {
const elem = eve.target
const do_handle = accept_sources.some(e => eve.target.matches(e))
&& eve.key === snip_end_marker
if(!do_handle) return
const snip = checkSnip(elem)
if(!snip) return
const action = snimap[snip.key]
elem.value = strcut(elem.value, snip.start, snip.end)
setCaret(elem, snip.start)
if(typeof action === "string"){
elem.value = strinsert(elem.value, snip.start, action)
setCaret(elem, snip.start + action.length)
}else{
action(elem)
}
eve.preventDefault()
eve.stopPropagation()
}, true)
Gist