mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-28 00:10:57 +01:00
Add a Javascript method to find the pixel position of a range in a textarea
Summary: Ref T3725. This might eventually allow us to do `@username` typeaheads in textareas. Javascript!!! Test Plan: Dumped this into console and got a "<<<" at the caret position in Safari, Firefox and Chrome. ``` setInterval(function() { var area = JX.$('comment-content'); var r = JX.TextAreaUtils.getSelectionRange(area); var d = JX.TextAreaUtils.getPixelDimensions(area, r.start, r.end); JX.log(d); try { JX.DOM.remove(JX.$('ptr')); } catch (_) {} document.body.appendChild( JX.$N( 'div', {id: "ptr", style: { position: 'absolute', left: d.start.x + 'px', top: d.start.y + 'px', zIndex: 9999, border: '2px solid red' }}, '<<<')); }, 1000); ``` Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T3725 Differential Revision: https://secure.phabricator.com/D10280
This commit is contained in:
parent
1652e07b4d
commit
fe042def42
2 changed files with 76 additions and 5 deletions
|
@ -339,11 +339,29 @@
|
|||
border-top-color: {$thinblueborder};
|
||||
border-radius: 0;
|
||||
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
|
||||
/* Set line height explicitly so the metrics <var /> and the real textarea
|
||||
are forced to the same value. */
|
||||
line-height: 1.25em;
|
||||
|
||||
/* Prevent Safari and Chrome users from dragging the textarea any wider,
|
||||
because the top bar won't resize along with it. */
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
var.remarkup-assist-textarea {
|
||||
/* This is an invisible element used to measure the size of text in the
|
||||
textarea so we can float typeaheads over the cursor position. */
|
||||
display: block;
|
||||
border-color: orange;
|
||||
box-sizing: border-box;
|
||||
padding: 4px 6px;
|
||||
white-space: pre-wrap;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.remarkup-assist-textarea:focus {
|
||||
border: 1px solid rgba(82, 168, 236, 0.8);
|
||||
}
|
||||
|
@ -424,11 +442,6 @@
|
|||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.remarkup-assist-textarea {
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
}
|
||||
|
||||
.remarkup-control-fullscreen-mode {
|
||||
position: fixed;
|
||||
top: -1px;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/**
|
||||
* @requires javelin-install
|
||||
* javelin-dom
|
||||
* javelin-vector
|
||||
* @provides phabricator-textareautils
|
||||
* @javelin
|
||||
*/
|
||||
|
@ -44,6 +46,62 @@ JX.install('TextAreaUtils', {
|
|||
area.value = v;
|
||||
|
||||
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)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue