codenothing/CSSTree

View on GitHub
demo/textarea.js

Summary

Maintainability
F
5 days
Test Coverage
// Textarea Helper from Codecademy
// https://github.com/Codecademy/textarea-helper
(function($) {
    var caretClass = 'textarea-helper-caret',
        dataKey = 'textarea-helper'

        // Styles that could influence size of the mirrored element.
        ,
        mirrorStyles = [
        // Box Styles.
        'box-sizing', 'height', 'width', 'padding-bottom', 'padding-left', 'padding-right', 'padding-top'

        // Font stuff.
        ,
        'font-family', 'font-size', 'font-style', 'font-variant', 'font-weight'

        // Spacing etc.
        ,
        'word-spacing', 'letter-spacing', 'line-height', 'text-decoration', 'text-indent', 'text-transform'];

    var TextareaHelper = function(elem) {
        if (elem.nodeName.toLowerCase() !== 'textarea') return;
        this.$text = $(elem);
        this.$mirror = $('<div/>')
            .css({
            'position': 'absolute',
            'overflow': 'auto',
            'white-space': 'pre-wrap',
            'word-wrap': 'break-word',
            'top': 0,
            'left': -9999
        })
            .insertAfter(this.$text);
    };

    (function() {
        this.update = function() {

            // Copy styles.
            var styles = {};
            for (var i = 0, style; style = mirrorStyles[i]; i++) {
                styles[style] = this.$text.css(style);
            }
            this.$mirror.css(styles)
                .empty();

            // Update content and insert caret.
            var caretPos = this.getOriginalCaretPos(),
                str = this.$text.val(),
                pre = document.createTextNode(str.substring(0, caretPos)),
                post = document.createTextNode(str.substring(caretPos)),
                $car = $('<span/>')
                    .addClass(caretClass)
                    .html(' ');
            this.$mirror.append(pre, $car, post)
                .scrollTop(this.$text.scrollTop());
        };

        this.destroy = function() {
            this.$mirror.remove();
            this.$text.removeData(dataKey);
            return null;
        };

        this.caretPos = function() {
            this.update();
            return this.$mirror.find('.' + caretClass)
                .position();
        };

        this.height = function() {
            this.update();
            this.$mirror.css('height', '');
            return this.$mirror.height();
        };

        // XBrowser caret position
        // Adapted from http://stackoverflow.com/questions/263743/how-to-get-caret-position-in-textarea
        this.getOriginalCaretPos = function() {
            var text = this.$text[0];
            if (text.selectionStart) {
                return text.selectionStart;
            } else if (document.selection) {
                text.focus();
                var r = document.selection.createRange();
                if (r == null) {
                    return 0;
                }
                var re = text.createTextRange(),
                    rc = re.duplicate();
                re.moveToBookmark(r.getBookmark());
                rc.setEndPoint('EndToStart', re);
                return rc.text.length;
            }
            return 0;
        };

    })
        .call(TextareaHelper.prototype);

    $.fn.textareaHelper = function(method) {
        this.each(function() {
            var $this = $(this),
                instance = $this.data(dataKey);
            if (!instance) {
                instance = new TextareaHelper(this);
                $this.data(dataKey, instance);
            }
        });
        if (method) {
            var instance = this.first()
                .data(dataKey);
            return instance[method]();
        } else {
            return this;
        }
    };

})(jQuery);