mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-29 08:50:58 +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-top-color: {$thinblueborder};
|
||||||
border-radius: 0;
|
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,
|
/* Prevent Safari and Chrome users from dragging the textarea any wider,
|
||||||
because the top bar won't resize along with it. */
|
because the top bar won't resize along with it. */
|
||||||
resize: vertical;
|
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 {
|
.remarkup-assist-textarea:focus {
|
||||||
border: 1px solid rgba(82, 168, 236, 0.8);
|
border: 1px solid rgba(82, 168, 236, 0.8);
|
||||||
}
|
}
|
||||||
|
@ -424,11 +442,6 @@
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.remarkup-assist-textarea {
|
|
||||||
box-shadow: none;
|
|
||||||
-webkit-box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.remarkup-control-fullscreen-mode {
|
.remarkup-control-fullscreen-mode {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: -1px;
|
top: -1px;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* @requires javelin-install
|
* @requires javelin-install
|
||||||
|
* javelin-dom
|
||||||
|
* javelin-vector
|
||||||
* @provides phabricator-textareautils
|
* @provides phabricator-textareautils
|
||||||
* @javelin
|
* @javelin
|
||||||
*/
|
*/
|
||||||
|
@ -44,6 +46,62 @@ JX.install('TextAreaUtils', {
|
||||||
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)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue