Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/js/core/TextAreaUtils.js
/** | /** | ||||
* @requires javelin-install | * @requires javelin-install | ||||
* javelin-dom | |||||
* javelin-vector | |||||
* @provides phabricator-textareautils | * @provides phabricator-textareautils | ||||
* @javelin | * @javelin | ||||
*/ | */ | ||||
JX.install('TextAreaUtils', { | JX.install('TextAreaUtils', { | ||||
statics : { | statics : { | ||||
getSelectionRange : function(area) { | getSelectionRange : function(area) { | ||||
var v = area.value; | var v = area.value; | ||||
Show All 28 Lines | statics : { | ||||
setSelectionText : function(area, text) { | setSelectionText : function(area, text) { | ||||
var v = area.value; | var v = area.value; | ||||
var r = JX.TextAreaUtils.getSelectionRange(area); | var r = JX.TextAreaUtils.getSelectionRange(area); | ||||
v = v.substring(0, r.start) + text + v.substring(r.end, v.length); | v = v.substring(0, r.start) + text + v.substring(r.end, v.length); | ||||
area.value = v; | area.value = v; | ||||
JX.TextAreaUtils.setSelectionRange(area, r.start, r.start + text.length); | JX.TextAreaUtils.setSelectionRange(area, r.start, r.start + text.length); | ||||
}, | |||||
/** | |||||
* Get the document pixel positions of the beginning and end of a character | |||||
* range in a textarea. | |||||
*/ | |||||
getPixelDimensions: function(area, start, end) { | |||||
var v = area.value; | |||||
// We're using zero-width spaces to make sure the spans get some | |||||
// height even if there's no text in the metrics tag. | |||||
var head = v.substring(0, start); | |||||
var before = JX.$N('span', {}, '\u200b'); | |||||
var body = v.substring(start, end); | |||||
var after = JX.$N('span', {}, '\u200b'); | |||||
// Create a similar shadow element which we can measure. | |||||
var metrics = JX.$N( | |||||
'var', | |||||
{ | |||||
className: area.className, | |||||
}, | |||||
[head, before, body, after]); | |||||
// If the textarea has a scrollbar, force a scrollbar on the shadow | |||||
// element too. | |||||
if (area.scrollHeight > area.clientHeight) { | |||||
metrics.style.overflowY = 'scroll'; | |||||
} | } | ||||
area.parentNode.appendChild(metrics); | |||||
// Adjust the positions we read out of the document to account for the | |||||
// current scroll position of the textarea. | |||||
var metrics_pos = JX.Vector.getPos(metrics); | |||||
metrics_pos.x += area.scrollLeft; | |||||
metrics_pos.y += area.scrollTop; | |||||
var area_pos = JX.Vector.getPos(area); | |||||
var before_pos = JX.Vector.getPos(before); | |||||
var after_pos = JX.Vector.getPos(after); | |||||
JX.DOM.remove(metrics); | |||||
return { | |||||
start: { | |||||
x: area_pos.x + (before_pos.x - metrics_pos.x), | |||||
y: area_pos.y + (before_pos.y - metrics_pos.y) | |||||
}, | |||||
end: { | |||||
x: area_pos.x + (after_pos.x - metrics_pos.x), | |||||
y: area_pos.y + (after_pos.y - metrics_pos.y) | |||||
} | |||||
}; | |||||
} | |||||
} | } | ||||
}); | }); |