HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptMinor

Script to convert Shift + Spacebar into four spaces on SE

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
scriptshiftconvertintofourspacesspacebar

Problem

I've posted this feature request and would like to improve the code involved to handle a few "bugs" (not that it's necessary to provide such code, just for my own practice), but I doubt I'm doing it as efficiently as possible with my updated conditions for the feature:

$("textarea").keydown(function (e) {
    if (e.shiftKey && e.keyCode == 32) {
        var white = " ",
            pad = "    ",
            t = this.value,
            n = this.selectionStart,
            s = this.scrollTop,
            r = [t.slice(0, n), t.slice(n)];
        if (r[0].indexOf(white, r[0].length - 1) !== -1) {
            this.value = r.join(pad);
            this.selectionStart = this.selectionEnd = n + pad.length;
            this.scrollTop = s;
            e.preventDefault();
        }
    }
});


Purpose:

-
Most importantly, Shift + Spacebar creates 4 spaces, cancelling the default space action.

-
Also to avoid accidental usage, it should not execute unless the character before the cursor is a space, or empty. (Avoids "XML is..." becoming "XML is..."). I couldn't figure out how to check for either whitespace OR a new line, so if someone could mention how that's done, it would be helpful, but if not I can always ask on SO.

-
To avoid a (reported) potential bug:


the scrollTop property of long textareas must be involved because re-setting the .value to insert the tab can cause a scroll [in some browsers]

Review

I'm looking for general improvements, best practices, shortening opportunities, simplification, etc. I'd particularly like to learn a better method / trick for figuring out if the previous character doesn't contain a non-space character rather than checking for either nothing or a space.

Solution

You can use charAt to grab the preceding character and check it against a space, newline, or empty string (the case when the cursor is at the start). But let's not stop there.

-
white and pad are okay enough (white is probably unnecessary, but space would be a better name since newlines are typically included in the generic term "whitespace"), but those other names are truly horrible!

-
You should probably maintain their full text selection--beginning and end.

Updated code:

$("textarea").keydown(function (e) {
    if (e.shiftKey && e.keyCode === 32) {
        var pad = "    ",
            text = this.value,
            start = this.selectionStart,
            end = this.selectionEnd,
            scroll = this.scrollTop,
            before = text.slice(0, start),
            after = text.slice(start),
            prevChar = before.charAt(before.length - 1);
        if (prevChar === "" || prevChar === " " || prevChar === "\n") {
            this.value = before + pad + after;
            this.selectionStart = start + pad.length;
            this.selectionEnd = end + pad.length;
            this.scrollTop = scroll;
            e.preventDefault();
        }
    }
});


Here are some future enhancement ideas:

-
Search for the preceding newline to ensure there is only whitespace before the cursor. This would fully stop expansion inside a sentence. Right now you can still insert four spaces in the middle right after a space.

-
Consider using ctrl + space so you can add ctrl + shift + space for outdenting.

-
Shift/unshift every selected line instead of just the cursor position. Right now the { } button can be wrangled to do shifting, but it's cumbersome since you have to put some non-space character on the first line to get indentation.

Code Snippets

$("textarea").keydown(function (e) {
    if (e.shiftKey && e.keyCode === 32) {
        var pad = "    ",
            text = this.value,
            start = this.selectionStart,
            end = this.selectionEnd,
            scroll = this.scrollTop,
            before = text.slice(0, start),
            after = text.slice(start),
            prevChar = before.charAt(before.length - 1);
        if (prevChar === "" || prevChar === " " || prevChar === "\n") {
            this.value = before + pad + after;
            this.selectionStart = start + pad.length;
            this.selectionEnd = end + pad.length;
            this.scrollTop = scroll;
            e.preventDefault();
        }
    }
});

Context

StackExchange Code Review Q#55531, answer score: 4

Revisions (0)

No revisions yet.