Page MenuHomePhabricator

D10280.id.diff
No OneTemporary

D10280.id.diff

diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css
--- a/webroot/rsrc/css/core/remarkup.css
+++ b/webroot/rsrc/css/core/remarkup.css
@@ -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;
diff --git a/webroot/rsrc/js/core/TextAreaUtils.js b/webroot/rsrc/js/core/TextAreaUtils.js
--- a/webroot/rsrc/js/core/TextAreaUtils.js
+++ b/webroot/rsrc/js/core/TextAreaUtils.js
@@ -1,5 +1,7 @@
/**
* @requires javelin-install
+ * javelin-dom
+ * javelin-vector
* @provides phabricator-textareautils
* @javelin
*/
@@ -44,6 +46,62 @@
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)
+ }
+ };
}
+
}
});

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 5, 6:19 PM (13 h, 5 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7226208
Default Alt Text
D10280.id.diff (3 KB)

Event Timeline