TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
9.9 KiB
263 lines
9.9 KiB
function bindCodeEditorShortcutKeys(textarea) {
|
|
|
|
// applying shortcut keys
|
|
textarea.addEventListener('keydown', function (e) {
|
|
|
|
// [Enter] key pressed detected
|
|
if (e.key === 'Enter') {
|
|
|
|
// Prevent the default behavior (new line)
|
|
e.preventDefault();
|
|
|
|
// Get the cursor position
|
|
var cursorPos = textarea.selectionStart;
|
|
|
|
// Get the previous line
|
|
var prevLine = textarea.value.substring(0, cursorPos).split('\n').slice(-1)[0];
|
|
|
|
// Get the indentation of the previous line
|
|
var indent = prevLine.match(/^\s*/)[0];
|
|
|
|
// Add a new line with the same indentation
|
|
textarea.setRangeText('\n' + indent, cursorPos, cursorPos, 'end');
|
|
|
|
// remove focus
|
|
textarea.blur();
|
|
|
|
// regain focus (this is force the textarea scroll to caret position in case the caret falls out the textarea visible area)
|
|
textarea.focus();
|
|
|
|
// copy the code from textarea to code block
|
|
updateCode();
|
|
return;
|
|
}
|
|
|
|
// [Tab] pressed, but no [Shift]
|
|
if (e.key === "Tab" && !e.shiftKey &&
|
|
|
|
// and no highlight detected
|
|
textarea.selectionStart == textarea.selectionEnd) {
|
|
|
|
// suspend default behaviour
|
|
e.preventDefault();
|
|
|
|
// Get the current cursor position
|
|
let cursorPosition = textarea.selectionStart;
|
|
|
|
// Insert 4 white spaces at the cursor position
|
|
let newValue = textarea.value.substring(0, cursorPosition) + " " +
|
|
textarea.value.substring(cursorPosition);
|
|
|
|
// Update the textarea value and cursor position
|
|
textarea.value = newValue;
|
|
textarea.selectionStart = textarea.selectionEnd = cursorPosition + 4;
|
|
|
|
// copy the code from textarea to code block
|
|
updateCode();
|
|
return;
|
|
}
|
|
|
|
// [Tab] and [Shift] keypress presence
|
|
if (e.key === "Tab" && e.shiftKey &&
|
|
|
|
// no highlight detected
|
|
textarea.selectionStart == textarea.selectionEnd) {
|
|
|
|
// suspend default behaviour
|
|
e.preventDefault();
|
|
|
|
// Get the current cursor position
|
|
let cursorPosition = textarea.selectionStart;
|
|
|
|
// Check the previous characters for spaces
|
|
let leadingSpaces = 0;
|
|
for (let i = 0; i < 4; i++) {
|
|
if (textarea.value[cursorPosition - i - 1] === " ") {
|
|
leadingSpaces++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (leadingSpaces > 0) {
|
|
// Remove the spaces
|
|
let newValue = textarea.value.substring(0, cursorPosition - leadingSpaces) +
|
|
textarea.value.substring(cursorPosition);
|
|
|
|
// Update the textarea value and cursor position
|
|
textarea.value = newValue;
|
|
textarea.selectionStart = textarea.selectionEnd = cursorPosition - leadingSpaces;
|
|
}
|
|
|
|
// copy the code from textarea to code block
|
|
updateCode();
|
|
return;
|
|
}
|
|
|
|
// [Tab] key pressed and range selection detected
|
|
if (e.key == 'Tab' & textarea.selectionStart != textarea.selectionEnd) {
|
|
e.preventDefault();
|
|
|
|
// split the textarea content into lines
|
|
let lines = textarea.value.split('\n');
|
|
|
|
// find the start/end lines
|
|
let startPos = textarea.value.substring(0, textarea.selectionStart).split('\n').length - 1;
|
|
let endPos = textarea.value.substring(0, textarea.selectionEnd).split('\n').length - 1;
|
|
|
|
// calculating total removed white spaces
|
|
// these values will be used for adjusting new cursor position
|
|
let spacesRemovedFirstLine = 0;
|
|
let spacesRemoved = 0;
|
|
|
|
// [Shift] key was pressed (this means we're un-indenting)
|
|
if (e.shiftKey) {
|
|
|
|
// iterate over all lines
|
|
for (let i = startPos; i <= endPos; i++) {
|
|
|
|
// /^ = from the start of the line,
|
|
// {1,4} = remove in between 1 to 4 white spaces that may existed
|
|
lines[i] = lines[i].replace(/^ {1,4}/, function (match) {
|
|
|
|
// "match" is a string (white space) extracted
|
|
|
|
// obtaining total white spaces removed
|
|
|
|
// total white space removed at first line
|
|
if (i == startPos)
|
|
spacesRemovedFirstLine = match.length;
|
|
|
|
// total white space removed overall
|
|
spacesRemoved += match.length;
|
|
|
|
return '';
|
|
});
|
|
}
|
|
}
|
|
|
|
// no shift key, so we're indenting
|
|
else {
|
|
// iterate over all lines
|
|
for (let i = startPos; i <= endPos; i++) {
|
|
// add a tab to the start of the line
|
|
lines[i] = ' ' + lines[i]; // four spaces
|
|
}
|
|
}
|
|
|
|
// remember the cursor position
|
|
let start = textarea.selectionStart;
|
|
let end = textarea.selectionEnd;
|
|
|
|
// put the modified lines back into the textarea
|
|
textarea.value = lines.join('\n');
|
|
|
|
// adjust the position of cursor start selection
|
|
textarea.selectionStart = e.shiftKey ?
|
|
start - spacesRemovedFirstLine : start + 4;
|
|
|
|
// adjust the position of cursor end selection
|
|
textarea.selectionEnd = e.shiftKey ?
|
|
end - spacesRemoved : end + 4 * (endPos - startPos + 1);
|
|
|
|
// copy the code from textarea to code block
|
|
updateCode();
|
|
return;
|
|
}
|
|
|
|
// [Shift] + [Del]/[Backspace] = Delete entire line(s)
|
|
if (e.shiftKey && (e.key === "Delete" || e.key === "Backspace")) {
|
|
|
|
e.preventDefault();
|
|
|
|
// find the start/end lines
|
|
let startPos = textarea.value.substring(0, textarea.selectionStart).split('\n').length - 1;
|
|
let endPos = textarea.value.substring(0, textarea.selectionEnd).split('\n').length - 1;
|
|
|
|
// get the line and the position in that line where the cursor is
|
|
// pop() = take out the last line (which is the cursor selection start located)
|
|
let cursorLine = textarea.value.substring(0, textarea.selectionStart).split('\n').pop();
|
|
|
|
// get the position of cursor within the last line
|
|
let cursorPosInLine = cursorLine.length;
|
|
|
|
// calculating total lines to be removed
|
|
let totalLinesRemove = endPos - startPos + 1;
|
|
|
|
// split the textarea content into lines
|
|
let lines = textarea.value.split('\n');
|
|
|
|
// calculate new cursor position
|
|
let newStart = lines.slice(0, startPos).join('\n').length + (startPos > 0 ? 1 : 0);
|
|
// add 1 if startPos > 0 to account for '\n' character
|
|
|
|
// remove the selected lines
|
|
lines.splice(startPos, totalLinesRemove);
|
|
|
|
// get the new line where the cursor will be after deleting lines
|
|
// if lines[startPos] is not existed, then the new line will be an empty string
|
|
let newLine = lines[startPos] || '';
|
|
|
|
// if the new line is shorter than the cursor position, put the cursor at the end of the line
|
|
if (newLine.length < cursorPosInLine) {
|
|
cursorPosInLine = newLine.length;
|
|
}
|
|
|
|
// adjuct the cursor's position in the line to the new cursor position
|
|
newStart += cursorPosInLine;
|
|
|
|
// put the modified lines back into the textarea
|
|
textarea.value = lines.join('\n');
|
|
|
|
// set the new cursor position
|
|
// both cursor selection start and end will be at the same position
|
|
textarea.selectionStart = textarea.selectionEnd = newStart;
|
|
|
|
// copy the code from textarea to code block
|
|
updateCode();
|
|
|
|
return;
|
|
}
|
|
|
|
// Move cursor to the first non-white space character
|
|
if (e.key === "Home") {
|
|
|
|
// get the line and the position in that line where the cursor is
|
|
// pop() = take out the last line (which is the cursor selection start located)
|
|
let line = textarea.value.substring(0, textarea.selectionStart).split('\n').pop();
|
|
|
|
// get the position of cursor within the last line
|
|
let cursorPosInLine = line.length;
|
|
|
|
// Find the start of the current line
|
|
let lineStartPos = textarea.value.substring(0, textarea.selectionStart).lastIndexOf('\n') + 1;
|
|
|
|
// Find the first non-whitespace character on the line
|
|
let firstNonWhitespacePos = line.search(/\S/);
|
|
|
|
// the cursor's position is already in front of first non-whitespace character,
|
|
// or it's position is before first none-whitespace character,
|
|
// move the cursor to the start of line
|
|
if (firstNonWhitespacePos >= cursorPosInLine) {
|
|
// do nothing, perform default behaviour, which is moving the cursor to beginning of the line
|
|
return true;
|
|
}
|
|
// If there's no non-whitespace character, this is an empty or whitespace-only line
|
|
else if (firstNonWhitespacePos === -1) {
|
|
// do nothing, perform default behaviour, which is moving the cursor to beginning of the line
|
|
return true;
|
|
}
|
|
|
|
// Prevent the default Home key behavior
|
|
e.preventDefault();
|
|
|
|
// Move the cursor to the position of the first non-whitespace character
|
|
textarea.selectionStart = textarea.selectionEnd = lineStartPos + firstNonWhitespacePos;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
});
|
|
|
|
} |