Page MenuHomePhorge

D25966.1745389752.diff
No OneTemporary

D25966.1745389752.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -9,7 +9,7 @@
'names' => array(
'conpherence.pkg.css' => '3144a5e2',
'conpherence.pkg.js' => '020aebcf',
- 'core.pkg.css' => '10815c8e',
+ 'core.pkg.css' => '6a84521c',
'core.pkg.js' => 'f58c3c6e',
'dark-console.pkg.js' => '187792c2',
'differential.pkg.css' => '91ac6214',
@@ -109,7 +109,7 @@
'rsrc/css/application/tokens/tokens.css' => 'ce5a50bd',
'rsrc/css/application/uiexample/example.css' => 'b4795059',
'rsrc/css/core/core.css' => '531ad849',
- 'rsrc/css/core/remarkup.css' => '03b6c819',
+ 'rsrc/css/core/remarkup.css' => 'b4f2c357',
'rsrc/css/core/syntax.css' => '548567f6',
'rsrc/css/core/z-index.css' => 'ac3bfcd4',
'rsrc/css/diviner/diviner-shared.css' => '4bd263b0',
@@ -460,6 +460,7 @@
'rsrc/js/core/MultirowRowManager.js' => '5b54c823',
'rsrc/js/core/Notification.js' => 'a9b91e3f',
'rsrc/js/core/Prefab.js' => '5793d835',
+ 'rsrc/js/core/RemarkupCodeblockCopy.js' => '22a8ed50',
'rsrc/js/core/RemarkupMetadata.js' => 'e40c4991',
'rsrc/js/core/ShapedRequest.js' => '995f5102',
'rsrc/js/core/TextAreaUtils.js' => 'f340a484',
@@ -532,6 +533,7 @@
'rsrc/js/phuix/PHUIXIconView.js' => 'a5257c4e',
),
'symbols' => array(
+ 'RemarkupCodeblockCopy' => '22a8ed50',
'almanac-css' => '2e050f4f',
'aphront-bars' => '4a327b4a',
'aphront-dark-console-css' => '7f06cda2',
@@ -797,7 +799,7 @@
'phabricator-object-selector-css' => 'ee77366f',
'phabricator-phtize' => '2f1db1ed',
'phabricator-prefab' => '5793d835',
- 'phabricator-remarkup-css' => '03b6c819',
+ 'phabricator-remarkup-css' => 'b4f2c357',
'phabricator-remarkup-metadata' => 'e40c4991',
'phabricator-search-results-css' => '9ea70ace',
'phabricator-shaped-request' => '995f5102',
diff --git a/src/applications/phame/controller/post/PhamePostViewController.php b/src/applications/phame/controller/post/PhamePostViewController.php
--- a/src/applications/phame/controller/post/PhamePostViewController.php
+++ b/src/applications/phame/controller/post/PhamePostViewController.php
@@ -87,6 +87,8 @@
),
$engine->getOutput($post, PhamePost::MARKUP_FIELD_BODY)));
+ require_celerity_resource('RemarkupCodeblockCopy');
+
$blogger = id(new PhabricatorPeopleQuery())
->setViewer($viewer)
->withPHIDs(array($post->getBloggerPHID()))
diff --git a/src/infrastructure/markup/view/PHUIRemarkupView.php b/src/infrastructure/markup/view/PHUIRemarkupView.php
--- a/src/infrastructure/markup/view/PHUIRemarkupView.php
+++ b/src/infrastructure/markup/view/PHUIRemarkupView.php
@@ -89,6 +89,7 @@
$viewer,
$context);
+ require_celerity_resource('RemarkupCodeblockCopy');
return $content;
}
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
@@ -913,3 +913,39 @@
left: 0;
right: 0;
}
+
+.phui-font-fa.fa-spinner {
+ animation: spin .5s linear infinite;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+.remarkup-code-block {
+ position: relative;
+}
+
+.remarkup-code-block .phui-font-fa.btn-clipboard {
+ position: absolute;
+ top: -16px;
+ right: 0px;
+ text-decoration: none;
+}
+
+.remarkup-code-block .phui-font-fa.btn-clipboard.fa-spinner {
+ color: {$darkbluetext};
+}
+
+.remarkup-code-block .phui-font-fa.btn-clipboard.fa-clipboard {
+ color: {$darkgreybackground};
+}
+
+.remarkup-code-block.has-header .phui-font-fa.btn-clipboard {
+ top: 16px;
+}
+
+.remarkup-code-block .phui-font-fa.btn-clipboard:hover {
+ color: {$darkbluetext};
+}
diff --git a/webroot/rsrc/js/core/RemarkupCodeblockCopy.js b/webroot/rsrc/js/core/RemarkupCodeblockCopy.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/core/RemarkupCodeblockCopy.js
@@ -0,0 +1,126 @@
+/**
+ * @provides RemarkupCodeblockCopy
+ */
+
+JX.onload(function() {
+ var pageBody = document.querySelector('.phabricator-standard-page-body');
+
+ var codeBlocks = Array.from(
+ document.querySelectorAll('.remarkup-code-block')
+ );
+
+ for (var codeBlockIndex in codeBlocks) {
+ var codeBlock = codeBlocks[codeBlockIndex];
+
+ var button = document.createElement('a');
+ button.id = 'codeBlock-' + codeBlockIndex;
+ button.href = '#';
+ button.classList.add('phui-font-fa');
+ button.classList.add('btn-clipboard');
+ button.classList.add('fa-clipboard');
+ codeBlock.appendChild(button);
+
+ if (codeBlock.querySelector('.remarkup-code-header')) {
+ codeBlock.classList.add('has-header');
+ }
+
+ button.addEventListener('click', function(e) {
+ var button = e.target;
+ var codeBlock = button.closest('.remarkup-code-block');
+
+ e.preventDefault();
+
+ // show animated icon
+ button.classList.remove('fa-clipboard');
+ button.classList.add('fa-spinner');
+
+ // start copy to clipboard
+ var code = codeBlock.querySelector('pre');
+ if (!code) {
+ code = '';
+ } else {
+ code = code.innerText;
+ }
+
+ var temp = document.createElement('div');
+ temp.innerHTML = code;
+ var text = temp.textContent || temp.innerText;
+ if (!text) {
+ return;
+ }
+
+ if (navigator.clipboard) {
+ navigator.clipboard.writeText(text.trim()).catch(function(err) {
+ // restore icon
+ button.classList.remove('fa-spinner');
+ button.classList.add('fa-clipboard');
+ });
+ } else {
+ var textarea = document.createElement('textarea');
+ textarea.value = text.trim();
+ textarea.style.position = 'fixed';
+ textarea.style.opacity = '0';
+ document.body.appendChild(textarea);
+ textarea.focus();
+ textarea.select();
+ try {
+ var success = document.execCommand('copy');
+ if (success) {
+ setTimeout(function() {
+ // restore icon
+ button.classList.remove('fa-spinner');
+ button.classList.add('fa-clipboard');
+ }, 500);
+ } else {
+ // restore icon
+ button.classList.remove('fa-spinner');
+ button.classList.add('fa-clipboard');
+ }
+ } catch (err) {
+ // restore icon
+ button.classList.remove('fa-spinner');
+ button.classList.add('fa-clipboard');
+ }
+ document.body.removeChild(textarea);
+ }
+
+ });
+
+ button.addEventListener('mouseenter', function(e) {
+ var button = e.target;
+
+ var tooltipContainer = document.createElement('div');
+ tooltipContainer.id = 'tooltip-' + button.id;
+ tooltipContainer.classList.add('jx-tooltip-container');
+ tooltipContainer.classList.add('jx-tooltip-align-N');
+ tooltipContainer.classList.add('jx-tooltip-appear');
+ tooltipContainer.style.maxWidth = '160px';
+
+ var tooltipInner = document.createElement('div');
+ tooltipInner.classList.add('jx-tooltip-inner');
+ tooltipContainer.appendChild(tooltipInner);
+
+ var tooltip = document.createElement('div');
+ tooltip.classList.add('jx-tooltip');
+ tooltip.innerText = 'Copy to clipboard';
+ tooltipInner.appendChild(tooltip);
+
+ var rect = button.getBoundingClientRect();
+ tooltipContainer.style.left = (rect.x + window.scrollX - 58) + 'px';
+ tooltipContainer.style.top = (rect.y + window.scrollY - 51) + 'px';
+
+ tooltipContainer.style.display = 'block';
+
+ pageBody.appendChild(tooltipContainer);
+ });
+
+ button.addEventListener('mouseleave', function(e) {
+ var button = e.target;
+
+ var tooltipContainer = pageBody.querySelector('#tooltip-' + button.id);
+ if (tooltipContainer){
+ pageBody.removeChild(tooltipContainer);
+ }
+ });
+ }
+});

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 23, 06:29 (18 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1316802
Default Alt Text
D25966.1745389752.diff (7 KB)

Event Timeline