forked from Codecademy/textarea-helper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
textarea-helper.js
121 lines (104 loc) · 3.79 KB
/
textarea-helper.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
(function ($) {
'use strict';
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'
// The direction.
, 'direction'
];
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).css('position', 'absolute').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();
var $caret = this.$mirror.find('.' + caretClass)
, pos = $caret.position();
if (this.$text.css('direction') === 'rtl') {
pos.right = this.$mirror.innerWidth() - pos.left - $caret.width();
pos.left = 'auto';
}
return pos;
};
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);