Skip to content

Commit

Permalink
changed textarea backtick wrapping to only act on selections (#313)
Browse files Browse the repository at this point in the history
- changed the backtick button in comment box to only add enclosing
  backticks on selected text, as I find the current behavior utterly
  irritating especially when trying to type a fenced code block
- activates the selection wrapping for single/double quote, and tilde
- activates the selection wrapping for underscore and asterisk, but it
  will cycle between 0,1,2 wrapping characters
  like this: `word` -> `*word*` -> `**word**` -> `word` -> ...
  • Loading branch information
asdfzdfj authored Nov 29, 2023
1 parent 1e35f5a commit f82241d
Showing 1 changed file with 24 additions and 15 deletions.
39 changes: 24 additions & 15 deletions assets/controllers/rich_textarea_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,37 @@ import {Controller} from '@hotwired/stimulus';
/* stimulusFetch: 'lazy' */
export default class extends Controller {
connect() {
this.element.addEventListener('keydown',
this.handleInput.bind(this));
this.element.addEventListener('keydown', this.handleInput.bind(this));
}

// map: allowed enclosure key -> max repeats
enclosureKeys = {
'`': 1, '~': 1, '"': 1, "'": 1,
'*': 2, '_': 2,
};

handleInput (event) {
let hasSelection = this.element.selectionStart != this.element.selectionEnd;
let key = event.key;

// ctrl + enter to submit form
if (event.ctrlKey && event.key === "Enter") {
if (event.ctrlKey && key === "Enter") {
this.element.form.submit();
}

// ctrl + b to toggle bold
else if (event.ctrlKey && event.key === "b") {
else if (event.ctrlKey && key === "b") {
this.toggleFormattingEnclosure('**');
}

// ctrl + i to toggle italic
else if (event.ctrlKey && event.key === "i") {
else if (event.ctrlKey && key === "i") {
this.toggleFormattingEnclosure('_');
}

// grave to toggle inline code
else if (event.key === "`") {
this.toggleFormattingEnclosure('`');
// toggle/cycle wrapping on selection texts
else if (hasSelection && key in this.enclosureKeys) {
this.toggleFormattingEnclosure(key, this.enclosureKeys[key] ?? 1);
}

else {
Expand All @@ -35,7 +43,7 @@ export default class extends Controller {
event.preventDefault();
}

toggleFormattingEnclosure(encl) {
toggleFormattingEnclosure(encl, maxLength = 1) {
const start = this.element.selectionStart, end = this.element.selectionEnd;
const ranged = start != end;
const before = this.element.value.substring(0, start),
Expand All @@ -45,18 +53,19 @@ export default class extends Controller {
// TODO: find a way to do undo-aware text manipulations that isn't deprecated like execCommand?
// it seems like specs never actually replaced it with anything unless i'm missing it

// remove an existing enclosure
if (before.endsWith(encl) && after.startsWith(encl)) {
this.element.selectionStart = start - encl.length;
this.element.selectionEnd = end + encl.length;
// remove enclosure when it's at the max
const finalEnclosure = encl.repeat(maxLength);
if (before.endsWith(finalEnclosure) && after.startsWith(finalEnclosure)) {
this.element.selectionStart = start - finalEnclosure.length;
this.element.selectionEnd = end + finalEnclosure.length;

// TODO: find a way to do this that isn't deprecated?
// it seems like this was never actually replaced by anything
document.execCommand('delete', false, null);
document.execCommand('insertText', false, inner);

this.element.selectionStart = start - encl.length;
this.element.selectionEnd = end - encl.length;
this.element.selectionStart = start - finalEnclosure.length;
this.element.selectionEnd = end - finalEnclosure.length;
}

// add a new enclosure
Expand Down

0 comments on commit f82241d

Please sign in to comment.