Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/webroot/rsrc/js/core/TextAreaUtils.js
12241 views
1
/**
2
* @requires javelin-install
3
* javelin-dom
4
* javelin-vector
5
* @provides phabricator-textareautils
6
* @javelin
7
*/
8
9
JX.install('TextAreaUtils', {
10
statics : {
11
getSelectionRange : function(area) {
12
var v = area.value;
13
14
// NOTE: This works well in Safari, Firefox and Chrome. We'll probably get
15
// less-good behavior on IE.
16
17
var s = v.length;
18
var e = v.length;
19
20
if ('selectionStart' in area) {
21
s = area.selectionStart;
22
e = area.selectionEnd;
23
}
24
25
return {start: s, end: e};
26
},
27
28
getSelectionText : function(area) {
29
var v = area.value;
30
var r = JX.TextAreaUtils.getSelectionRange(area);
31
return v.substring(r.start, r.end);
32
},
33
34
setSelectionRange : function(area, start, end) {
35
if ('setSelectionRange' in area) {
36
37
// Chrome scrolls the textarea to the bottom as a side effect of
38
// calling focus(), so save the scroll position, focus, then restore
39
// the scroll position.
40
var scroll_top = area.scrollTop;
41
area.focus();
42
area.scrollTop = scroll_top;
43
44
area.setSelectionRange(start, end);
45
}
46
},
47
48
setSelectionText : function(area, text, select) {
49
var v = area.value;
50
var r = JX.TextAreaUtils.getSelectionRange(area);
51
52
v = v.substring(0, r.start) + text + v.substring(r.end, v.length);
53
area.value = v;
54
55
var start = r.start;
56
var end = r.start + text.length;
57
58
if (!select) {
59
start = end;
60
}
61
62
JX.TextAreaUtils.setSelectionRange(area, start, end);
63
},
64
65
66
/**
67
* Insert a reference to a given uploaded file into a textarea.
68
*/
69
insertFileReference: function(area, file) {
70
var ref = '{F' + file.getID() + '}';
71
72
// If we're inserting immediately after a "}" (usually, another file
73
// reference), put some newlines before our token so that multiple file
74
// uploads get laid out more nicely.
75
var range = JX.TextAreaUtils.getSelectionRange(area);
76
var before = area.value.substring(0, range.start);
77
if (before.match(/\}$/)) {
78
ref = '\n\n' + ref;
79
}
80
81
JX.TextAreaUtils.setSelectionText(area, ref, false);
82
},
83
84
85
/**
86
* Get the document pixel positions of the beginning and end of a character
87
* range in a textarea.
88
*/
89
getPixelDimensions: function(area, start, end) {
90
var v = area.value;
91
92
// We're using zero-width spaces to make sure the spans get some
93
// height even if there's no text in the metrics tag.
94
95
var head = v.substring(0, start);
96
var before = JX.$N('span', {}, '\u200b');
97
var body = v.substring(start, end);
98
var after = JX.$N('span', {}, '\u200b');
99
100
// Create a similar shadow element which we can measure.
101
var metrics = JX.$N(
102
'var',
103
{
104
className: area.className,
105
},
106
[head, before, body, after]);
107
108
// If the textarea has a scrollbar, force a scrollbar on the shadow
109
// element too.
110
if (area.scrollHeight > area.clientHeight) {
111
metrics.style.overflowY = 'scroll';
112
}
113
114
area.parentNode.appendChild(metrics);
115
116
// Adjust the positions we read out of the document to account for the
117
// current scroll position of the textarea.
118
var metrics_pos = JX.Vector.getPos(metrics);
119
metrics_pos.x += area.scrollLeft;
120
metrics_pos.y += area.scrollTop;
121
122
var area_pos = JX.Vector.getPos(area);
123
var before_pos = JX.Vector.getPos(before);
124
var after_pos = JX.Vector.getPos(after);
125
126
JX.DOM.remove(metrics);
127
128
return {
129
start: {
130
x: area_pos.x + (before_pos.x - metrics_pos.x),
131
y: area_pos.y + (before_pos.y - metrics_pos.y)
132
},
133
end: {
134
x: area_pos.x + (after_pos.x - metrics_pos.x),
135
y: area_pos.y + (after_pos.y - metrics_pos.y)
136
}
137
};
138
}
139
140
}
141
});
142
143