您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
An userscript to improve plain textarea for code editing.
当前为
// ==UserScript== // @name Textarea Plus // @description An userscript to improve plain textarea for code editing. // @namespace eight04.blogspot.com // @include http* // @version 1.1 // @grant GM_addStyle // ==/UserScript== "use strict"; var ignoreClassList = ["CodeMirror", "ace_editor"]; var textareaPlus = function(){ var editor = { indent: indent, unindent: unindent, home: home, selectHome: selectHome, enter: enter }; function selectionRange(data){ return data.pos[1] - data.pos[0]; } function takeRange(data) { if (data.pos[0] > data.pos[1]) { return [data.pos[1], data.pos[0]]; } return data.pos; } function insert(data, text){ var pos = takeRange(data); data.text = data.text.substr(0, pos[0]) + text + data.text.substr(pos[1]); data.pos[0] = pos[0] + text.length; data.pos[1] = data.pos[0]; } function del(data){ if (!selectionRange(data)) { data.pos[1]++; } insert(data, ""); } function getLineStart(data, pos){ if (pos == undefined) { pos = data.pos[1]; } if (data.text[pos] == "\n") { pos--; } var s = data.text.lastIndexOf("\n", pos); if (s < 0) { return 0; } return s + 1; } function getLineEnd(data, pos){ if (pos == undefined) { pos = data.pos[1]; } var s = data.text.indexOf("\n", pos); if (s < 0) { return data.text.length; } return s; } function multiIndent(data){ var pos = takeRange(data); var lineStart = getLineStart(data, pos[0]), lineEnd = getLineEnd(data, pos[1]); var lines = data.text.substr(lineStart, lineEnd - lineStart); lines = lines.split("\n"); for (var i = 0; i < lines.length; i++) { lines[i] = "\t" + lines[i]; } lines = lines.join("\n"); data.text = data.text.substr(0, lineStart) + lines + data.text.substr(lineEnd); if (data.pos[0] > data.pos[1]) { data.pos[1] = lineStart; data.pos[0] = lineEnd + i; } else { data.pos[0] = lineStart; data.pos[1] = lineEnd + i; } } function inMultiLine(data) { var pos = takeRange(data); var s = data.text.indexOf("\n", pos[0]); if (s < 0) { return false; } return s < pos[1]; } function indent(data){ if (!selectionRange(data)) { insert(data, "\t"); if (data.pos[0] < getTextStart(data)) { home(data); } } else { if (inMultiLine(data)) { multiIndent(data); } else { insert(data, "\t"); } } } function multiUnindent(data){ var pos = takeRange(data); var lineStart = getLineStart(data, pos[0]), lineEnd = getLineEnd(data, pos[1]); var lines = data.text.substr(lineStart, lineEnd - lineStart); lines = lines.split("\n"); var len = 0; for (var i = 0; i < lines.length; i++) { var m = lines[i].match(/^( {4}| {0,3}\t?)(.*)$/); // console.log(m); len += m[1].length; lines[i] = m[2]; } lines = lines.join("\n"); data.text = data.text.substr(0, lineStart) + lines + data.text.substr(lineEnd); if (data.pos[0] > data.pos[1]) { data.pos[1] = lineStart; data.pos[0] = lineEnd - len; } else { data.pos[0] = lineStart; data.pos[1] = lineEnd - len; } } function backspace(data) { if (selectionRange(data)) { del(data); } else if (data.pos[0] > 0) { data.pos[0]--; del(data); } } function unindent(data) { if (inMultiLine(data)) { multiUnindent(data); } else if (!selectionRange(data) && data.text[data.pos[0] - 1] == "\t") { backspace(data); } else { multiUnindent(data); home(data); } } function searchFrom(text, re, pos) { pos = pos || 0; var t = text.substr(pos); var s = t.search(re); if (s < 0) { return -1; } return s + pos; } function getTextStart(data, pos) { var lineStart = getLineStart(data, pos); pos = searchFrom(data.text, /[\S\n]/, lineStart); if (pos < 0 || data.text[pos] == "\n") { return getLineEnd(data); } return pos; } function isTextStart(data) { return getTextStart(data) == data.pos[1]; } function home(data) { if (isTextStart(data)) { data.pos[0] = getLineStart(data); } else { data.pos[0] = getTextStart(data); } data.pos[1] = data.pos[0]; } function selectHome(data) { var pos = data.pos[0]; home(data); data.pos[0] = pos; } function getIndents(data) { var pos = takeRange(data); var lineStart = getLineStart(data, pos[0]); var len; var textStart = getTextStart(data, pos[0]); // console.log(textStart); if (textStart >= pos[0]) { len = pos[0] - lineStart; } else { len = textStart - lineStart; } return data.text.substr(lineStart, len); } function enter(data) { // console.log(data); var indents = getIndents(data); insert(data, "\n" + indents); } function init(node, command) { var data = { text: node.value, pos: [node.selectionStart, node.selectionEnd] }, t; if (node.selectionDirection == "backward") { t = data.pos[0]; data.pos[0] = data.pos[1]; data.pos[1] = t; } editor[command](data); node.value = data.text; if (data.pos[0] > data.pos[1]) { node.setSelectionRange(data.pos[1], data.pos[0], "backward"); } else { node.setSelectionRange(data.pos[0], data.pos[1], "forward"); } } return init; }(); function validArea(area) { if (area.nodeName != "TEXTAREA") { return false; } if (area.dataset.textareaPlus === "false") { return false; } if (area.dataset.textareaPlus === "true") { return true; } // if (area.onkeydown) { // area.dataset.textareaPlus = "false"; // return false; // } var node = area, i; while ((node = node.parentNode) != document.body) { for (i = 0; i < ignoreClassList.length; i++) { if (node.classList.contains(ignoreClassList[i])) { area.dataset.textareaPlus = "false"; return false; } } } area.dataset.textareaPlus = "true"; return true; } window.addEventListener("keydown", function(e){ if (!validArea(e.target)) { return; } var command; if (e.keyCode == 9 && !e.ctrlKey && !e.altKey) { // tab if (e.shiftKey) { command = "unindent"; } else { command = "indent"; } } else if (e.keyCode == 13 && !e.ctrlKey && !e.altKey && !e.shiftKey) { // enter command = "enter"; } else if (e.keyCode == 36 && !e.ctrlKey && !e.altKey) { // home if (!e.shiftKey) { command = "home"; } else { command = "selectHome"; } } else { return; } e.preventDefault(); e.stopPropagation(); textareaPlus(e.target, command); }, true); GM_addStyle("textarea {tab-size: 4; -moz-tab-size: 4; -o-tab-size: 4;}");