mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-20 03:31:10 +01:00
Kind-of-terrible (?) oncopy handler
Summary: Works in Safari, Firefox, Chrome. Test Plan: Copied some text, threw up a little in my mouth. Reviewers: aran, tuomaspelkonen, tomo, rstout, btrahan Reviewed By: aran CC: aran, epriestley, ddfisher Maniphest Tasks: T145, T995 Differential Revision: https://secure.phabricator.com/D244
This commit is contained in:
parent
fffc1e51d0
commit
57fd4bc68b
6 changed files with 103 additions and 2 deletions
|
@ -839,6 +839,17 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/application/core/behavior-object-selector.js',
|
||||
),
|
||||
'javelin-behavior-phabricator-oncopy' =>
|
||||
array(
|
||||
'uri' => '/res/70b9b75e/rsrc/js/application/core/behavior-oncopy.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/core/behavior-oncopy.js',
|
||||
),
|
||||
'javelin-behavior-phabricator-tooltips' =>
|
||||
array(
|
||||
'uri' => '/res/49f92a92/rsrc/js/application/core/behavior-tooltip.js',
|
||||
|
|
|
@ -1417,7 +1417,10 @@ final class DifferentialChangesetParser {
|
|||
'<th'.$o_id.'>'.$o_num.'</th>'.
|
||||
'<td'.$o_attr.'>'.$o_text.'</td>'.
|
||||
'<th'.$n_id.'>'.$n_num.'</th>'.
|
||||
'<td'.$n_attr.'>'.$n_text.'</td>'.
|
||||
// NOTE: This is a unicode zero-width space, which we use as a hint
|
||||
// when intercepting 'copy' events to make sure sensible text ends
|
||||
// up on the clipboard. See the 'phabricator-oncopy' behavior.
|
||||
'<td'.$n_attr.'>'."\xE2\x80\x8B".$n_text.'</td>'.
|
||||
$n_cov.
|
||||
'</tr>';
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ final class DifferentialChangesetDetailView extends AphrontView {
|
|||
require_celerity_resource('differential-changeset-view-css');
|
||||
require_celerity_resource('syntax-highlighting-css');
|
||||
|
||||
Javelin::initBehavior('phabricator-oncopy', array());
|
||||
|
||||
if ($this->revisionID) {
|
||||
$edit = true;
|
||||
} else {
|
||||
|
|
|
@ -142,6 +142,7 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController {
|
|||
|
||||
$text_list = explode("\n", $source);
|
||||
|
||||
Javelin::initBehavior('phabricator-oncopy', array());
|
||||
$rows = $this->buildDisplayRows($text_list);
|
||||
|
||||
$corpus_table = phutil_render_tag(
|
||||
|
@ -179,7 +180,10 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController {
|
|||
),
|
||||
$n);
|
||||
$rows[] = '<tr id="'.$anchor.'"><th>'.$link.'</th>'.
|
||||
'<td style="white-space: pre-wrap;">'.$line.'</td></tr>';
|
||||
'<td style="white-space: pre-wrap;">'.
|
||||
// NOTE: See the 'phabricator-oncopy' behavior.
|
||||
"\xE2\x80\x8B".
|
||||
$line.'</td></tr>';
|
||||
++$n;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ phutil_require_module('phabricator', 'applications/markup/syntax');
|
|||
phutil_require_module('phabricator', 'applications/paste/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/paste/storage/paste');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
|
||||
|
|
80
webroot/rsrc/js/application/core/behavior-oncopy.js
Normal file
80
webroot/rsrc/js/application/core/behavior-oncopy.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* @provides javelin-behavior-phabricator-oncopy
|
||||
* @requires javelin-behavior
|
||||
* javelin-dom
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tools like Paste and Differential don't normally respond to the clipboard
|
||||
* 'copy' operation well, because when a user copies text they'll get line
|
||||
* numbers and other metadata.
|
||||
*
|
||||
* To improve this behavior, applications can embed markers that delimit
|
||||
* metadata (left of the marker) from content (right of the marker). When
|
||||
* we get a copy event, we strip out all the metadata and just copy the
|
||||
* actual text.
|
||||
*/
|
||||
JX.behavior('phabricator-oncopy', function() {
|
||||
|
||||
var zws = "\u200B"; // Unicode Zero-Width Space
|
||||
|
||||
document.body.oncopy = function(e) {
|
||||
|
||||
var selection = window.getSelection();
|
||||
var text = selection.toString();
|
||||
|
||||
if (text.indexOf(zws) == -1) {
|
||||
// If there's no marker in the text, just let it copy normally.
|
||||
return;
|
||||
}
|
||||
|
||||
var result = [];
|
||||
|
||||
// Strip everything before the marker (and the marker itself) out of the
|
||||
// text. If a line doesn't have the marker, throw it away (the assumption
|
||||
// is that it's a line number or part of some other meta-text).
|
||||
var lines = text.split("\n");
|
||||
var pos;
|
||||
for (var ii = 0; ii < lines.length; ii++) {
|
||||
pos = lines[ii].indexOf(zws);
|
||||
if (pos == -1 && ii != 0) {
|
||||
continue;
|
||||
}
|
||||
result.push(lines[ii].substring(pos + 1));
|
||||
}
|
||||
result = result.join("\n");
|
||||
|
||||
if (e.clipboardData) {
|
||||
// Safari and Chrome support this easy, straightforward mechanism.
|
||||
e.clipboardData.setData('Text', result);
|
||||
e.preventDefault();
|
||||
} else {
|
||||
|
||||
// In Firefox, we have to create a <pre> and select the text in it, then
|
||||
// let the copy event fire. It has to be a <pre> because Firefox won't
|
||||
// copy returns properly out of a div, even if it has 'whitespace: pre'.
|
||||
// There's been a bug open for 10 (!) years:
|
||||
//
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=116083
|
||||
|
||||
var style = {
|
||||
position: 'absolute',
|
||||
left: '-10000px'
|
||||
};
|
||||
var pre = JX.$N('pre', style, result);
|
||||
document.body.appendChild(pre);
|
||||
|
||||
// Select the text in the <pre>.
|
||||
var range = document.createRange();
|
||||
range.selectNodeContents(pre);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
|
||||
setTimeout(function() { JX.DOM.remove(pre) }, 0);
|
||||
|
||||
// TODO: I tried to restore the old selection range but it doesn't seem
|
||||
// to work or give me any errors. So you lose your selection when you
|
||||
// copy. Oh well?
|
||||
}
|
||||
}
|
||||
});
|
Loading…
Reference in a new issue